wrangler 0.0.0-e2b7352 → 0.0.0-e2f9bb2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -13
- package/bin/wrangler.js +3 -0
- package/miniflare-dist/index.mjs +4828 -21
- package/package.json +29 -22
- package/pages/functions/buildPlugin.ts +92 -0
- package/pages/functions/buildWorker.ts +80 -4
- package/pages/functions/filepath-routing.test.ts +11 -0
- package/pages/functions/filepath-routing.ts +8 -0
- package/pages/functions/routes.ts +6 -1
- package/pages/functions/template-plugin.ts +146 -0
- package/pages/functions/template-worker.ts +21 -8
- package/src/__tests__/config-cache.test.ts +36 -0
- package/src/__tests__/configuration.test.ts +386 -81
- package/src/__tests__/dev.test.tsx +242 -21
- package/src/__tests__/guess-worker-format.test.ts +18 -1
- package/src/__tests__/helpers/mock-cfetch.ts +5 -1
- package/src/__tests__/helpers/mock-console.ts +20 -3
- package/src/__tests__/helpers/mock-dialogs.ts +24 -0
- package/src/__tests__/helpers/mock-http-server.ts +46 -0
- package/src/__tests__/helpers/mock-istty.ts +27 -0
- package/src/__tests__/helpers/mock-oauth-flow.ts +255 -0
- package/src/__tests__/helpers/run-in-tmp.ts +7 -0
- package/src/__tests__/helpers/write-worker-source.ts +31 -0
- package/src/__tests__/https-options.test.ts +5 -2
- package/src/__tests__/index.test.ts +25 -759
- package/src/__tests__/init.test.ts +1042 -0
- package/src/__tests__/jest.setup.ts +4 -4
- package/src/__tests__/kv.test.ts +130 -56
- package/src/__tests__/logger.test.ts +115 -0
- package/src/__tests__/pages.test.ts +290 -43
- package/src/__tests__/publish.test.ts +1699 -333
- package/src/__tests__/r2.test.ts +24 -8
- package/src/__tests__/route.test.ts +4 -4
- package/src/__tests__/secret.test.ts +55 -34
- package/src/__tests__/tail.test.ts +97 -45
- package/src/__tests__/user.test.ts +131 -0
- package/src/__tests__/whoami.test.tsx +14 -9
- package/src/bundle.ts +15 -1
- package/src/cfetch/internal.ts +0 -2
- package/src/cli.ts +5 -11
- package/src/config/README.md +1 -1
- package/src/config/config.ts +20 -4
- package/src/config/environment.ts +26 -3
- package/src/config/index.ts +2 -1
- package/src/config/validation-helpers.ts +26 -5
- package/src/config/validation.ts +233 -41
- package/src/config-cache.ts +45 -0
- package/src/create-worker-preview.ts +22 -13
- package/src/create-worker-upload-form.ts +32 -9
- package/src/dev/dev-vars.ts +36 -0
- package/src/dev/dev.tsx +60 -34
- package/src/dev/local.tsx +101 -21
- package/src/dev/remote.tsx +23 -13
- package/src/dev/use-esbuild.ts +19 -5
- package/src/dialogs.tsx +16 -6
- package/src/entry.ts +38 -11
- package/src/environment-variables.ts +3 -1
- package/src/errors.ts +11 -0
- package/src/https-options.ts +3 -2
- package/src/index.tsx +529 -303
- package/src/inspect.ts +17 -11
- package/src/logger.ts +66 -0
- package/src/miniflare-cli/index.ts +4 -0
- package/src/miniflare-cli/request-context.ts +40 -0
- package/src/module-collection.ts +7 -7
- package/src/open-in-browser.ts +5 -4
- package/src/package-manager.ts +9 -8
- package/src/pages.tsx +860 -55
- package/src/parse.ts +1 -1
- package/src/proxy.ts +25 -11
- package/src/publish.ts +260 -141
- package/src/sites.tsx +27 -14
- package/src/tail/index.ts +1 -1
- package/src/tail/printing.ts +13 -8
- package/src/update-check.ts +19 -0
- package/src/user.tsx +104 -38
- package/src/whoami.tsx +2 -1
- package/src/worker.ts +15 -6
- package/templates/gitignore +171 -0
- package/templates/static-asset-facade.js +1 -1
- package/wrangler-dist/cli.js +20948 -50169
- package/miniflare-dist/index.mjs.map +0 -7
- package/src/__tests__/logout.test.ts +0 -52
- package/src/__tests__/sentry.test.ts +0 -146
- package/src/reporting.ts +0 -131
- package/wrangler-dist/cli.js.map +0 -7
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
|
-
import { readFileSync } from "node:fs";
|
|
3
2
|
import patchConsole from "patch-console";
|
|
3
|
+
import dedent from "ts-dedent";
|
|
4
4
|
import Dev from "../dev/dev";
|
|
5
5
|
import { mockAccountId, mockApiToken } from "./helpers/mock-account-id";
|
|
6
6
|
import { setMockResponse, unsetAllMocks } from "./helpers/mock-cfetch";
|
|
@@ -20,6 +20,56 @@ describe("wrangler dev", () => {
|
|
|
20
20
|
unsetAllMocks();
|
|
21
21
|
});
|
|
22
22
|
|
|
23
|
+
describe("compatibility-date", () => {
|
|
24
|
+
it("should not warn if there is no wrangler.toml and no compatibility-date specified", async () => {
|
|
25
|
+
fs.writeFileSync("index.js", `export default {};`);
|
|
26
|
+
await runWrangler("dev index.js");
|
|
27
|
+
expect(std.out).toMatchInlineSnapshot(`""`);
|
|
28
|
+
expect(std.warn).toMatchInlineSnapshot(`""`);
|
|
29
|
+
expect(std.err).toMatchInlineSnapshot(`""`);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("should warn if there is a wrangler.toml but no compatibility-date", async () => {
|
|
33
|
+
writeWranglerToml({
|
|
34
|
+
main: "index.js",
|
|
35
|
+
compatibility_date: undefined,
|
|
36
|
+
});
|
|
37
|
+
fs.writeFileSync("index.js", `export default {};`);
|
|
38
|
+
await runWrangler("dev");
|
|
39
|
+
const currentDate = new Date().toISOString().substring(0, 10);
|
|
40
|
+
expect(std.out).toMatchInlineSnapshot(`""`);
|
|
41
|
+
expect(std.warn.replaceAll(currentDate, "<current-date>"))
|
|
42
|
+
.toMatchInlineSnapshot(`
|
|
43
|
+
"[33m▲ [43;33m[[43;30mWARNING[43;33m][0m [1mNo compatibility_date was specified. Using today's date: <current-date>.[0m
|
|
44
|
+
|
|
45
|
+
Add one to your wrangler.toml file:
|
|
46
|
+
\`\`\`
|
|
47
|
+
compatibility_date = \\"<current-date>\\"
|
|
48
|
+
\`\`\`
|
|
49
|
+
or pass it in your terminal:
|
|
50
|
+
\`\`\`
|
|
51
|
+
--compatibility-date=<current-date>
|
|
52
|
+
\`\`\`
|
|
53
|
+
See [4mhttps://developers.cloudflare.com/workers/platform/compatibility-dates[0m for more information.
|
|
54
|
+
|
|
55
|
+
"
|
|
56
|
+
`);
|
|
57
|
+
expect(std.err).toMatchInlineSnapshot(`""`);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("should not warn if there is a wrangler.toml but compatibility-date is specified at the command line", async () => {
|
|
61
|
+
writeWranglerToml({
|
|
62
|
+
main: "index.js",
|
|
63
|
+
compatibility_date: undefined,
|
|
64
|
+
});
|
|
65
|
+
fs.writeFileSync("index.js", `export default {};`);
|
|
66
|
+
await runWrangler("dev --compatibility-date=2020-01-01");
|
|
67
|
+
expect(std.out).toMatchInlineSnapshot(`""`);
|
|
68
|
+
expect(std.warn).toMatchInlineSnapshot(`""`);
|
|
69
|
+
expect(std.err).toMatchInlineSnapshot(`""`);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
23
73
|
describe("entry-points", () => {
|
|
24
74
|
it("should error if there is no entry-point specified", async () => {
|
|
25
75
|
writeWranglerToml();
|
|
@@ -30,11 +80,14 @@ describe("wrangler dev", () => {
|
|
|
30
80
|
`"Missing entry-point: The entry-point should be specified via the command line (e.g. \`wrangler dev path/to/script\`) or the \`main\` config field."`
|
|
31
81
|
);
|
|
32
82
|
|
|
33
|
-
expect(std.out).toMatchInlineSnapshot(`
|
|
83
|
+
expect(std.out).toMatchInlineSnapshot(`
|
|
84
|
+
"
|
|
85
|
+
[32mIf you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new.[0m"
|
|
86
|
+
`);
|
|
34
87
|
expect(std.err).toMatchInlineSnapshot(`
|
|
35
|
-
"
|
|
88
|
+
"[31mX [41;31m[[41;97mERROR[41;31m][0m [1mMissing entry-point: The entry-point should be specified via the command line (e.g. \`wrangler dev path/to/script\`) or the \`main\` config field.[0m
|
|
36
89
|
|
|
37
|
-
|
|
90
|
+
"
|
|
38
91
|
`);
|
|
39
92
|
});
|
|
40
93
|
|
|
@@ -171,6 +224,38 @@ describe("wrangler dev", () => {
|
|
|
171
224
|
);
|
|
172
225
|
});
|
|
173
226
|
|
|
227
|
+
it("should, when provided, use a configured zone_id", async () => {
|
|
228
|
+
writeWranglerToml({
|
|
229
|
+
main: "index.js",
|
|
230
|
+
routes: [
|
|
231
|
+
{ pattern: "https://some-domain.com/*", zone_id: "some-zone-id" },
|
|
232
|
+
],
|
|
233
|
+
});
|
|
234
|
+
fs.writeFileSync("index.js", `export default {};`);
|
|
235
|
+
await runWrangler("dev");
|
|
236
|
+
expect((Dev as jest.Mock).mock.calls[0][0].zone).toEqual({
|
|
237
|
+
host: "some-domain.com",
|
|
238
|
+
id: "some-zone-id",
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it("should, when provided, use a zone_name to get a zone_id", async () => {
|
|
243
|
+
writeWranglerToml({
|
|
244
|
+
main: "index.js",
|
|
245
|
+
routes: [
|
|
246
|
+
{ pattern: "https://some-domain.com/*", zone_name: "some-zone.com" },
|
|
247
|
+
],
|
|
248
|
+
});
|
|
249
|
+
fs.writeFileSync("index.js", `export default {};`);
|
|
250
|
+
mockGetZones("some-zone.com", [{ id: "a-zone-id" }]);
|
|
251
|
+
await runWrangler("dev");
|
|
252
|
+
expect((Dev as jest.Mock).mock.calls[0][0].zone).toEqual({
|
|
253
|
+
// note that it uses the provided zone_name as a host too
|
|
254
|
+
host: "some-zone.com",
|
|
255
|
+
id: "a-zone-id",
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
|
|
174
259
|
it("given a long host, it should use the longest subdomain that resolves to a zone", async () => {
|
|
175
260
|
writeWranglerToml({
|
|
176
261
|
main: "index.js",
|
|
@@ -298,7 +383,7 @@ describe("wrangler dev", () => {
|
|
|
298
383
|
|
|
299
384
|
await runWrangler("dev index.js");
|
|
300
385
|
|
|
301
|
-
expect(readFileSync("index.js", "utf-8")).toMatchInlineSnapshot(
|
|
386
|
+
expect(fs.readFileSync("index.js", "utf-8")).toMatchInlineSnapshot(
|
|
302
387
|
`"export default { fetch(){ return new Response(123) } }"`
|
|
303
388
|
);
|
|
304
389
|
|
|
@@ -310,7 +395,7 @@ describe("wrangler dev", () => {
|
|
|
310
395
|
watch_dir: "src",
|
|
311
396
|
});
|
|
312
397
|
expect(std.out).toMatchInlineSnapshot(
|
|
313
|
-
`"
|
|
398
|
+
`"Running custom build: node -e \\"console.log('custom build'); require('fs').writeFileSync('index.js', 'export default { fetch(){ return new Response(123) } }')\\""`
|
|
314
399
|
);
|
|
315
400
|
expect(std.err).toMatchInlineSnapshot(`""`);
|
|
316
401
|
expect(std.warn).toMatchInlineSnapshot(`""`);
|
|
@@ -326,13 +411,13 @@ describe("wrangler dev", () => {
|
|
|
326
411
|
|
|
327
412
|
await runWrangler("dev index.js");
|
|
328
413
|
|
|
329
|
-
expect(readFileSync("index.js", "utf-8")).toMatchInlineSnapshot(`
|
|
414
|
+
expect(fs.readFileSync("index.js", "utf-8")).toMatchInlineSnapshot(`
|
|
330
415
|
"export default { fetch(){ return new Response(123) } }
|
|
331
416
|
"
|
|
332
417
|
`);
|
|
333
418
|
|
|
334
419
|
expect(std.out).toMatchInlineSnapshot(
|
|
335
|
-
`"
|
|
420
|
+
`"Running custom build: echo \\"custom build\\" && echo \\"export default { fetch(){ return new Response(123) } }\\" > index.js"`
|
|
336
421
|
);
|
|
337
422
|
expect(std.err).toMatchInlineSnapshot(`""`);
|
|
338
423
|
expect(std.warn).toMatchInlineSnapshot(`""`);
|
|
@@ -352,13 +437,15 @@ describe("wrangler dev", () => {
|
|
|
352
437
|
).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
353
438
|
`"Could not resolve \\"index.js\\" after running custom build: node -e \\"console.log('custom build');\\""`
|
|
354
439
|
);
|
|
355
|
-
expect(std.out).toMatchInlineSnapshot(
|
|
356
|
-
|
|
357
|
-
|
|
440
|
+
expect(std.out).toMatchInlineSnapshot(`
|
|
441
|
+
"Running custom build: node -e \\"console.log('custom build');\\"
|
|
442
|
+
|
|
443
|
+
[32mIf you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new.[0m"
|
|
444
|
+
`);
|
|
358
445
|
expect(std.err).toMatchInlineSnapshot(`
|
|
359
|
-
"
|
|
446
|
+
"[31mX [41;31m[[41;97mERROR[41;31m][0m [1mCould not resolve \\"index.js\\" after running custom build: node -e \\"console.log('custom build');\\"[0m
|
|
360
447
|
|
|
361
|
-
|
|
448
|
+
"
|
|
362
449
|
`);
|
|
363
450
|
expect(std.warn).toMatchInlineSnapshot(`""`);
|
|
364
451
|
});
|
|
@@ -390,9 +477,12 @@ describe("wrangler dev", () => {
|
|
|
390
477
|
);
|
|
391
478
|
expect(std.out).toMatchInlineSnapshot(`""`);
|
|
392
479
|
expect(std.warn).toMatchInlineSnapshot(`
|
|
393
|
-
"
|
|
394
|
-
|
|
395
|
-
|
|
480
|
+
"[33m▲ [43;33m[[43;30mWARNING[43;33m][0m [1mSetting upstream-protocol to http is not currently implemented.[0m
|
|
481
|
+
|
|
482
|
+
If this is required in your project, please add your use case to the following issue:
|
|
483
|
+
[4mhttps://github.com/cloudflare/wrangler2/issues/583[0m.
|
|
484
|
+
|
|
485
|
+
"
|
|
396
486
|
`);
|
|
397
487
|
expect(std.err).toMatchInlineSnapshot(`""`);
|
|
398
488
|
});
|
|
@@ -516,15 +606,146 @@ describe("wrangler dev", () => {
|
|
|
516
606
|
expect((Dev as jest.Mock).mock.calls[0][0].ip).toEqual("localhost");
|
|
517
607
|
expect(std.out).toMatchInlineSnapshot(`""`);
|
|
518
608
|
expect(std.warn).toMatchInlineSnapshot(`
|
|
519
|
-
"
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
609
|
+
"[33m▲ [43;33m[[43;30mWARNING[43;33m][0m [1mWARNING: You have Durable Object bindings that are not defined locally in the worker being developed.[0m
|
|
610
|
+
|
|
611
|
+
Be aware that changes to the data stored in these Durable Objects will be permanent and affect the
|
|
612
|
+
live instances.
|
|
613
|
+
Remote Durable Objects that are affected:
|
|
614
|
+
- {\\"name\\":\\"NAME_2\\",\\"class_name\\":\\"CLASS_2\\",\\"script_name\\":\\"SCRIPT_A\\"}
|
|
615
|
+
- {\\"name\\":\\"NAME_4\\",\\"class_name\\":\\"CLASS_4\\",\\"script_name\\":\\"SCRIPT_B\\"}
|
|
616
|
+
|
|
617
|
+
"
|
|
524
618
|
`);
|
|
525
619
|
expect(std.err).toMatchInlineSnapshot(`""`);
|
|
526
620
|
});
|
|
527
621
|
});
|
|
622
|
+
|
|
623
|
+
describe(".dev.vars", () => {
|
|
624
|
+
it("should override `vars` bindings from `wrangler.toml` with values in `.dev.vars`", async () => {
|
|
625
|
+
fs.writeFileSync("index.js", `export default {};`);
|
|
626
|
+
|
|
627
|
+
const localVarsEnvContent = dedent`
|
|
628
|
+
# Preceding comment
|
|
629
|
+
VAR_1="var #1 value" # End of line comment
|
|
630
|
+
VAR_3="var #3 value"
|
|
631
|
+
VAR_MULTI_LINE_1="A: line 1
|
|
632
|
+
line 2"
|
|
633
|
+
VAR_MULTI_LINE_2="B: line 1\\nline 2"
|
|
634
|
+
EMPTY=
|
|
635
|
+
UNQUOTED= unquoted value
|
|
636
|
+
`;
|
|
637
|
+
fs.writeFileSync(".dev.vars", localVarsEnvContent, "utf8");
|
|
638
|
+
|
|
639
|
+
writeWranglerToml({
|
|
640
|
+
main: "index.js",
|
|
641
|
+
vars: {
|
|
642
|
+
VAR_1: "original value 1",
|
|
643
|
+
VAR_2: "original value 2", // should not get overridden
|
|
644
|
+
VAR_3: "original value 3",
|
|
645
|
+
VAR_MULTI_LINE_1: "original multi-line 1",
|
|
646
|
+
VAR_MULTI_LINE_2: "original multi-line 2",
|
|
647
|
+
EMPTY: "original empty",
|
|
648
|
+
UNQUOTED: "original unquoted",
|
|
649
|
+
},
|
|
650
|
+
});
|
|
651
|
+
await runWrangler("dev");
|
|
652
|
+
const varBindings: Record<string, unknown> = (Dev as jest.Mock).mock
|
|
653
|
+
.calls[0][0].bindings.vars;
|
|
654
|
+
|
|
655
|
+
expect(varBindings).toEqual({
|
|
656
|
+
VAR_1: "var #1 value",
|
|
657
|
+
VAR_2: "original value 2",
|
|
658
|
+
VAR_3: "var #3 value",
|
|
659
|
+
VAR_MULTI_LINE_1: "A: line 1\nline 2",
|
|
660
|
+
VAR_MULTI_LINE_2: "B: line 1\nline 2",
|
|
661
|
+
EMPTY: "",
|
|
662
|
+
UNQUOTED: "unquoted value", // Note that whitespace is trimmed
|
|
663
|
+
});
|
|
664
|
+
expect(std.out).toMatchInlineSnapshot(
|
|
665
|
+
`"Using vars defined in .dev.vars"`
|
|
666
|
+
);
|
|
667
|
+
expect(std.warn).toMatchInlineSnapshot(`""`);
|
|
668
|
+
expect(std.err).toMatchInlineSnapshot(`""`);
|
|
669
|
+
});
|
|
670
|
+
});
|
|
671
|
+
|
|
672
|
+
describe("site", () => {
|
|
673
|
+
it("should error if --site is used with no value", async () => {
|
|
674
|
+
await expect(
|
|
675
|
+
runWrangler("dev --site")
|
|
676
|
+
).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
677
|
+
`"Not enough arguments following: site"`
|
|
678
|
+
);
|
|
679
|
+
|
|
680
|
+
expect(std).toMatchInlineSnapshot(`
|
|
681
|
+
Object {
|
|
682
|
+
"debug": "",
|
|
683
|
+
"err": "wrangler dev [script]
|
|
684
|
+
|
|
685
|
+
👂 Start a local server for developing your worker
|
|
686
|
+
|
|
687
|
+
Positionals:
|
|
688
|
+
script The path to an entry point for your worker [string]
|
|
689
|
+
|
|
690
|
+
Flags:
|
|
691
|
+
-c, --config Path to .toml configuration file [string]
|
|
692
|
+
-h, --help Show help [boolean]
|
|
693
|
+
-v, --version Show version number [boolean]
|
|
694
|
+
--legacy-env Use legacy environments [boolean]
|
|
695
|
+
|
|
696
|
+
Options:
|
|
697
|
+
--name Name of the worker [string]
|
|
698
|
+
--format Choose an entry type [deprecated] [choices: \\"modules\\", \\"service-worker\\"]
|
|
699
|
+
-e, --env Perform on a specific environment [string]
|
|
700
|
+
--compatibility-date Date to use for compatibility checks [string]
|
|
701
|
+
--compatibility-flags, --compatibility-flag Flags to use for compatibility checks [array]
|
|
702
|
+
--latest Use the latest version of the worker runtime [boolean] [default: true]
|
|
703
|
+
--ip IP address to listen on, defaults to \`localhost\` [string]
|
|
704
|
+
--port Port to listen on [number]
|
|
705
|
+
--inspector-port Port for devtools to connect to [number]
|
|
706
|
+
--routes, --route Routes to upload [array]
|
|
707
|
+
--host Host to forward requests to, defaults to the zone of project [string]
|
|
708
|
+
--local-protocol Protocol to listen to requests on, defaults to http. [choices: \\"http\\", \\"https\\"]
|
|
709
|
+
--experimental-public Static assets to be served [string]
|
|
710
|
+
--site Root folder of static assets for Workers Sites [string]
|
|
711
|
+
--site-include Array of .gitignore-style patterns that match file or directory names from the sites directory. Only matched items will be uploaded. [array]
|
|
712
|
+
--site-exclude Array of .gitignore-style patterns that match file or directory names from the sites directory. Matched items will not be uploaded. [array]
|
|
713
|
+
--upstream-protocol Protocol to forward requests to host on, defaults to https. [choices: \\"http\\", \\"https\\"]
|
|
714
|
+
--jsx-factory The function that is called for each JSX element [string]
|
|
715
|
+
--jsx-fragment The function that is called for each JSX fragment [string]
|
|
716
|
+
--tsconfig Path to a custom tsconfig.json file [string]
|
|
717
|
+
-l, --local Run on my machine [boolean] [default: false]
|
|
718
|
+
--minify Minify the script [boolean]
|
|
719
|
+
--node-compat Enable node.js compatibility [boolean]
|
|
720
|
+
--experimental-enable-local-persistence Enable persistence for this session (only for local mode) [boolean]
|
|
721
|
+
--inspect Enable dev tools [deprecated] [boolean]
|
|
722
|
+
[31mX [41;31m[[41;97mERROR[41;31m][0m [1mNot enough arguments following: site[0m
|
|
723
|
+
|
|
724
|
+
",
|
|
725
|
+
"out": "
|
|
726
|
+
",
|
|
727
|
+
"warn": "",
|
|
728
|
+
}
|
|
729
|
+
`);
|
|
730
|
+
});
|
|
731
|
+
});
|
|
732
|
+
|
|
733
|
+
describe("--inspect", () => {
|
|
734
|
+
it("should warn if --inspect is used", async () => {
|
|
735
|
+
fs.writeFileSync("index.js", `export default {};`);
|
|
736
|
+
await runWrangler("dev index.js --inspect");
|
|
737
|
+
expect(std).toMatchInlineSnapshot(`
|
|
738
|
+
Object {
|
|
739
|
+
"debug": "",
|
|
740
|
+
"err": "",
|
|
741
|
+
"out": "",
|
|
742
|
+
"warn": "[33m▲ [43;33m[[43;30mWARNING[43;33m][0m [1mPassing --inspect is unnecessary, now you can always connect to devtools.[0m
|
|
743
|
+
|
|
744
|
+
",
|
|
745
|
+
}
|
|
746
|
+
`);
|
|
747
|
+
});
|
|
748
|
+
});
|
|
528
749
|
});
|
|
529
750
|
|
|
530
751
|
function mockGetZones(domain: string, zones: { id: string }[] = []) {
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { writeFile } from "fs/promises";
|
|
2
2
|
import path from "path";
|
|
3
3
|
import guessWorkerFormat from "../entry";
|
|
4
|
+
import { mockConsoleMethods } from "./helpers/mock-console";
|
|
4
5
|
import { runInTempDir } from "./helpers/run-in-tmp";
|
|
5
6
|
|
|
6
7
|
describe("guess worker format", () => {
|
|
7
8
|
runInTempDir();
|
|
9
|
+
const std = mockConsoleMethods();
|
|
8
10
|
it('should detect a "modules" worker', async () => {
|
|
9
11
|
await writeFile("./index.ts", "export default {};");
|
|
10
12
|
// Note that this isn't actually a valid worker, because it's missing
|
|
@@ -39,7 +41,7 @@ describe("guess worker format", () => {
|
|
|
39
41
|
"service-worker"
|
|
40
42
|
)
|
|
41
43
|
).rejects.toThrow(
|
|
42
|
-
"You configured this worker to be a 'service-worker', but the file you are trying to build appears to have
|
|
44
|
+
"You configured this worker to be a 'service-worker', but the file you are trying to build appears to have a `default` export like a module worker. Please pass `--format modules`, or simply remove the configuration."
|
|
43
45
|
);
|
|
44
46
|
});
|
|
45
47
|
|
|
@@ -65,4 +67,19 @@ describe("guess worker format", () => {
|
|
|
65
67
|
);
|
|
66
68
|
expect(guess).toBe("service-worker");
|
|
67
69
|
});
|
|
70
|
+
|
|
71
|
+
it("logs a warning when a worker has exports, but not a default one", async () => {
|
|
72
|
+
await writeFile("./index.ts", "export const foo = 1;");
|
|
73
|
+
const guess = await guessWorkerFormat(
|
|
74
|
+
path.join(process.cwd(), "./index.ts"),
|
|
75
|
+
process.cwd(),
|
|
76
|
+
undefined
|
|
77
|
+
);
|
|
78
|
+
expect(guess).toBe("service-worker");
|
|
79
|
+
expect(std.warn).toMatchInlineSnapshot(`
|
|
80
|
+
"[33m▲ [43;33m[[43;30mWARNING[43;33m][0m [1mThe entrypoint index.ts has exports like an ES Module, but hasn't defined a default export like a module worker normally would. Building the worker using \\"service-worker\\" format...[0m
|
|
81
|
+
|
|
82
|
+
"
|
|
83
|
+
`);
|
|
84
|
+
});
|
|
68
85
|
});
|
|
@@ -181,6 +181,9 @@ export function unsetAllMocks() {
|
|
|
181
181
|
|
|
182
182
|
const kvGetMocks = new Map<string, string>();
|
|
183
183
|
|
|
184
|
+
/**
|
|
185
|
+
* @mocked typeof fetchKVGetValue
|
|
186
|
+
*/
|
|
184
187
|
export function mockFetchKVGetValue(
|
|
185
188
|
accountId: string,
|
|
186
189
|
namespaceId: string,
|
|
@@ -188,7 +191,8 @@ export function mockFetchKVGetValue(
|
|
|
188
191
|
) {
|
|
189
192
|
const mapKey = `${accountId}/${namespaceId}/${key}`;
|
|
190
193
|
if (kvGetMocks.has(mapKey)) {
|
|
191
|
-
|
|
194
|
+
const value = kvGetMocks.get(mapKey);
|
|
195
|
+
if (value !== undefined) return Promise.resolve(value);
|
|
192
196
|
}
|
|
193
197
|
throw new Error(`no mock value found for \`kv:key get\` - ${mapKey}`);
|
|
194
198
|
}
|
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
import * as util from "node:util";
|
|
2
|
+
import { logger } from "../../logger";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* We use this module to mock console methods, and optionally
|
|
5
6
|
* assert on the values they're called with in our tests.
|
|
6
7
|
*/
|
|
7
8
|
|
|
8
|
-
let
|
|
9
|
+
let debugSpy: jest.SpyInstance,
|
|
10
|
+
logSpy: jest.SpyInstance,
|
|
9
11
|
errorSpy: jest.SpyInstance,
|
|
10
12
|
warnSpy: jest.SpyInstance;
|
|
11
13
|
|
|
12
14
|
const std = {
|
|
15
|
+
get debug() {
|
|
16
|
+
return normalizeOutput(debugSpy);
|
|
17
|
+
},
|
|
13
18
|
get out() {
|
|
14
19
|
return normalizeOutput(logSpy);
|
|
15
20
|
},
|
|
@@ -22,8 +27,8 @@ const std = {
|
|
|
22
27
|
};
|
|
23
28
|
|
|
24
29
|
function normalizeOutput(spy: jest.SpyInstance): string {
|
|
25
|
-
return
|
|
26
|
-
normalizeSlashes(stripTimings(captureCalls(spy)))
|
|
30
|
+
return normalizeErrorMarkers(
|
|
31
|
+
stripTrailingWhitespace(normalizeSlashes(stripTimings(captureCalls(spy))))
|
|
27
32
|
);
|
|
28
33
|
}
|
|
29
34
|
|
|
@@ -35,11 +40,14 @@ function captureCalls(spy: jest.SpyInstance): string {
|
|
|
35
40
|
|
|
36
41
|
export function mockConsoleMethods() {
|
|
37
42
|
beforeEach(() => {
|
|
43
|
+
logger.columns = 100;
|
|
44
|
+
debugSpy = jest.spyOn(console, "debug").mockImplementation();
|
|
38
45
|
logSpy = jest.spyOn(console, "log").mockImplementation();
|
|
39
46
|
errorSpy = jest.spyOn(console, "error").mockImplementation();
|
|
40
47
|
warnSpy = jest.spyOn(console, "warn").mockImplementation();
|
|
41
48
|
});
|
|
42
49
|
afterEach(() => {
|
|
50
|
+
debugSpy.mockRestore();
|
|
43
51
|
logSpy.mockRestore();
|
|
44
52
|
errorSpy.mockRestore();
|
|
45
53
|
warnSpy.mockRestore();
|
|
@@ -47,6 +55,15 @@ export function mockConsoleMethods() {
|
|
|
47
55
|
return std;
|
|
48
56
|
}
|
|
49
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Normalize error `X` markers.
|
|
60
|
+
*
|
|
61
|
+
* Windows gets a different character.
|
|
62
|
+
*/
|
|
63
|
+
function normalizeErrorMarkers(str: string): string {
|
|
64
|
+
return str.replaceAll("✘", "X");
|
|
65
|
+
}
|
|
66
|
+
|
|
50
67
|
/**
|
|
51
68
|
* Ensure slashes in the `str` are OS file-system agnostic.
|
|
52
69
|
*
|
|
@@ -28,6 +28,18 @@ export function mockConfirm(...expectations: ConfirmExpectation[]) {
|
|
|
28
28
|
});
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
export function clearConfirmMocks() {
|
|
32
|
+
(confirm as jest.Mock).mockReset();
|
|
33
|
+
// Because confirm was originally a spy, calling mockReset will simply reset
|
|
34
|
+
// it as a function with no return value (!), so we need to accitionally reset
|
|
35
|
+
// the mock implementation to the one that throws (from jest.setup.js).
|
|
36
|
+
(confirm as jest.Mock).mockImplementation((text: string) => {
|
|
37
|
+
throw new Error(
|
|
38
|
+
`Unexpected call to \`confirm("${text}")\`.\nYou should use \`mockConfirm()\` to mock calls to \`confirm()\` with expectations. Search the codebase for \`mockConfirm\` to learn more.`
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
31
43
|
/**
|
|
32
44
|
* The expected values for a prompt request.
|
|
33
45
|
*/
|
|
@@ -63,3 +75,15 @@ export function mockPrompt(...expectations: PromptExpectation[]) {
|
|
|
63
75
|
}
|
|
64
76
|
);
|
|
65
77
|
}
|
|
78
|
+
|
|
79
|
+
export function clearPromptMocks() {
|
|
80
|
+
(prompt as jest.Mock).mockReset();
|
|
81
|
+
// Because prompt was originally a spy, calling mockReset will simply reset
|
|
82
|
+
// it as a function with no return value (!), so we need to accitionally reset
|
|
83
|
+
// the mock implementation to the one that throws (from jest.setup.js).
|
|
84
|
+
(prompt as jest.Mock).mockImplementation((text: string) => {
|
|
85
|
+
throw new Error(
|
|
86
|
+
`Unexpected call to \`prompt(${text}, ...)\`.\nYou should use \`mockPrompt()\` to mock calls to \`prompt()\` with expectations. Search the codebase for \`mockPrompt\` to learn more.`
|
|
87
|
+
);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import http from "node:http";
|
|
2
|
+
import type { Request } from "undici";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Setup a mock HTTP server that can be triggered directly without interacting with any network.
|
|
6
|
+
*
|
|
7
|
+
* @returns a `fetch`-like function that will trigger the mock server to handle the request.
|
|
8
|
+
*/
|
|
9
|
+
export function mockHttpServer() {
|
|
10
|
+
let listener: http.RequestListener;
|
|
11
|
+
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
jest
|
|
14
|
+
.spyOn(http, "createServer")
|
|
15
|
+
.mockImplementation((...args: unknown[]) => {
|
|
16
|
+
listener = args.pop() as http.RequestListener;
|
|
17
|
+
return {
|
|
18
|
+
listen: jest.fn(),
|
|
19
|
+
close(callback?: (err?: Error) => void) {
|
|
20
|
+
callback?.();
|
|
21
|
+
return this;
|
|
22
|
+
},
|
|
23
|
+
} as unknown as http.Server;
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
return async (req: Request) => {
|
|
28
|
+
const resp = new http.ServerResponse(
|
|
29
|
+
// If you squint you can just about see that an `IncomingMessages` is like a `Request`!
|
|
30
|
+
req as unknown as http.IncomingMessage
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
// The listener will attache a callback to the response by calling `resp.end(callback)`.
|
|
34
|
+
// We want to capture that so that we can trigger it after the listener has completed its work.
|
|
35
|
+
const endSpy = jest.spyOn(resp, "end");
|
|
36
|
+
|
|
37
|
+
// The `await` here is important to allow the listener to complete its async work before we end the response.
|
|
38
|
+
await listener(req as unknown as http.IncomingMessage, resp);
|
|
39
|
+
|
|
40
|
+
// Now trigger the end callback.
|
|
41
|
+
const endCallback = endSpy.mock.calls[0].pop();
|
|
42
|
+
endCallback?.();
|
|
43
|
+
|
|
44
|
+
return resp;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const ORIGINAL_STDOUT_ISTTY = process.stdout.isTTY;
|
|
2
|
+
const ORIGINAL_STDIN_ISTTY = process.stdin.isTTY;
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Mock `process.stdout.isTTY`
|
|
6
|
+
*/
|
|
7
|
+
export function useMockIsTTY() {
|
|
8
|
+
/**
|
|
9
|
+
* Explicitly set `process.stdout.isTTY` to a given value
|
|
10
|
+
*/
|
|
11
|
+
const setIsTTY = (isTTY: boolean) => {
|
|
12
|
+
process.stdout.isTTY = isTTY;
|
|
13
|
+
process.stdin.isTTY = isTTY;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
process.stdout.isTTY = ORIGINAL_STDOUT_ISTTY;
|
|
18
|
+
process.stdin.isTTY = ORIGINAL_STDIN_ISTTY;
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
afterEach(() => {
|
|
22
|
+
process.stdout.isTTY = ORIGINAL_STDOUT_ISTTY;
|
|
23
|
+
process.stdin.isTTY = ORIGINAL_STDIN_ISTTY;
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
return { setIsTTY };
|
|
27
|
+
}
|