wrangler 0.0.0-e88a54e → 0.0.0-e95e5a0
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 +25 -14
- package/bin/wrangler.js +13 -1
- package/miniflare-dist/index.mjs +4828 -21
- package/package.json +29 -24
- 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 +530 -201
- package/src/__tests__/dev.test.tsx +284 -18
- package/src/__tests__/guess-worker-format.test.ts +28 -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 +26 -1
- 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 +27 -769
- package/src/__tests__/init.test.ts +1516 -0
- package/src/__tests__/jest.setup.ts +4 -4
- package/src/__tests__/kv.test.ts +133 -61
- package/src/__tests__/logger.test.ts +115 -0
- package/src/__tests__/pages.test.ts +311 -26
- package/src/__tests__/publish.test.ts +2789 -618
- package/src/__tests__/r2.test.ts +26 -10
- package/src/__tests__/route.test.ts +4 -4
- package/src/__tests__/secret.test.ts +55 -34
- package/src/__tests__/tail.test.ts +146 -20
- package/src/__tests__/user.test.ts +131 -0
- package/src/__tests__/whoami.test.tsx +14 -9
- package/src/bundle.ts +30 -3
- 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 +32 -4
- package/src/config/index.ts +4 -3
- package/src/config/validation-helpers.ts +96 -7
- package/src/config/validation.ts +388 -54
- 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 +132 -78
- package/src/dev/local.tsx +101 -21
- package/src/dev/remote.tsx +23 -13
- package/src/dev/use-esbuild.ts +23 -5
- package/src/dialogs.tsx +16 -6
- package/src/entry.ts +83 -24
- package/src/environment-variables.ts +3 -1
- package/src/errors.ts +11 -0
- package/src/https-options.ts +3 -2
- package/src/index.tsx +689 -394
- package/src/inspect.ts +17 -11
- package/src/intl-polyfill.d.ts +139 -0
- 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 +875 -56
- package/src/parse.ts +1 -1
- package/src/proxy.ts +28 -19
- package/src/publish.ts +263 -141
- package/src/sites.tsx +27 -14
- package/src/tail/index.ts +2 -2
- package/src/tail/printing.ts +13 -8
- package/src/update-check.ts +19 -0
- package/src/user.tsx +116 -41
- 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 +21162 -50227
- package/miniflare-dist/index.mjs.map +0 -7
- package/src/__tests__/dev2.test.tsx +0 -154
- 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";
|
|
@@ -9,7 +9,7 @@ import { runInTempDir } from "./helpers/run-in-tmp";
|
|
|
9
9
|
import { runWrangler } from "./helpers/run-wrangler";
|
|
10
10
|
import writeWranglerToml from "./helpers/write-wrangler-toml";
|
|
11
11
|
|
|
12
|
-
describe("
|
|
12
|
+
describe("wrangler dev", () => {
|
|
13
13
|
mockAccountId();
|
|
14
14
|
mockApiToken();
|
|
15
15
|
runInTempDir();
|
|
@@ -20,6 +20,56 @@ describe("Dev component", () => {
|
|
|
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("Dev component", () => {
|
|
|
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("Dev component", () => {
|
|
|
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",
|
|
@@ -277,6 +362,15 @@ describe("Dev component", () => {
|
|
|
277
362
|
`"Could not find zone for some-host.com"`
|
|
278
363
|
);
|
|
279
364
|
});
|
|
365
|
+
|
|
366
|
+
it("should not try to resolve a zone when starting in local mode", async () => {
|
|
367
|
+
writeWranglerToml({
|
|
368
|
+
main: "index.js",
|
|
369
|
+
});
|
|
370
|
+
fs.writeFileSync("index.js", `export default {};`);
|
|
371
|
+
await runWrangler("dev --host some-host.com --local");
|
|
372
|
+
expect((Dev as jest.Mock).mock.calls[0][0].zone).toEqual(undefined);
|
|
373
|
+
});
|
|
280
374
|
});
|
|
281
375
|
|
|
282
376
|
describe("custom builds", () => {
|
|
@@ -289,19 +383,19 @@ describe("Dev component", () => {
|
|
|
289
383
|
|
|
290
384
|
await runWrangler("dev index.js");
|
|
291
385
|
|
|
292
|
-
expect(readFileSync("index.js", "utf-8")).toMatchInlineSnapshot(
|
|
386
|
+
expect(fs.readFileSync("index.js", "utf-8")).toMatchInlineSnapshot(
|
|
293
387
|
`"export default { fetch(){ return new Response(123) } }"`
|
|
294
388
|
);
|
|
295
389
|
|
|
296
390
|
// and the command would pass through
|
|
297
|
-
expect((Dev as jest.Mock).mock.calls[0][0].
|
|
391
|
+
expect((Dev as jest.Mock).mock.calls[0][0].build).toEqual({
|
|
298
392
|
command:
|
|
299
393
|
"node -e \"console.log('custom build'); require('fs').writeFileSync('index.js', 'export default { fetch(){ return new Response(123) } }')\"",
|
|
300
394
|
cwd: undefined,
|
|
301
395
|
watch_dir: "src",
|
|
302
396
|
});
|
|
303
397
|
expect(std.out).toMatchInlineSnapshot(
|
|
304
|
-
`"
|
|
398
|
+
`"Running custom build: node -e \\"console.log('custom build'); require('fs').writeFileSync('index.js', 'export default { fetch(){ return new Response(123) } }')\\""`
|
|
305
399
|
);
|
|
306
400
|
expect(std.err).toMatchInlineSnapshot(`""`);
|
|
307
401
|
expect(std.warn).toMatchInlineSnapshot(`""`);
|
|
@@ -317,13 +411,13 @@ describe("Dev component", () => {
|
|
|
317
411
|
|
|
318
412
|
await runWrangler("dev index.js");
|
|
319
413
|
|
|
320
|
-
expect(readFileSync("index.js", "utf-8")).toMatchInlineSnapshot(`
|
|
414
|
+
expect(fs.readFileSync("index.js", "utf-8")).toMatchInlineSnapshot(`
|
|
321
415
|
"export default { fetch(){ return new Response(123) } }
|
|
322
416
|
"
|
|
323
417
|
`);
|
|
324
418
|
|
|
325
419
|
expect(std.out).toMatchInlineSnapshot(
|
|
326
|
-
`"
|
|
420
|
+
`"Running custom build: echo \\"custom build\\" && echo \\"export default { fetch(){ return new Response(123) } }\\" > index.js"`
|
|
327
421
|
);
|
|
328
422
|
expect(std.err).toMatchInlineSnapshot(`""`);
|
|
329
423
|
expect(std.warn).toMatchInlineSnapshot(`""`);
|
|
@@ -343,13 +437,15 @@ describe("Dev component", () => {
|
|
|
343
437
|
).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
344
438
|
`"Could not resolve \\"index.js\\" after running custom build: node -e \\"console.log('custom build');\\""`
|
|
345
439
|
);
|
|
346
|
-
expect(std.out).toMatchInlineSnapshot(
|
|
347
|
-
|
|
348
|
-
|
|
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
|
+
`);
|
|
349
445
|
expect(std.err).toMatchInlineSnapshot(`
|
|
350
|
-
"
|
|
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
|
|
351
447
|
|
|
352
|
-
|
|
448
|
+
"
|
|
353
449
|
`);
|
|
354
450
|
expect(std.warn).toMatchInlineSnapshot(`""`);
|
|
355
451
|
});
|
|
@@ -381,9 +477,12 @@ describe("Dev component", () => {
|
|
|
381
477
|
);
|
|
382
478
|
expect(std.out).toMatchInlineSnapshot(`""`);
|
|
383
479
|
expect(std.warn).toMatchInlineSnapshot(`
|
|
384
|
-
"
|
|
385
|
-
|
|
386
|
-
|
|
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
|
+
"
|
|
387
486
|
`);
|
|
388
487
|
expect(std.err).toMatchInlineSnapshot(`""`);
|
|
389
488
|
});
|
|
@@ -480,6 +579,173 @@ describe("Dev component", () => {
|
|
|
480
579
|
expect(std.err).toMatchInlineSnapshot(`""`);
|
|
481
580
|
});
|
|
482
581
|
});
|
|
582
|
+
|
|
583
|
+
describe("durable_objects", () => {
|
|
584
|
+
it("should warn if there is one or more remote Durable Object", async () => {
|
|
585
|
+
writeWranglerToml({
|
|
586
|
+
main: "index.js",
|
|
587
|
+
durable_objects: {
|
|
588
|
+
bindings: [
|
|
589
|
+
{ name: "NAME_1", class_name: "CLASS_1" },
|
|
590
|
+
{
|
|
591
|
+
name: "NAME_2",
|
|
592
|
+
class_name: "CLASS_2",
|
|
593
|
+
script_name: "SCRIPT_A",
|
|
594
|
+
},
|
|
595
|
+
{ name: "NAME_3", class_name: "CLASS_3" },
|
|
596
|
+
{
|
|
597
|
+
name: "NAME_4",
|
|
598
|
+
class_name: "CLASS_4",
|
|
599
|
+
script_name: "SCRIPT_B",
|
|
600
|
+
},
|
|
601
|
+
],
|
|
602
|
+
},
|
|
603
|
+
});
|
|
604
|
+
fs.writeFileSync("index.js", `export default {};`);
|
|
605
|
+
await runWrangler("dev");
|
|
606
|
+
expect((Dev as jest.Mock).mock.calls[0][0].ip).toEqual("localhost");
|
|
607
|
+
expect(std.out).toMatchInlineSnapshot(`""`);
|
|
608
|
+
expect(std.warn).toMatchInlineSnapshot(`
|
|
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
|
+
"
|
|
618
|
+
`);
|
|
619
|
+
expect(std.err).toMatchInlineSnapshot(`""`);
|
|
620
|
+
});
|
|
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
|
+
});
|
|
483
749
|
});
|
|
484
750
|
|
|
485
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
|
|
|
@@ -55,4 +57,29 @@ describe("guess worker format", () => {
|
|
|
55
57
|
"You configured this worker to be 'modules', but the file you are trying to build doesn't export a handler. Please pass `--format service-worker`, or simply remove the configuration."
|
|
56
58
|
);
|
|
57
59
|
});
|
|
60
|
+
|
|
61
|
+
it("should not error if a .js entry point has jsx", async () => {
|
|
62
|
+
await writeFile("./index.js", "console.log(<div/>)");
|
|
63
|
+
const guess = await guessWorkerFormat(
|
|
64
|
+
path.join(process.cwd(), "./index.js"),
|
|
65
|
+
process.cwd(),
|
|
66
|
+
undefined
|
|
67
|
+
);
|
|
68
|
+
expect(guess).toBe("service-worker");
|
|
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
|
+
});
|
|
58
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
|
*
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { confirm, prompt } from "../../dialogs";
|
|
2
|
+
import { normalizeSlashes } from "./mock-console";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* The expected values for a confirmation request.
|
|
@@ -20,7 +21,7 @@ export interface ConfirmExpectation {
|
|
|
20
21
|
export function mockConfirm(...expectations: ConfirmExpectation[]) {
|
|
21
22
|
(confirm as jest.Mock).mockImplementation((text: string) => {
|
|
22
23
|
for (const { text: expectedText, result } of expectations) {
|
|
23
|
-
if (text === expectedText) {
|
|
24
|
+
if (normalizeSlashes(text) === normalizeSlashes(expectedText)) {
|
|
24
25
|
return Promise.resolve(result);
|
|
25
26
|
}
|
|
26
27
|
}
|
|
@@ -28,6 +29,18 @@ export function mockConfirm(...expectations: ConfirmExpectation[]) {
|
|
|
28
29
|
});
|
|
29
30
|
}
|
|
30
31
|
|
|
32
|
+
export function clearConfirmMocks() {
|
|
33
|
+
(confirm as jest.Mock).mockReset();
|
|
34
|
+
// Because confirm was originally a spy, calling mockReset will simply reset
|
|
35
|
+
// it as a function with no return value (!), so we need to accitionally reset
|
|
36
|
+
// the mock implementation to the one that throws (from jest.setup.js).
|
|
37
|
+
(confirm as jest.Mock).mockImplementation((text: string) => {
|
|
38
|
+
throw new Error(
|
|
39
|
+
`Unexpected call to \`confirm("${text}")\`.\nYou should use \`mockConfirm()\` to mock calls to \`confirm()\` with expectations. Search the codebase for \`mockConfirm\` to learn more.`
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
31
44
|
/**
|
|
32
45
|
* The expected values for a prompt request.
|
|
33
46
|
*/
|
|
@@ -63,3 +76,15 @@ export function mockPrompt(...expectations: PromptExpectation[]) {
|
|
|
63
76
|
}
|
|
64
77
|
);
|
|
65
78
|
}
|
|
79
|
+
|
|
80
|
+
export function clearPromptMocks() {
|
|
81
|
+
(prompt as jest.Mock).mockReset();
|
|
82
|
+
// Because prompt was originally a spy, calling mockReset will simply reset
|
|
83
|
+
// it as a function with no return value (!), so we need to accitionally reset
|
|
84
|
+
// the mock implementation to the one that throws (from jest.setup.js).
|
|
85
|
+
(prompt as jest.Mock).mockImplementation((text: string) => {
|
|
86
|
+
throw new Error(
|
|
87
|
+
`Unexpected call to \`prompt(${text}, ...)\`.\nYou should use \`mockPrompt()\` to mock calls to \`prompt()\` with expectations. Search the codebase for \`mockPrompt\` to learn more.`
|
|
88
|
+
);
|
|
89
|
+
});
|
|
90
|
+
}
|
|
@@ -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
|
+
}
|