wrangler 0.0.0-e2a26a0 → 0.0.0-e2b7352

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.
Files changed (91) hide show
  1. package/README.md +3 -3
  2. package/bin/wrangler.js +10 -1
  3. package/miniflare-dist/index.mjs +79 -0
  4. package/miniflare-dist/index.mjs.map +7 -0
  5. package/package.json +24 -12
  6. package/pages/functions/filepath-routing.test.ts +212 -36
  7. package/pages/functions/filepath-routing.ts +69 -119
  8. package/pages/functions/routes.ts +8 -17
  9. package/pages/functions/template-worker.ts +3 -9
  10. package/src/__tests__/configuration.test.ts +2820 -0
  11. package/src/__tests__/dev.test.tsx +535 -65
  12. package/src/__tests__/guess-worker-format.test.ts +68 -0
  13. package/src/__tests__/helpers/faye-websocket.d.ts +6 -0
  14. package/src/__tests__/helpers/mock-account-id.ts +26 -8
  15. package/src/__tests__/helpers/mock-bin.ts +4 -1
  16. package/src/__tests__/helpers/mock-cfetch.ts +5 -5
  17. package/src/__tests__/helpers/mock-console.ts +21 -7
  18. package/src/__tests__/helpers/mock-kv.ts +9 -16
  19. package/src/__tests__/helpers/mock-stdin.ts +103 -0
  20. package/src/__tests__/helpers/mock-web-socket.ts +29 -0
  21. package/src/__tests__/helpers/run-in-tmp.ts +3 -0
  22. package/src/__tests__/helpers/run-wrangler.ts +5 -3
  23. package/src/__tests__/helpers/write-wrangler-toml.ts +17 -0
  24. package/src/__tests__/https-options.test.ts +127 -0
  25. package/src/__tests__/index.test.ts +467 -27
  26. package/src/__tests__/jest.setup.ts +37 -5
  27. package/src/__tests__/kv.test.ts +442 -201
  28. package/src/__tests__/logout.test.ts +15 -13
  29. package/src/__tests__/package-manager.test.ts +2 -2
  30. package/src/__tests__/pages.test.ts +82 -0
  31. package/src/__tests__/parse.test.ts +322 -0
  32. package/src/__tests__/publish.test.ts +2717 -430
  33. package/src/__tests__/r2.test.ts +198 -0
  34. package/src/__tests__/route.test.ts +45 -0
  35. package/src/__tests__/secret.test.ts +301 -86
  36. package/src/__tests__/sentry.test.ts +146 -0
  37. package/src/__tests__/tail.test.ts +638 -0
  38. package/src/__tests__/whoami.test.tsx +21 -7
  39. package/src/bundle.ts +155 -0
  40. package/src/cfetch/index.ts +8 -6
  41. package/src/cfetch/internal.ts +60 -22
  42. package/src/cli.ts +10 -0
  43. package/src/config/README.md +107 -0
  44. package/src/config/config.ts +218 -0
  45. package/src/config/diagnostics.ts +80 -0
  46. package/src/config/environment.ts +371 -0
  47. package/src/config/index.ts +62 -0
  48. package/src/config/validation-helpers.ts +554 -0
  49. package/src/config/validation.ts +1232 -0
  50. package/src/{api/preview.ts → create-worker-preview.ts} +59 -21
  51. package/src/create-worker-upload-form.ts +217 -0
  52. package/src/dev/dev.tsx +392 -0
  53. package/src/dev/local.tsx +232 -0
  54. package/src/dev/remote.tsx +203 -0
  55. package/src/dev/use-esbuild.ts +104 -0
  56. package/src/entry.ts +240 -0
  57. package/src/environment-variables.ts +33 -0
  58. package/src/https-options.ts +122 -0
  59. package/src/index.tsx +1068 -780
  60. package/src/inspect.ts +25 -4
  61. package/src/intl-polyfill.d.ts +139 -0
  62. package/src/{kv.tsx → kv.ts} +95 -60
  63. package/src/miniflare-cli/README.md +30 -0
  64. package/src/miniflare-cli/enum-keys.ts +17 -0
  65. package/src/miniflare-cli/index.ts +37 -0
  66. package/src/module-collection.ts +226 -31
  67. package/src/open-in-browser.ts +25 -0
  68. package/src/package-manager.ts +21 -15
  69. package/src/pages.tsx +35 -20
  70. package/src/parse.ts +183 -0
  71. package/src/proxy.ts +115 -45
  72. package/src/publish.ts +268 -328
  73. package/src/r2.ts +50 -0
  74. package/src/reporting.ts +131 -0
  75. package/src/selfsigned.d.ts +29 -0
  76. package/src/sites.tsx +83 -43
  77. package/src/tail/filters.ts +279 -0
  78. package/src/tail/index.ts +299 -0
  79. package/src/tail/printing.ts +62 -0
  80. package/src/user.tsx +234 -126
  81. package/src/{api/worker.ts → worker.ts} +44 -36
  82. package/templates/new-worker.js +1 -1
  83. package/templates/new-worker.ts +1 -1
  84. package/templates/tsconfig.json +105 -0
  85. package/wrangler-dist/cli.js +131202 -114243
  86. package/wrangler-dist/cli.js.map +3 -3
  87. package/src/__tests__/helpers/mock-user.ts +0 -27
  88. package/src/api/form_data.ts +0 -134
  89. package/src/config.ts +0 -641
  90. package/src/dev.tsx +0 -834
  91. package/src/tail.tsx +0 -73
@@ -2,17 +2,29 @@ import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
3
  import * as TOML from "@iarna/toml";
4
4
  import { mockAccountId, mockApiToken } from "./helpers/mock-account-id";
5
- import { setMockResponse, unsetAllMocks } from "./helpers/mock-cfetch";
5
+ import {
6
+ createFetchResult,
7
+ setMockRawResponse,
8
+ setMockResponse,
9
+ unsetAllMocks,
10
+ unsetMockFetchKVGetValues,
11
+ } from "./helpers/mock-cfetch";
6
12
  import { mockConsoleMethods } from "./helpers/mock-console";
7
13
  import { mockKeyListRequest } from "./helpers/mock-kv";
8
14
  import { runInTempDir } from "./helpers/run-in-tmp";
9
15
  import { runWrangler } from "./helpers/run-wrangler";
10
- import type { WorkerMetadata } from "../api/form_data";
11
- import type { Config } from "../config";
16
+ import writeWranglerToml from "./helpers/write-wrangler-toml";
17
+ import type { WorkerMetadata } from "../create-worker-upload-form";
12
18
  import type { KVNamespaceInfo } from "../kv";
13
19
  import type { FormData, File } from "undici";
14
20
 
15
21
  describe("publish", () => {
22
+ beforeEach(() => {
23
+ // @ts-expect-error we're using a very simple setTimeout mock here
24
+ jest.spyOn(global, "setTimeout").mockImplementation((fn, _period) => {
25
+ fn();
26
+ });
27
+ });
16
28
  mockAccountId();
17
29
  mockApiToken();
18
30
  runInTempDir();
@@ -20,6 +32,258 @@ describe("publish", () => {
20
32
 
21
33
  afterEach(() => {
22
34
  unsetAllMocks();
35
+ unsetMockFetchKVGetValues();
36
+ });
37
+
38
+ describe("environments", () => {
39
+ it("should use legacy environments by default", async () => {
40
+ writeWranglerToml({ env: { "some-env": {} } });
41
+ writeWorkerSource();
42
+ mockSubDomainRequest();
43
+ mockUploadWorkerRequest({
44
+ env: "some-env",
45
+ legacyEnv: true,
46
+ });
47
+ await runWrangler("publish index.js --env some-env");
48
+ expect(std.out).toMatchInlineSnapshot(`
49
+ "Uploaded test-name-some-env (TIMINGS)
50
+ Published test-name-some-env (TIMINGS)
51
+ test-name-some-env.test-sub-domain.workers.dev"
52
+ `);
53
+ expect(std.err).toMatchInlineSnapshot(`""`);
54
+ expect(std.warn).toMatchInlineSnapshot(`""`);
55
+ });
56
+
57
+ describe("legacy", () => {
58
+ it("uses the script name when no environment is specified", async () => {
59
+ writeWranglerToml();
60
+ writeWorkerSource();
61
+ mockSubDomainRequest();
62
+ mockUploadWorkerRequest({
63
+ legacyEnv: true,
64
+ });
65
+ await runWrangler("publish index.js --legacy-env true");
66
+ expect(std.out).toMatchInlineSnapshot(`
67
+ "Uploaded test-name (TIMINGS)
68
+ Published test-name (TIMINGS)
69
+ test-name.test-sub-domain.workers.dev"
70
+ `);
71
+ expect(std.err).toMatchInlineSnapshot(`""`);
72
+ expect(std.warn).toMatchInlineSnapshot(`""`);
73
+ });
74
+
75
+ it("appends the environment name when provided, and there is associated config", async () => {
76
+ writeWranglerToml({ env: { "some-env": {} } });
77
+ writeWorkerSource();
78
+ mockSubDomainRequest();
79
+ mockUploadWorkerRequest({
80
+ env: "some-env",
81
+ legacyEnv: true,
82
+ });
83
+ await runWrangler("publish index.js --env some-env --legacy-env true");
84
+ expect(std.out).toMatchInlineSnapshot(`
85
+ "Uploaded test-name-some-env (TIMINGS)
86
+ Published test-name-some-env (TIMINGS)
87
+ test-name-some-env.test-sub-domain.workers.dev"
88
+ `);
89
+ expect(std.err).toMatchInlineSnapshot(`""`);
90
+ expect(std.warn).toMatchInlineSnapshot(`""`);
91
+ });
92
+
93
+ it("appends the environment name when provided (with a warning), if there are no configured environments", async () => {
94
+ writeWranglerToml({});
95
+ writeWorkerSource();
96
+ mockSubDomainRequest();
97
+ mockUploadWorkerRequest({
98
+ env: "some-env",
99
+ legacyEnv: true,
100
+ });
101
+ await runWrangler("publish index.js --env some-env --legacy-env true");
102
+ expect(std.out).toMatchInlineSnapshot(`
103
+ "Uploaded test-name-some-env (TIMINGS)
104
+ Published test-name-some-env (TIMINGS)
105
+ test-name-some-env.test-sub-domain.workers.dev"
106
+ `);
107
+ expect(std.err).toMatchInlineSnapshot(`""`);
108
+ expect(std.warn).toMatchInlineSnapshot(`
109
+ "Processing wrangler.toml configuration:
110
+ - No environment found in configuration with name \\"some-env\\".
111
+ Before using \`--env=some-env\` there should be an equivalent environment section in the configuration.
112
+
113
+ Consider adding an environment configuration section to the wrangler.toml file:
114
+ \`\`\`
115
+ [env.some-env]
116
+ \`\`\`
117
+ "
118
+ `);
119
+ });
120
+
121
+ it("should throw an error when an environment name when provided, which doesn't match those in the config", async () => {
122
+ writeWranglerToml({ env: { "other-env": {} } });
123
+ writeWorkerSource();
124
+ mockSubDomainRequest();
125
+ await expect(
126
+ runWrangler("publish index.js --env some-env --legacy-env true")
127
+ ).rejects.toThrowErrorMatchingInlineSnapshot(`
128
+ "Processing wrangler.toml configuration:
129
+ - No environment found in configuration with name \\"some-env\\".
130
+ Before using \`--env=some-env\` there should be an equivalent environment section in the configuration.
131
+ The available configured environment names are: [\\"other-env\\"]
132
+
133
+ Consider adding an environment configuration section to the wrangler.toml file:
134
+ \`\`\`
135
+ [env.some-env]
136
+ \`\`\`
137
+ "
138
+ `);
139
+ });
140
+
141
+ it("should throw an error w/ helpful message when using --env --name", async () => {
142
+ writeWranglerToml({ env: { "some-env": {} } });
143
+ writeWorkerSource();
144
+ mockSubDomainRequest();
145
+ await runWrangler(
146
+ "publish index.js --name voyager --env some-env --legacy-env true"
147
+ ).catch((err) =>
148
+ expect(err).toMatchInlineSnapshot(`
149
+ [Error: In legacy environment mode you cannot use --name and --env together. If you want to specify a Worker name for a specific environment you can add the following to your wrangler.toml config:
150
+ [env.some-env]
151
+ name = "voyager"
152
+ ]
153
+ `)
154
+ );
155
+ });
156
+ });
157
+
158
+ describe("services", () => {
159
+ it("uses the script name when no environment is specified", async () => {
160
+ writeWranglerToml();
161
+ writeWorkerSource();
162
+ mockSubDomainRequest();
163
+ mockUploadWorkerRequest({
164
+ legacyEnv: false,
165
+ });
166
+ await runWrangler("publish index.js");
167
+ expect(std.out).toMatchInlineSnapshot(`
168
+ "Uploaded test-name (TIMINGS)
169
+ Published test-name (TIMINGS)
170
+ test-name.test-sub-domain.workers.dev"
171
+ `);
172
+ expect(std.err).toMatchInlineSnapshot(`""`);
173
+ expect(std.warn).toMatchInlineSnapshot(`""`);
174
+ });
175
+
176
+ it("publishes as an environment when provided", async () => {
177
+ writeWranglerToml({ env: { "some-env": {} } });
178
+ writeWorkerSource();
179
+ mockSubDomainRequest();
180
+ mockUploadWorkerRequest({
181
+ env: "some-env",
182
+ legacyEnv: false,
183
+ });
184
+ await runWrangler("publish index.js --env some-env --legacy-env false");
185
+ expect(std.out).toMatchInlineSnapshot(`
186
+ "Uploaded test-name (some-env) (TIMINGS)
187
+ Published test-name (some-env) (TIMINGS)
188
+ some-env.test-name.test-sub-domain.workers.dev"
189
+ `);
190
+ expect(std.err).toMatchInlineSnapshot(`""`);
191
+ expect(std.warn).toMatchInlineSnapshot(`""`);
192
+ });
193
+ });
194
+ });
195
+
196
+ it("should resolve wrangler.toml relative to the entrypoint", async () => {
197
+ fs.mkdirSync("./some-path/worker", { recursive: true });
198
+ fs.writeFileSync(
199
+ "./some-path/wrangler.toml",
200
+ TOML.stringify({
201
+ name: "test-name",
202
+ compatibility_date: "2022-01-12",
203
+ vars: { xyz: 123 },
204
+ }),
205
+ "utf-8"
206
+ );
207
+ writeWorkerSource({ basePath: "./some-path/worker" });
208
+ mockUploadWorkerRequest({
209
+ expectedBindings: [
210
+ {
211
+ json: 123,
212
+ name: "xyz",
213
+ type: "json",
214
+ },
215
+ ],
216
+ expectedCompatibilityDate: "2022-01-12",
217
+ });
218
+ mockSubDomainRequest();
219
+ await runWrangler("publish ./some-path/worker/index.js");
220
+ expect(std.out).toMatchInlineSnapshot(`
221
+ "Uploaded test-name (TIMINGS)
222
+ Published test-name (TIMINGS)
223
+ test-name.test-sub-domain.workers.dev"
224
+ `);
225
+ expect(std.err).toMatchInlineSnapshot(`""`);
226
+ });
227
+
228
+ describe("routes", () => {
229
+ it("should publish the worker to a route", async () => {
230
+ writeWranglerToml({
231
+ routes: ["example.com/some-route/*"],
232
+ });
233
+ writeWorkerSource();
234
+ mockUpdateWorkerRequest({ enabled: false });
235
+ mockUploadWorkerRequest({ expectedType: "esm" });
236
+ mockPublishRoutesRequest({ routes: ["example.com/some-route/*"] });
237
+ await runWrangler("publish ./index");
238
+ });
239
+
240
+ it("should publish to legacy environment specific routes", async () => {
241
+ writeWranglerToml({
242
+ routes: ["example.com/some-route/*"],
243
+ env: {
244
+ dev: {
245
+ routes: ["dev-example.com/some-route/*"],
246
+ },
247
+ },
248
+ });
249
+ writeWorkerSource();
250
+ mockUpdateWorkerRequest({ enabled: false, legacyEnv: true, env: "dev" });
251
+ mockUploadWorkerRequest({
252
+ expectedType: "esm",
253
+ legacyEnv: true,
254
+ env: "dev",
255
+ });
256
+ mockPublishRoutesRequest({
257
+ routes: ["dev-example.com/some-route/*"],
258
+ legacyEnv: true,
259
+ env: "dev",
260
+ });
261
+ await runWrangler("publish ./index --env dev --legacy-env true");
262
+ });
263
+
264
+ it("services: should publish to service environment specific routes", async () => {
265
+ writeWranglerToml({
266
+ routes: ["example.com/some-route/*"],
267
+ env: {
268
+ dev: {
269
+ routes: ["dev-example.com/some-route/*"],
270
+ },
271
+ },
272
+ });
273
+ writeWorkerSource();
274
+ mockUpdateWorkerRequest({ enabled: false, env: "dev" });
275
+ mockUploadWorkerRequest({
276
+ expectedType: "esm",
277
+ env: "dev",
278
+ });
279
+ mockPublishRoutesRequest({
280
+ routes: ["dev-example.com/some-route/*"],
281
+ env: "dev",
282
+ });
283
+ await runWrangler("publish ./index --env dev --legacy-env false");
284
+ });
285
+
286
+ it.todo("should error if it's a workers.dev route");
23
287
  });
24
288
 
25
289
  describe("entry-points", () => {
@@ -32,17 +296,13 @@ describe("publish", () => {
32
296
  await runWrangler("publish ./index");
33
297
 
34
298
  expect(std.out).toMatchInlineSnapshot(`
35
- "Uploaded
36
- test-name
37
- (TIMINGS)
38
- Deployed
39
- test-name
40
- (TIMINGS)
41
-
42
- test-name.test-sub-domain.workers.dev"
43
- `);
299
+ "Uploaded test-name (TIMINGS)
300
+ Published test-name (TIMINGS)
301
+ test-name.test-sub-domain.workers.dev"
302
+ `);
44
303
  expect(std.err).toMatchInlineSnapshot(`""`);
45
304
  });
305
+
46
306
  it("should be able to use `index` with no extension as the entry-point (sw)", async () => {
47
307
  writeWranglerToml();
48
308
  writeWorkerSource({ type: "sw" });
@@ -52,20 +312,15 @@ describe("publish", () => {
52
312
  await runWrangler("publish ./index");
53
313
 
54
314
  expect(std.out).toMatchInlineSnapshot(`
55
- "Uploaded
56
- test-name
57
- (TIMINGS)
58
- Deployed
59
- test-name
60
- (TIMINGS)
61
-
62
- test-name.test-sub-domain.workers.dev"
63
- `);
315
+ "Uploaded test-name (TIMINGS)
316
+ Published test-name (TIMINGS)
317
+ test-name.test-sub-domain.workers.dev"
318
+ `);
64
319
  expect(std.err).toMatchInlineSnapshot(`""`);
65
320
  });
66
321
 
67
- it("should be able to use the `build.upload.main` config as the entry-point for ESM sources", async () => {
68
- writeWranglerToml({ build: { upload: { main: "./index.js" } } });
322
+ it("should be able to use the `main` config as the entry-point for ESM sources", async () => {
323
+ writeWranglerToml({ main: "./index.js" });
69
324
  writeWorkerSource();
70
325
  mockUploadWorkerRequest();
71
326
  mockSubDomainRequest();
@@ -73,16 +328,107 @@ describe("publish", () => {
73
328
  await runWrangler("publish");
74
329
 
75
330
  expect(std.out).toMatchInlineSnapshot(`
76
- "Uploaded
77
- test-name
78
- (TIMINGS)
79
- Deployed
80
- test-name
81
- (TIMINGS)
82
-
83
- test-name.test-sub-domain.workers.dev"
84
- `);
331
+ "Uploaded test-name (TIMINGS)
332
+ Published test-name (TIMINGS)
333
+ test-name.test-sub-domain.workers.dev"
334
+ `);
335
+ expect(std.err).toMatchInlineSnapshot(`""`);
336
+ });
337
+
338
+ it("should use `main` relative to the wrangler.toml not cwd", async () => {
339
+ writeWranglerToml({
340
+ main: "./foo/index.js",
341
+ });
342
+ writeWorkerSource({ basePath: "foo" });
343
+ mockUploadWorkerRequest({ expectedEntry: "var foo = 100;" });
344
+ mockSubDomainRequest();
345
+ process.chdir("foo");
346
+ await runWrangler("publish");
347
+
348
+ expect(std.out).toMatchInlineSnapshot(`
349
+ "Uploaded test-name (TIMINGS)
350
+ Published test-name (TIMINGS)
351
+ test-name.test-sub-domain.workers.dev"
352
+ `);
353
+ expect(std.err).toMatchInlineSnapshot(`""`);
354
+ });
355
+
356
+ it('should use `build.upload.main` as an entry point, where `build.upload.dir` defaults to "./dist", and log a deprecation warning', async () => {
357
+ writeWranglerToml({ build: { upload: { main: "./index.js" } } });
358
+ writeWorkerSource({ basePath: "./dist" });
359
+ mockUploadWorkerRequest();
360
+ mockSubDomainRequest();
361
+
362
+ await runWrangler("publish");
363
+
364
+ expect(std.out).toMatchInlineSnapshot(`
365
+ "Uploaded test-name (TIMINGS)
366
+ Published test-name (TIMINGS)
367
+ test-name.test-sub-domain.workers.dev"
368
+ `);
369
+ expect(std.err).toMatchInlineSnapshot(`""`);
370
+ expect(std.warn).toMatchInlineSnapshot(`
371
+ "Processing wrangler.toml configuration:
372
+ - DEPRECATION: \\"build.upload.main\\":
373
+ Delete the \`build.upload.main\` and \`build.upload.dir\` fields.
374
+ Then add the top level \`main\` field to your configuration file:
375
+ \`\`\`
376
+ main = \\"dist/index.js\\"
377
+ \`\`\`"
378
+ `);
379
+ });
380
+
381
+ it("should use `build.upload.main` relative to `build.upload.dir`", async () => {
382
+ writeWranglerToml({
383
+ build: {
384
+ upload: {
385
+ main: "./index.js",
386
+ dir: "./foo",
387
+ },
388
+ },
389
+ });
390
+ writeWorkerSource({ basePath: "./foo" });
391
+ mockUploadWorkerRequest({ expectedEntry: "var foo = 100;" });
392
+ mockSubDomainRequest();
393
+ process.chdir("foo");
394
+ await runWrangler("publish");
395
+
396
+ expect(std.out).toMatchInlineSnapshot(`
397
+ "Uploaded test-name (TIMINGS)
398
+ Published test-name (TIMINGS)
399
+ test-name.test-sub-domain.workers.dev"
400
+ `);
85
401
  expect(std.err).toMatchInlineSnapshot(`""`);
402
+ expect(std.warn).toMatchInlineSnapshot(`
403
+ "Processing ../wrangler.toml configuration:
404
+ - DEPRECATION: \\"build.upload.main\\":
405
+ Delete the \`build.upload.main\` and \`build.upload.dir\` fields.
406
+ Then add the top level \`main\` field to your configuration file:
407
+ \`\`\`
408
+ main = \\"foo/index.js\\"
409
+ \`\`\`
410
+ - DEPRECATION: \\"build.upload.dir\\":
411
+ Use the top level \\"main\\" field or a command-line argument to specify the entry-point for the Worker."
412
+ `);
413
+ });
414
+
415
+ it("should error when both `main` and `build.upload.main` are used", async () => {
416
+ writeWranglerToml({
417
+ main: "./index.js",
418
+ build: {
419
+ upload: {
420
+ main: "./index.js",
421
+ dir: "./foo",
422
+ },
423
+ },
424
+ });
425
+ await expect(runWrangler("publish")).rejects
426
+ .toThrowErrorMatchingInlineSnapshot(`
427
+ "Processing wrangler.toml configuration:
428
+ - Don't define both the \`main\` and \`build.upload.main\` fields in your configuration.
429
+ They serve the same purpose: to point to the entry-point of your worker.
430
+ Delete the \`build.upload.main\` and \`build.upload.dir\` field from your config."
431
+ `);
86
432
  });
87
433
 
88
434
  it("should be able to transpile TypeScript (esm)", async () => {
@@ -93,15 +439,10 @@ describe("publish", () => {
93
439
  await runWrangler("publish index.ts");
94
440
 
95
441
  expect(std.out).toMatchInlineSnapshot(`
96
- "Uploaded
97
- test-name
98
- (TIMINGS)
99
- Deployed
100
- test-name
101
- (TIMINGS)
102
-
103
- test-name.test-sub-domain.workers.dev"
104
- `);
442
+ "Uploaded test-name (TIMINGS)
443
+ Published test-name (TIMINGS)
444
+ test-name.test-sub-domain.workers.dev"
445
+ `);
105
446
  expect(std.err).toMatchInlineSnapshot(`""`);
106
447
  });
107
448
 
@@ -116,19 +457,14 @@ describe("publish", () => {
116
457
  await runWrangler("publish index.ts");
117
458
 
118
459
  expect(std.out).toMatchInlineSnapshot(`
119
- "Uploaded
120
- test-name
121
- (TIMINGS)
122
- Deployed
123
- test-name
124
- (TIMINGS)
125
-
126
- test-name.test-sub-domain.workers.dev"
127
- `);
460
+ "Uploaded test-name (TIMINGS)
461
+ Published test-name (TIMINGS)
462
+ test-name.test-sub-domain.workers.dev"
463
+ `);
128
464
  expect(std.err).toMatchInlineSnapshot(`""`);
129
465
  });
130
466
 
131
- it("should inline referenced text modules into the worker", async () => {
467
+ it("should add referenced text modules into the form upload", async () => {
132
468
  writeWranglerToml();
133
469
  fs.writeFileSync(
134
470
  "./index.js",
@@ -142,18 +478,18 @@ export default{
142
478
  `
143
479
  );
144
480
  fs.writeFileSync("./textfile.txt", "Hello, World!");
145
- mockUploadWorkerRequest({ expectedEntry: "Hello, World!" });
481
+ mockUploadWorkerRequest({
482
+ expectedModules: {
483
+ "./0a0a9f2a6772942557ab5355d76af442f8f65e01-textfile.txt":
484
+ "Hello, World!",
485
+ },
486
+ });
146
487
  mockSubDomainRequest();
147
488
  await runWrangler("publish index.js");
148
489
  expect(std.out).toMatchInlineSnapshot(`
149
- "Uploaded
150
- test-name
151
- (TIMINGS)
152
- Deployed
153
- test-name
154
- (TIMINGS)
155
-
156
- test-name.test-sub-domain.workers.dev"
490
+ "Uploaded test-name (TIMINGS)
491
+ Published test-name (TIMINGS)
492
+ test-name.test-sub-domain.workers.dev"
157
493
  `);
158
494
  expect(std.err).toMatchInlineSnapshot(`""`);
159
495
  });
@@ -167,15 +503,10 @@ export default{
167
503
  await runWrangler("publish ./src/index.js");
168
504
 
169
505
  expect(std.out).toMatchInlineSnapshot(`
170
- "Uploaded
171
- test-name
172
- (TIMINGS)
173
- Deployed
174
- test-name
175
- (TIMINGS)
176
-
177
- test-name.test-sub-domain.workers.dev"
178
- `);
506
+ "Uploaded test-name (TIMINGS)
507
+ Published test-name (TIMINGS)
508
+ test-name.test-sub-domain.workers.dev"
509
+ `);
179
510
  expect(std.err).toMatchInlineSnapshot(`""`);
180
511
  });
181
512
 
@@ -191,50 +522,39 @@ export default{
191
522
  await runWrangler("publish ./src/index.js");
192
523
 
193
524
  expect(std.out).toMatchInlineSnapshot(`
194
- "Uploaded
195
- test-name
196
- (TIMINGS)
197
- Deployed
198
- test-name
199
- (TIMINGS)
200
-
201
- test-name.test-sub-domain.workers.dev"
202
- `);
525
+ "Uploaded test-name (TIMINGS)
526
+ Published test-name (TIMINGS)
527
+ test-name.test-sub-domain.workers.dev"
528
+ `);
203
529
  expect(std.err).toMatchInlineSnapshot(`""`);
204
530
  });
205
531
 
206
532
  it('should error if a site definition doesn\'t have a "bucket" field', async () => {
207
533
  writeWranglerToml({
208
- // @ts-expect-error we're purposely missing the required `site.bucket` field
209
- site: {
210
- "entry-point": "./index.js",
211
- },
534
+ // @ts-expect-error we're intentionally setting an invalid config
535
+ site: {},
212
536
  });
213
537
  writeWorkerSource();
214
538
  mockUploadWorkerRequest();
215
539
  mockSubDomainRequest();
216
540
 
217
- await expect(
218
- runWrangler("publish ./index.js")
219
- ).rejects.toThrowErrorMatchingInlineSnapshot(
220
- `"A [site] definition requires a \`bucket\` field with a path to the site's public directory."`
221
- );
541
+ await expect(runWrangler("publish ./index.js")).rejects
542
+ .toThrowErrorMatchingInlineSnapshot(`
543
+ "Processing wrangler.toml configuration:
544
+ - \\"site.bucket\\" is a required field."
545
+ `);
222
546
 
223
547
  expect(std.out).toMatchInlineSnapshot(`""`);
224
548
  expect(std.err).toMatchInlineSnapshot(`
225
- "A [site] definition requires a \`bucket\` field with a path to the site's public directory.
549
+ "Processing wrangler.toml configuration:
550
+ - \\"site.bucket\\" is a required field.
226
551
 
227
- %s
228
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
229
- `);
230
- expect(std.warn).toMatchInlineSnapshot(`
231
- "Deprecation notice: The \`site.entry-point\` config field is no longer used.
232
- The entry-point should be specified via the command line (e.g. \`wrangler publish path/to/script\`) or the \`build.upload.main\` config field.
233
- Please remove the \`site.entry-point\` field from the \`wrangler.toml\` file."
552
+ %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
234
553
  `);
554
+ expect(std.warn).toMatchInlineSnapshot(`""`);
235
555
  });
236
556
 
237
- it("should warn if there is a `site.entry-point` configuration", async () => {
557
+ it("should error if there is a `site.entry-point` configuration", async () => {
238
558
  const assets = [
239
559
  { filePath: "assets/file-1.txt", content: "Content of file-1" },
240
560
  { filePath: "assets/file-2.txt", content: "Content of file-2" },
@@ -258,27 +578,26 @@ export default{
258
578
  mockKeyListRequest(kvNamespace.id, []);
259
579
  mockUploadAssetsToKVRequest(kvNamespace.id, assets);
260
580
 
261
- await runWrangler("publish ./index.js");
581
+ await expect(runWrangler("publish ./index.js")).rejects
582
+ .toThrowErrorMatchingInlineSnapshot(`
583
+ "Processing wrangler.toml configuration:
584
+ - DEPRECATION: \\"site.entry-point\\":
585
+ The \`site.entry-point\` config field is no longer used.
586
+ The entry-point should be specified via the command line or the \`main\` config field."
587
+ `);
262
588
 
263
- expect(std.out).toMatchInlineSnapshot(`
264
- "reading assets/file-1.txt...
265
- uploading as assets/file-1.2ca234f380.txt...
266
- reading assets/file-2.txt...
267
- uploading as assets/file-2.5938485188.txt...
268
- Uploaded
269
- test-name
270
- (TIMINGS)
271
- Deployed
272
- test-name
273
- (TIMINGS)
274
-
275
- test-name.test-sub-domain.workers.dev"
589
+ expect(std.out).toMatchInlineSnapshot(`""`);
590
+ expect(std.err).toMatchInlineSnapshot(`
591
+ "Processing wrangler.toml configuration:
592
+ - DEPRECATION: \\"site.entry-point\\":
593
+ The \`site.entry-point\` config field is no longer used.
594
+ The entry-point should be specified via the command line or the \`main\` config field.
595
+
596
+ %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
276
597
  `);
277
- expect(std.err).toMatchInlineSnapshot(`""`);
278
598
  expect(std.warn).toMatchInlineSnapshot(`
279
- "Deprecation notice: The \`site.entry-point\` config field is no longer used.
280
- The entry-point should be specified via the command line (e.g. \`wrangler publish path/to/script\`) or the \`build.upload.main\` config field.
281
- Please remove the \`site.entry-point\` field from the \`wrangler.toml\` file."
599
+ "Processing wrangler.toml configuration:
600
+ - Unexpected fields found in site field: \\"entry-point\\""
282
601
  `);
283
602
  });
284
603
 
@@ -290,15 +609,14 @@ export default{
290
609
  await expect(
291
610
  runWrangler("publish")
292
611
  ).rejects.toThrowErrorMatchingInlineSnapshot(
293
- `"Missing entry-point: The entry-point should be specified via the command line (e.g. \`wrangler publish path/to/script\`) or the \`build.upload.main\` config field."`
612
+ `"Missing entry-point: The entry-point should be specified via the command line (e.g. \`wrangler publish path/to/script\`) or the \`main\` config field."`
294
613
  );
295
614
 
296
615
  expect(std.out).toMatchInlineSnapshot(`""`);
297
616
  expect(std.err).toMatchInlineSnapshot(`
298
- "Missing entry-point: The entry-point should be specified via the command line (e.g. \`wrangler publish path/to/script\`) or the \`build.upload.main\` config field.
617
+ "Missing entry-point: The entry-point should be specified via the command line (e.g. \`wrangler publish path/to/script\`) or the \`main\` config field.
299
618
 
300
- %s
301
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
619
+ %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
302
620
  `);
303
621
  });
304
622
  });
@@ -314,7 +632,7 @@ export default{
314
632
  id: "__test-name-workers_sites_assets-id",
315
633
  };
316
634
  writeWranglerToml({
317
- build: { upload: { main: "./index.js" } },
635
+ main: "./index.js",
318
636
  site: {
319
637
  bucket: "assets",
320
638
  },
@@ -333,19 +651,15 @@ export default{
333
651
  uploading as assets/file-1.2ca234f380.txt...
334
652
  reading assets/file-2.txt...
335
653
  uploading as assets/file-2.5938485188.txt...
336
- Uploaded
337
- test-name
338
- (TIMINGS)
339
- Deployed
340
- test-name
341
- (TIMINGS)
342
-
343
- test-name.test-sub-domain.workers.dev"
654
+ ↗️ Done syncing assets
655
+ Uploaded test-name (TIMINGS)
656
+ Published test-name (TIMINGS)
657
+ test-name.test-sub-domain.workers.dev"
344
658
  `);
345
659
  expect(std.err).toMatchInlineSnapshot(`""`);
346
660
  });
347
661
 
348
- it("when using a service worker type, it should inline an asset manifest, and bind to a namespace", async () => {
662
+ it("when using a service worker type, it should add an asset manifest as a text_blob, and bind to a namespace", async () => {
349
663
  const assets = [
350
664
  { filePath: "assets/file-1.txt", content: "Content of file-1" },
351
665
  { filePath: "assets/file-2.txt", content: "Content of file-2" },
@@ -355,7 +669,7 @@ export default{
355
669
  id: "__test-name-workers_sites_assets-id",
356
670
  };
357
671
  writeWranglerToml({
358
- build: { upload: { main: "./index.js" } },
672
+ main: "./index.js",
359
673
  site: {
360
674
  bucket: "assets",
361
675
  },
@@ -364,13 +678,21 @@ export default{
364
678
  writeAssets(assets);
365
679
  mockUploadWorkerRequest({
366
680
  expectedType: "sw",
367
- expectedEntry: `const __STATIC_CONTENT_MANIFEST = {"file-1.txt":"assets/file-1.2ca234f380.txt","file-2.txt":"assets/file-2.5938485188.txt"};`,
681
+ expectedModules: {
682
+ __STATIC_CONTENT_MANIFEST:
683
+ '{"file-1.txt":"assets/file-1.2ca234f380.txt","file-2.txt":"assets/file-2.5938485188.txt"}',
684
+ },
368
685
  expectedBindings: [
369
686
  {
370
687
  name: "__STATIC_CONTENT",
371
688
  namespace_id: "__test-name-workers_sites_assets-id",
372
689
  type: "kv_namespace",
373
690
  },
691
+ {
692
+ name: "__STATIC_CONTENT_MANIFEST",
693
+ part: "__STATIC_CONTENT_MANIFEST",
694
+ type: "text_blob",
695
+ },
374
696
  ],
375
697
  });
376
698
  mockSubDomainRequest();
@@ -385,14 +707,10 @@ export default{
385
707
  uploading as assets/file-1.2ca234f380.txt...
386
708
  reading assets/file-2.txt...
387
709
  uploading as assets/file-2.5938485188.txt...
388
- Uploaded
389
- test-name
390
- (TIMINGS)
391
- Deployed
392
- test-name
393
- (TIMINGS)
394
-
395
- test-name.test-sub-domain.workers.dev"
710
+ ↗️ Done syncing assets
711
+ Uploaded test-name (TIMINGS)
712
+ Published test-name (TIMINGS)
713
+ test-name.test-sub-domain.workers.dev"
396
714
  `);
397
715
  expect(std.err).toMatchInlineSnapshot(`""`);
398
716
  });
@@ -407,7 +725,7 @@ export default{
407
725
  id: "__test-name-workers_sites_assets-id",
408
726
  };
409
727
  writeWranglerToml({
410
- build: { upload: { main: "./index.js" } },
728
+ main: "./index.js",
411
729
  site: {
412
730
  bucket: "assets",
413
731
  },
@@ -439,19 +757,15 @@ export default{
439
757
  uploading as assets/file-1.2ca234f380.txt...
440
758
  reading assets/file-2.txt...
441
759
  uploading as assets/file-2.5938485188.txt...
442
- Uploaded
443
- test-name
444
- (TIMINGS)
445
- Deployed
446
- test-name
447
- (TIMINGS)
448
-
449
- test-name.test-sub-domain.workers.dev"
760
+ ↗️ Done syncing assets
761
+ Uploaded test-name (TIMINGS)
762
+ Published test-name (TIMINGS)
763
+ test-name.test-sub-domain.workers.dev"
450
764
  `);
451
765
  expect(std.err).toMatchInlineSnapshot(`""`);
452
766
  });
453
767
 
454
- it("should make environment specific kv namespace for assets", async () => {
768
+ it("should make environment specific kv namespace for assets, even for service envs", async () => {
455
769
  // This is the same test as the one before this, but with an env arg
456
770
  const assets = [
457
771
  { filePath: "assets/file-1.txt", content: "Content of file-1" },
@@ -462,14 +776,64 @@ export default{
462
776
  id: "__test-name-some-env-workers_sites_assets-id",
463
777
  };
464
778
  writeWranglerToml({
465
- build: { upload: { main: "./index.js" } },
779
+ main: "./index.js",
780
+ site: {
781
+ bucket: "assets",
782
+ },
783
+ env: { "some-env": {} },
784
+ });
785
+ writeWorkerSource();
786
+ writeAssets(assets);
787
+ mockUploadWorkerRequest({
788
+ env: "some-env",
789
+ expectedBindings: [
790
+ {
791
+ name: "__STATIC_CONTENT",
792
+ namespace_id: "__test-name-some-env-workers_sites_assets-id",
793
+ type: "kv_namespace",
794
+ },
795
+ ],
796
+ });
797
+ mockSubDomainRequest();
798
+ mockListKVNamespacesRequest(kvNamespace);
799
+ mockKeyListRequest(kvNamespace.id, []);
800
+ mockUploadAssetsToKVRequest(kvNamespace.id, assets);
801
+ await runWrangler("publish --env some-env --legacy-env false");
802
+
803
+ expect(std.out).toMatchInlineSnapshot(`
804
+ "reading assets/file-1.txt...
805
+ uploading as assets/file-1.2ca234f380.txt...
806
+ reading assets/file-2.txt...
807
+ uploading as assets/file-2.5938485188.txt...
808
+ ↗️ Done syncing assets
809
+ Uploaded test-name (some-env) (TIMINGS)
810
+ Published test-name (some-env) (TIMINGS)
811
+ some-env.test-name.test-sub-domain.workers.dev"
812
+ `);
813
+ expect(std.err).toMatchInlineSnapshot(`""`);
814
+ });
815
+
816
+ it("should make environment specific kv namespace for assets, even for legacy envs", async () => {
817
+ // And this is the same test as the one before this, but with legacyEnv:true
818
+ const assets = [
819
+ { filePath: "assets/file-1.txt", content: "Content of file-1" },
820
+ { filePath: "assets/file-2.txt", content: "Content of file-2" },
821
+ ];
822
+ const kvNamespace = {
823
+ title: "__test-name-some-env-workers_sites_assets",
824
+ id: "__test-name-some-env-workers_sites_assets-id",
825
+ };
826
+ writeWranglerToml({
827
+ main: "./index.js",
466
828
  site: {
467
829
  bucket: "assets",
468
830
  },
831
+ env: { "some-env": {} },
469
832
  });
470
833
  writeWorkerSource();
471
834
  writeAssets(assets);
472
835
  mockUploadWorkerRequest({
836
+ legacyEnv: true,
473
837
  env: "some-env",
474
838
  expectedBindings: [
475
839
  {
@@ -483,21 +847,17 @@ export default{
483
847
  mockListKVNamespacesRequest(kvNamespace);
484
848
  mockKeyListRequest(kvNamespace.id, []);
485
849
  mockUploadAssetsToKVRequest(kvNamespace.id, assets);
486
- await runWrangler("publish --env some-env");
850
+ await runWrangler("publish --env some-env --legacy-env true");
487
851
 
488
852
  expect(std.out).toMatchInlineSnapshot(`
489
853
  "reading assets/file-1.txt...
490
854
  uploading as assets/file-1.2ca234f380.txt...
491
855
  reading assets/file-2.txt...
492
856
  uploading as assets/file-2.5938485188.txt...
493
- Uploaded
494
- test-name (some-env)
495
- (TIMINGS)
496
- Deployed
497
- test-name (some-env)
498
- (TIMINGS)
499
-
500
- some-env.test-name.test-sub-domain.workers.dev"
857
+ ↗️ Done syncing assets
858
+ Uploaded test-name-some-env (TIMINGS)
859
+ Published test-name-some-env (TIMINGS)
860
+ test-name-some-env.test-sub-domain.workers.dev"
501
861
  `);
502
862
  expect(std.err).toMatchInlineSnapshot(`""`);
503
863
  });
@@ -512,7 +872,7 @@ export default{
512
872
  id: "__test-name-workers_sites_assets-id",
513
873
  };
514
874
  writeWranglerToml({
515
- build: { upload: { main: "./index.js" } },
875
+ main: "./index.js",
516
876
  site: {
517
877
  bucket: "assets",
518
878
  },
@@ -523,7 +883,9 @@ export default{
523
883
  mockSubDomainRequest();
524
884
  mockListKVNamespacesRequest(kvNamespace);
525
885
  // Put file-1 in the KV namespace
526
- mockKeyListRequest(kvNamespace.id, ["assets/file-1.2ca234f380.txt"]);
886
+ mockKeyListRequest(kvNamespace.id, [
887
+ { name: "assets/file-1.2ca234f380.txt" },
888
+ ]);
527
889
  // Check we do not upload file-1
528
890
  mockUploadAssetsToKVRequest(
529
891
  kvNamespace.id,
@@ -536,14 +898,10 @@ export default{
536
898
  skipping - already uploaded
537
899
  reading assets/file-2.txt...
538
900
  uploading as assets/file-2.5938485188.txt...
539
- Uploaded
540
- test-name
541
- (TIMINGS)
542
- Deployed
543
- test-name
544
- (TIMINGS)
545
-
546
- test-name.test-sub-domain.workers.dev"
901
+ ↗️ Done syncing assets
902
+ Uploaded test-name (TIMINGS)
903
+ Published test-name (TIMINGS)
904
+ test-name.test-sub-domain.workers.dev"
547
905
  `);
548
906
  expect(std.err).toMatchInlineSnapshot(`""`);
549
907
  });
@@ -558,7 +916,7 @@ export default{
558
916
  id: "__test-name-workers_sites_assets-id",
559
917
  };
560
918
  writeWranglerToml({
561
- build: { upload: { main: "./index.js" } },
919
+ main: "./index.js",
562
920
  site: {
563
921
  bucket: "assets",
564
922
  },
@@ -577,17 +935,13 @@ export default{
577
935
  await runWrangler("publish --site-include file-1.txt");
578
936
 
579
937
  expect(std.out).toMatchInlineSnapshot(`
580
- "reading assets/file-1.txt...
581
- uploading as assets/file-1.2ca234f380.txt...
582
- Uploaded
583
- test-name
584
- (TIMINGS)
585
- Deployed
586
- test-name
587
- (TIMINGS)
588
-
589
- test-name.test-sub-domain.workers.dev"
590
- `);
938
+ "reading assets/file-1.txt...
939
+ uploading as assets/file-1.2ca234f380.txt...
940
+ ↗️ Done syncing assets
941
+ Uploaded test-name (TIMINGS)
942
+ Published test-name (TIMINGS)
943
+ test-name.test-sub-domain.workers.dev"
944
+ `);
591
945
  expect(std.err).toMatchInlineSnapshot(`""`);
592
946
  });
593
947
 
@@ -601,7 +955,7 @@ export default{
601
955
  id: "__test-name-workers_sites_assets-id",
602
956
  };
603
957
  writeWranglerToml({
604
- build: { upload: { main: "./index.js" } },
958
+ main: "./index.js",
605
959
  site: {
606
960
  bucket: "assets",
607
961
  },
@@ -620,17 +974,13 @@ export default{
620
974
  await runWrangler("publish --site-exclude file-2.txt");
621
975
 
622
976
  expect(std.out).toMatchInlineSnapshot(`
623
- "reading assets/file-1.txt...
624
- uploading as assets/file-1.2ca234f380.txt...
625
- Uploaded
626
- test-name
627
- (TIMINGS)
628
- Deployed
629
- test-name
630
- (TIMINGS)
631
-
632
- test-name.test-sub-domain.workers.dev"
633
- `);
977
+ "reading assets/file-1.txt...
978
+ uploading as assets/file-1.2ca234f380.txt...
979
+ ↗️ Done syncing assets
980
+ Uploaded test-name (TIMINGS)
981
+ Published test-name (TIMINGS)
982
+ test-name.test-sub-domain.workers.dev"
983
+ `);
634
984
  expect(std.err).toMatchInlineSnapshot(`""`);
635
985
  });
636
986
 
@@ -644,7 +994,7 @@ export default{
644
994
  id: "__test-name-workers_sites_assets-id",
645
995
  };
646
996
  writeWranglerToml({
647
- build: { upload: { main: "./index.js" } },
997
+ main: "./index.js",
648
998
  site: {
649
999
  bucket: "assets",
650
1000
  include: ["file-1.txt"],
@@ -664,17 +1014,13 @@ export default{
664
1014
  await runWrangler("publish");
665
1015
 
666
1016
  expect(std.out).toMatchInlineSnapshot(`
667
- "reading assets/file-1.txt...
668
- uploading as assets/file-1.2ca234f380.txt...
669
- Uploaded
670
- test-name
671
- (TIMINGS)
672
- Deployed
673
- test-name
674
- (TIMINGS)
675
-
676
- test-name.test-sub-domain.workers.dev"
677
- `);
1017
+ "reading assets/file-1.txt...
1018
+ uploading as assets/file-1.2ca234f380.txt...
1019
+ ↗️ Done syncing assets
1020
+ Uploaded test-name (TIMINGS)
1021
+ Published test-name (TIMINGS)
1022
+ test-name.test-sub-domain.workers.dev"
1023
+ `);
678
1024
  expect(std.err).toMatchInlineSnapshot(`""`);
679
1025
  });
680
1026
 
@@ -688,7 +1034,7 @@ export default{
688
1034
  id: "__test-name-workers_sites_assets-id",
689
1035
  };
690
1036
  writeWranglerToml({
691
- build: { upload: { main: "./index.js" } },
1037
+ main: "./index.js",
692
1038
  site: {
693
1039
  bucket: "assets",
694
1040
  exclude: ["file-2.txt"],
@@ -708,17 +1054,13 @@ export default{
708
1054
  await runWrangler("publish");
709
1055
 
710
1056
  expect(std.out).toMatchInlineSnapshot(`
711
- "reading assets/file-1.txt...
712
- uploading as assets/file-1.2ca234f380.txt...
713
- Uploaded
714
- test-name
715
- (TIMINGS)
716
- Deployed
717
- test-name
718
- (TIMINGS)
719
-
720
- test-name.test-sub-domain.workers.dev"
721
- `);
1057
+ "reading assets/file-1.txt...
1058
+ uploading as assets/file-1.2ca234f380.txt...
1059
+ ↗️ Done syncing assets
1060
+ Uploaded test-name (TIMINGS)
1061
+ Published test-name (TIMINGS)
1062
+ test-name.test-sub-domain.workers.dev"
1063
+ `);
722
1064
  expect(std.err).toMatchInlineSnapshot(`""`);
723
1065
  });
724
1066
 
@@ -732,7 +1074,7 @@ export default{
732
1074
  id: "__test-name-workers_sites_assets-id",
733
1075
  };
734
1076
  writeWranglerToml({
735
- build: { upload: { main: "./index.js" } },
1077
+ main: "./index.js",
736
1078
  site: {
737
1079
  bucket: "assets",
738
1080
  include: ["file-2.txt"],
@@ -752,17 +1094,13 @@ export default{
752
1094
  await runWrangler("publish --site-include file-1.txt");
753
1095
 
754
1096
  expect(std.out).toMatchInlineSnapshot(`
755
- "reading assets/file-1.txt...
756
- uploading as assets/file-1.2ca234f380.txt...
757
- Uploaded
758
- test-name
759
- (TIMINGS)
760
- Deployed
761
- test-name
762
- (TIMINGS)
763
-
764
- test-name.test-sub-domain.workers.dev"
765
- `);
1097
+ "reading assets/file-1.txt...
1098
+ uploading as assets/file-1.2ca234f380.txt...
1099
+ ↗️ Done syncing assets
1100
+ Uploaded test-name (TIMINGS)
1101
+ Published test-name (TIMINGS)
1102
+ test-name.test-sub-domain.workers.dev"
1103
+ `);
766
1104
  expect(std.err).toMatchInlineSnapshot(`""`);
767
1105
  });
768
1106
 
@@ -776,7 +1114,7 @@ export default{
776
1114
  id: "__test-name-workers_sites_assets-id",
777
1115
  };
778
1116
  writeWranglerToml({
779
- build: { upload: { main: "./index.js" } },
1117
+ main: "./index.js",
780
1118
  site: {
781
1119
  bucket: "assets",
782
1120
  exclude: ["assets/file-1.txt"],
@@ -796,17 +1134,13 @@ export default{
796
1134
  await runWrangler("publish --site-exclude file-2.txt");
797
1135
 
798
1136
  expect(std.out).toMatchInlineSnapshot(`
799
- "reading assets/file-1.txt...
800
- uploading as assets/file-1.2ca234f380.txt...
801
- Uploaded
802
- test-name
803
- (TIMINGS)
804
- Deployed
805
- test-name
806
- (TIMINGS)
807
-
808
- test-name.test-sub-domain.workers.dev"
809
- `);
1137
+ "reading assets/file-1.txt...
1138
+ uploading as assets/file-1.2ca234f380.txt...
1139
+ ↗️ Done syncing assets
1140
+ Uploaded test-name (TIMINGS)
1141
+ Published test-name (TIMINGS)
1142
+ test-name.test-sub-domain.workers.dev"
1143
+ `);
810
1144
  expect(std.err).toMatchInlineSnapshot(`""`);
811
1145
  });
812
1146
 
@@ -826,7 +1160,7 @@ export default{
826
1160
  id: "__test-name-workers_sites_assets-id",
827
1161
  };
828
1162
  writeWranglerToml({
829
- build: { upload: { main: "./index.js" } },
1163
+ main: "./index.js",
830
1164
  site: {
831
1165
  bucket: "assets",
832
1166
  },
@@ -844,14 +1178,10 @@ export default{
844
1178
  expect(std.out).toMatchInlineSnapshot(`
845
1179
  "reading assets/directory-1/file-1.txt...
846
1180
  uploading as assets/directory-1/file-1.2ca234f380.txt...
847
- Uploaded
848
- test-name
849
- (TIMINGS)
850
- Deployed
851
- test-name
852
- (TIMINGS)
853
-
854
- test-name.test-sub-domain.workers.dev"
1181
+ ↗️ Done syncing assets
1182
+ Uploaded test-name (TIMINGS)
1183
+ Published test-name (TIMINGS)
1184
+ test-name.test-sub-domain.workers.dev"
855
1185
  `);
856
1186
  expect(std.err).toMatchInlineSnapshot(`""`);
857
1187
  });
@@ -876,7 +1206,7 @@ export default{
876
1206
  id: "__test-name-workers_sites_assets-id",
877
1207
  };
878
1208
  writeWranglerToml({
879
- build: { upload: { main: "./index.js" } },
1209
+ main: "./index.js",
880
1210
  site: {
881
1211
  bucket: "assets",
882
1212
  },
@@ -894,14 +1224,10 @@ export default{
894
1224
  expect(std.out).toMatchInlineSnapshot(`
895
1225
  "reading assets/.well-known/file-2.txt...
896
1226
  uploading as assets/.well-known/file-2.5938485188.txt...
897
- Uploaded
898
- test-name
899
- (TIMINGS)
900
- Deployed
901
- test-name
902
- (TIMINGS)
903
-
904
- test-name.test-sub-domain.workers.dev"
1227
+ ↗️ Done syncing assets
1228
+ Uploaded test-name (TIMINGS)
1229
+ Published test-name (TIMINGS)
1230
+ test-name.test-sub-domain.workers.dev"
905
1231
  `);
906
1232
  expect(std.err).toMatchInlineSnapshot(`""`);
907
1233
  });
@@ -923,7 +1249,7 @@ export default{
923
1249
  id: "__test-name-workers_sites_assets-id",
924
1250
  };
925
1251
  writeWranglerToml({
926
- build: { upload: { main: "./index.js" } },
1252
+ main: "./index.js",
927
1253
  site: {
928
1254
  bucket: "assets",
929
1255
  exclude: ["assets/file-1.txt"],
@@ -949,8 +1275,7 @@ export default{
949
1275
  expect(std.err).toMatchInlineSnapshot(`
950
1276
  "File assets/too-large-file.txt is too big, it should be under 25 MiB. See https://developers.cloudflare.com/workers/platform/limits#kv-limits
951
1277
 
952
- %s
953
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
1278
+ %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
954
1279
  `);
955
1280
  });
956
1281
 
@@ -964,7 +1289,7 @@ export default{
964
1289
  id: "__test-name-workers_sites_assets-id",
965
1290
  };
966
1291
  writeWranglerToml({
967
- build: { upload: { main: "./index.js" } },
1292
+ main: "./index.js",
968
1293
  site: {
969
1294
  bucket: "assets",
970
1295
  },
@@ -988,205 +1313,2147 @@ export default{
988
1313
  expect(std.err).toMatchInlineSnapshot(`
989
1314
  "The asset path key \\"assets/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/file.3da0d0cd12.txt\\" exceeds the maximum key size limit of 512. See https://developers.cloudflare.com/workers/platform/limits#kv-limits\\",
990
1315
 
991
- %s
992
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
1316
+ %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
993
1317
  `);
994
1318
  });
995
- });
996
1319
 
997
- describe("custom builds", () => {
998
- it("should run a custom build before publishing", async () => {
1320
+ it("should delete uploaded assets that aren't included anymore", async () => {
1321
+ const assets = [
1322
+ { filePath: "assets/file-1.txt", content: "Content of file-1" },
1323
+ { filePath: "assets/file-2.txt", content: "Content of file-2" },
1324
+ ];
1325
+ const kvNamespace = {
1326
+ title: "__test-name-workers_sites_assets",
1327
+ id: "__test-name-workers_sites_assets-id",
1328
+ };
999
1329
  writeWranglerToml({
1000
- build: {
1001
- command: `node -e "console.log('custom build'); require('fs').writeFileSync('index.js', 'export default { fetch(){ return new Response(123) } }')"`,
1330
+ main: "./index.js",
1331
+ site: {
1332
+ bucket: "assets",
1002
1333
  },
1003
1334
  });
1335
+ writeWorkerSource();
1336
+ writeAssets(assets);
1337
+ mockUploadWorkerRequest();
1338
+ mockSubDomainRequest();
1339
+ mockListKVNamespacesRequest(kvNamespace);
1340
+ mockKeyListRequest(kvNamespace.id, [
1341
+ // Put file-1 in the KV namespace
1342
+ { name: "assets/file-1.2ca234f380.txt" },
1343
+ // As well as a couple from a previous upload
1344
+ { name: "assets/file-3.somehash.txt" },
1345
+ { name: "assets/file-4.anotherhash.txt" },
1346
+ ]);
1347
+
1348
+ // we upload only file-1.txt
1349
+ mockUploadAssetsToKVRequest(kvNamespace.id, [
1350
+ ...assets.filter((a) => a.filePath !== "assets/file-1.txt"),
1351
+ ]);
1352
+
1353
+ // and mark file-3 and file-4 for deletion
1354
+ mockDeleteUnusedAssetsRequest(kvNamespace.id, [
1355
+ "assets/file-3.somehash.txt",
1356
+ "assets/file-4.anotherhash.txt",
1357
+ ]);
1004
1358
 
1005
- mockUploadWorkerRequest({
1006
- expectedEntry: "return new Response(123)",
1359
+ await runWrangler("publish");
1360
+
1361
+ expect(std.out).toMatchInlineSnapshot(`
1362
+ "reading assets/file-1.txt...
1363
+ skipping - already uploaded
1364
+ reading assets/file-2.txt...
1365
+ uploading as assets/file-2.5938485188.txt...
1366
+ deleting assets/file-3.somehash.txt from the asset store...
1367
+ deleting assets/file-4.anotherhash.txt from the asset store...
1368
+ ↗️ Done syncing assets
1369
+ Uploaded test-name (TIMINGS)
1370
+ Published test-name (TIMINGS)
1371
+ test-name.test-sub-domain.workers.dev"
1372
+ `);
1373
+ expect(std.err).toMatchInlineSnapshot(`""`);
1374
+ });
1375
+ });
1376
+
1377
+ describe("workers_dev setting", () => {
1378
+ it("should publish to a workers.dev domain if workers_dev is undefined", async () => {
1379
+ writeWranglerToml();
1380
+ writeWorkerSource();
1381
+ mockUploadWorkerRequest();
1382
+ mockSubDomainRequest();
1383
+
1384
+ await runWrangler("publish ./index");
1385
+
1386
+ expect(std.out).toMatchInlineSnapshot(`
1387
+ "Uploaded test-name (TIMINGS)
1388
+ Published test-name (TIMINGS)
1389
+ test-name.test-sub-domain.workers.dev"
1390
+ `);
1391
+ expect(std.err).toMatchInlineSnapshot(`""`);
1392
+ });
1393
+
1394
+ it("should publish to the workers.dev domain if workers_dev is `true`", async () => {
1395
+ writeWranglerToml({
1396
+ workers_dev: true,
1007
1397
  });
1398
+ writeWorkerSource();
1399
+ mockUploadWorkerRequest();
1008
1400
  mockSubDomainRequest();
1009
1401
 
1010
- await runWrangler("publish index.js");
1402
+ await runWrangler("publish ./index");
1403
+
1011
1404
  expect(std.out).toMatchInlineSnapshot(`
1012
- "running:
1013
- node -e \\"console.log('custom build'); require('fs').writeFileSync('index.js', 'export default { fetch(){ return new Response(123) } }')\\"
1014
- Uploaded
1015
- test-name
1016
- (TIMINGS)
1017
- Deployed
1018
- test-name
1019
- (TIMINGS)
1020
-
1021
- test-name.test-sub-domain.workers.dev"
1405
+ "Uploaded test-name (TIMINGS)
1406
+ Published test-name (TIMINGS)
1407
+ test-name.test-sub-domain.workers.dev"
1022
1408
  `);
1023
1409
  expect(std.err).toMatchInlineSnapshot(`""`);
1024
- expect(std.warn).toMatchInlineSnapshot(`""`);
1025
1410
  });
1026
1411
 
1027
- if (process.platform !== "win32") {
1028
- it("should run a custom build of multiple steps combined by && before publishing", async () => {
1029
- writeWranglerToml({
1030
- build: {
1031
- command: `echo "custom build" && echo "export default { fetch(){ return new Response(123) } }" > index.js`,
1412
+ it("should disable the workers.dev domain if workers_dev is `false`", async () => {
1413
+ writeWranglerToml({
1414
+ workers_dev: false,
1415
+ });
1416
+ writeWorkerSource();
1417
+ mockUploadWorkerRequest();
1418
+ mockUpdateWorkerRequest({ enabled: false });
1419
+
1420
+ await runWrangler("publish ./index");
1421
+
1422
+ expect(std.out).toMatchInlineSnapshot(`
1423
+ "Uploaded test-name (TIMINGS)
1424
+ No publish targets for test-name (TIMINGS)"
1425
+ `);
1426
+ expect(std.err).toMatchInlineSnapshot(`""`);
1427
+ });
1428
+
1429
+ it("should disable the workers.dev domain if workers_dev is undefined but overwritten to `false` in environment", async () => {
1430
+ writeWranglerToml({
1431
+ env: {
1432
+ dev: {
1433
+ workers_dev: false,
1032
1434
  },
1033
- });
1435
+ },
1436
+ });
1437
+ writeWorkerSource();
1438
+ mockUploadWorkerRequest({
1439
+ env: "dev",
1440
+ });
1441
+ mockUpdateWorkerRequest({ enabled: false, env: "dev" });
1034
1442
 
1035
- mockUploadWorkerRequest({
1036
- expectedEntry: "return new Response(123)",
1037
- });
1038
- mockSubDomainRequest();
1443
+ await runWrangler("publish ./index --env dev --legacy-env false");
1039
1444
 
1040
- await runWrangler("publish index.js");
1041
- expect(std.out).toMatchInlineSnapshot(`
1042
- "running:
1043
- echo \\"custom build\\" && echo \\"export default { fetch(){ return new Response(123) } }\\" > index.js
1044
- Uploaded
1045
- test-name
1046
- (TIMINGS)
1047
- Deployed
1048
- test-name
1049
- (TIMINGS)
1050
-
1051
- test-name.test-sub-domain.workers.dev"
1052
- `);
1053
- expect(std.err).toMatchInlineSnapshot(`""`);
1054
- expect(std.warn).toMatchInlineSnapshot(`""`);
1445
+ expect(std.out).toMatchInlineSnapshot(`
1446
+ "Uploaded test-name (dev) (TIMINGS)
1447
+ No publish targets for test-name (dev) (TIMINGS)"
1448
+ `);
1449
+ expect(std.err).toMatchInlineSnapshot(`""`);
1450
+ });
1451
+
1452
+ it("should disable the workers.dev domain if workers_dev is `true` but overwritten to `false` in environment", async () => {
1453
+ writeWranglerToml({
1454
+ workers_dev: true,
1455
+ env: {
1456
+ dev: {
1457
+ workers_dev: false,
1458
+ },
1459
+ },
1055
1460
  });
1056
- }
1057
- });
1058
- });
1461
+ writeWorkerSource();
1462
+ mockUploadWorkerRequest({
1463
+ env: "dev",
1464
+ });
1465
+ mockUpdateWorkerRequest({ enabled: false, env: "dev" });
1059
1466
 
1060
- /** Write a mock wrangler.toml file to disk. */
1061
- function writeWranglerToml(config: Omit<Config, "env"> = {}) {
1062
- // We Omit `env` from config because TOML.stringify() appears to
1063
- // have a weird type signature that appears to fail. We'll revisit this
1064
- // when we write tests for publishing environments
1065
- fs.writeFileSync(
1066
- "./wrangler.toml",
1067
- TOML.stringify({
1068
- compatibility_date: "2022-01-12",
1069
- name: "test-name",
1070
- ...config,
1071
- }),
1072
-
1073
- "utf-8"
1074
- );
1075
- }
1467
+ await runWrangler("publish ./index --env dev --legacy-env false");
1076
1468
 
1077
- /** Write a mock Worker script to disk. */
1078
- function writeWorkerSource({
1079
- basePath = ".",
1080
- format = "js",
1081
- type = "esm",
1082
- }: {
1083
- basePath?: string;
1084
- format?: "js" | "ts" | "jsx" | "tsx" | "mjs";
1085
- type?: "esm" | "sw";
1086
- } = {}) {
1087
- if (basePath !== ".") {
1088
- fs.mkdirSync(basePath, { recursive: true });
1089
- }
1090
- fs.writeFileSync(
1091
- `${basePath}/index.${format}`,
1092
- type === "esm"
1093
- ? `import { foo } from "./another";
1094
- export default {
1095
- async fetch(request) {
1096
- return new Response('Hello' + foo);
1469
+ expect(std.out).toMatchInlineSnapshot(`
1470
+ "Uploaded test-name (dev) (TIMINGS)
1471
+ No publish targets for test-name (dev) (TIMINGS)"
1472
+ `);
1473
+ expect(std.err).toMatchInlineSnapshot(`""`);
1474
+ });
1475
+
1476
+ it("should publish to a workers.dev domain if workers_dev is undefined but overwritten to `true` in environment", async () => {
1477
+ writeWranglerToml({
1478
+ env: {
1479
+ dev: {
1480
+ workers_dev: true,
1481
+ },
1097
1482
  },
1098
- };`
1099
- : `import { foo } from "./another";
1100
- addEventListener('fetch', event => {
1101
- event.respondWith(new Response('Hello' + foo));
1102
- })`
1103
- );
1104
- fs.writeFileSync(`${basePath}/another.${format}`, `export const foo = 100;`);
1105
- }
1483
+ });
1484
+ writeWorkerSource();
1485
+ mockUploadWorkerRequest({
1486
+ env: "dev",
1487
+ });
1488
+ mockSubDomainRequest();
1489
+ mockUpdateWorkerRequest({ enabled: true, env: "dev" });
1106
1490
 
1107
- /** Write mock assets to the file system so they can be uploaded. */
1108
- function writeAssets(assets: { filePath: string; content: string }[]) {
1109
- for (const asset of assets) {
1110
- fs.mkdirSync(path.dirname(asset.filePath), { recursive: true });
1111
- fs.writeFileSync(asset.filePath, asset.content);
1112
- }
1113
- }
1491
+ await runWrangler("publish ./index --env dev --legacy-env false");
1114
1492
 
1115
- /** Create a mock handler for the request to upload a worker script. */
1116
- function mockUploadWorkerRequest({
1117
- available_on_subdomain = true,
1118
- expectedEntry,
1119
- expectedType = "esm",
1120
- expectedBindings,
1121
- expectedModules = {},
1122
- env = undefined,
1123
- }: {
1124
- available_on_subdomain?: boolean;
1125
- expectedEntry?: string;
1126
- expectedType?: "esm" | "sw";
1127
- expectedBindings?: unknown;
1128
- expectedModules?: Record<string, string>;
1129
- env?: string | undefined;
1130
- } = {}) {
1131
- setMockResponse(
1132
- env
1133
- ? `/accounts/:accountId/workers/services/:scriptName/environments/:envName`
1134
- : "/accounts/:accountId/workers/scripts/:scriptName",
1135
- "PUT",
1136
- async ([_url, accountId, scriptName], { body }, queryParams) => {
1137
- expect(accountId).toEqual("some-account-id");
1138
- expect(scriptName).toEqual("test-name");
1139
- expect(queryParams.get("available_on_subdomains")).toEqual("true");
1140
- const formBody = body as FormData;
1141
- if (expectedEntry !== undefined) {
1142
- expect(await (formBody.get("index.js") as File).text()).toMatch(
1143
- expectedEntry
1144
- );
1145
- }
1493
+ expect(std.out).toMatchInlineSnapshot(`
1494
+ "Uploaded test-name (dev) (TIMINGS)
1495
+ Published test-name (dev) (TIMINGS)
1496
+ dev.test-name.test-sub-domain.workers.dev"
1497
+ `);
1498
+ expect(std.err).toMatchInlineSnapshot(`""`);
1499
+ });
1146
1500
 
1147
- const metadata = JSON.parse(
1148
- formBody.get("metadata") as string
1149
- ) as WorkerMetadata;
1150
- if (expectedType === "esm") {
1151
- expect(metadata.main_module).toEqual("index.js");
1152
- } else {
1153
- expect(metadata.body_part).toEqual("index.js");
1154
- }
1155
- if (expectedBindings !== undefined) {
1156
- expect(metadata.bindings).toEqual(expectedBindings);
1157
- }
1158
- for (const [name, content] of Object.entries(expectedModules)) {
1159
- expect(await (formBody.get(name) as File).text()).toMatch(content);
1160
- }
1501
+ it("should publish to a workers.dev domain if workers_dev is `false` but overwritten to `true` in environment", async () => {
1502
+ writeWranglerToml({
1503
+ workers_dev: false,
1504
+ env: {
1505
+ dev: {
1506
+ workers_dev: true,
1507
+ },
1508
+ },
1509
+ });
1510
+ writeWorkerSource();
1511
+ mockUploadWorkerRequest({
1512
+ env: "dev",
1513
+ });
1514
+ mockSubDomainRequest();
1515
+ mockUpdateWorkerRequest({ enabled: true, env: "dev" });
1161
1516
 
1162
- return { available_on_subdomain };
1163
- }
1164
- );
1165
- }
1517
+ await runWrangler("publish ./index --env dev --legacy-env false");
1166
1518
 
1167
- /** Create a mock handler for the request to get the account's subdomain. */
1168
- function mockSubDomainRequest(subdomain = "test-sub-domain") {
1169
- setMockResponse("/accounts/:accountId/workers/subdomain", () => {
1170
- return { subdomain };
1171
- });
1172
- }
1519
+ expect(std.out).toMatchInlineSnapshot(`
1520
+ "Uploaded test-name (dev) (TIMINGS)
1521
+ Published test-name (dev) (TIMINGS)
1522
+ dev.test-name.test-sub-domain.workers.dev"
1523
+ `);
1524
+ expect(std.err).toMatchInlineSnapshot(`""`);
1525
+ });
1173
1526
 
1174
- /** Create a mock handler for the request to get a list of all KV namespaces. */
1175
- function mockListKVNamespacesRequest(...namespaces: KVNamespaceInfo[]) {
1176
- setMockResponse(
1177
- "/accounts/:accountId/storage/kv/namespaces",
1178
- "GET",
1179
- ([_url, accountId]) => {
1180
- expect(accountId).toEqual("some-account-id");
1181
- return namespaces;
1182
- }
1183
- );
1184
- }
1527
+ it("should use the global compatibility_date and compatibility_flags if they are not overwritten by the environment", async () => {
1528
+ writeWranglerToml({
1529
+ compatibility_date: "2022-01-12",
1530
+ compatibility_flags: ["no_global_navigator"],
1531
+ env: {
1532
+ dev: {},
1533
+ },
1534
+ });
1535
+ writeWorkerSource();
1536
+ mockUploadWorkerRequest({
1537
+ env: "dev",
1538
+ expectedCompatibilityDate: "2022-01-12",
1539
+ expectedCompatibilityFlags: ["no_global_navigator"],
1540
+ });
1541
+ mockSubDomainRequest();
1542
+ mockUpdateWorkerRequest({ enabled: true, env: "dev" });
1185
1543
 
1186
- /** Create a mock handler for the request that tries to do a bulk upload of assets to a KV namespace. */
1544
+ await runWrangler("publish ./index --env dev --legacy-env false");
1545
+
1546
+ expect(std.out).toMatchInlineSnapshot(`
1547
+ "Uploaded test-name (dev) (TIMINGS)
1548
+ Published test-name (dev) (TIMINGS)
1549
+ dev.test-name.test-sub-domain.workers.dev"
1550
+ `);
1551
+ expect(std.err).toMatchInlineSnapshot(`""`);
1552
+ });
1553
+
1554
+ it("should use the environment specific compatibility_date and compatibility_flags", async () => {
1555
+ writeWranglerToml({
1556
+ compatibility_date: "2022-01-12",
1557
+ compatibility_flags: ["no_global_navigator"],
1558
+ env: {
1559
+ dev: {
1560
+ compatibility_date: "2022-01-13",
1561
+ compatibility_flags: ["global_navigator"],
1562
+ },
1563
+ },
1564
+ });
1565
+ writeWorkerSource();
1566
+ mockUploadWorkerRequest({
1567
+ env: "dev",
1568
+ expectedCompatibilityDate: "2022-01-13",
1569
+ expectedCompatibilityFlags: ["global_navigator"],
1570
+ });
1571
+ mockSubDomainRequest();
1572
+ mockUpdateWorkerRequest({ enabled: true, env: "dev" });
1573
+
1574
+ await runWrangler("publish ./index --env dev --legacy-env false");
1575
+
1576
+ expect(std.out).toMatchInlineSnapshot(`
1577
+ "Uploaded test-name (dev) (TIMINGS)
1578
+ Published test-name (dev) (TIMINGS)
1579
+ dev.test-name.test-sub-domain.workers.dev"
1580
+ `);
1581
+ expect(std.err).toMatchInlineSnapshot(`""`);
1582
+ });
1583
+
1584
+ it("should use the command line --compatibility-date and --compatibility-flags if they are specified", async () => {
1585
+ writeWranglerToml({
1586
+ compatibility_date: "2022-01-12",
1587
+ compatibility_flags: ["no_global_navigator"],
1588
+ env: {
1589
+ dev: {
1590
+ compatibility_date: "2022-01-13",
1591
+ compatibility_flags: ["global_navigator"],
1592
+ },
1593
+ },
1594
+ });
1595
+ writeWorkerSource();
1596
+ mockUploadWorkerRequest({
1597
+ env: "dev",
1598
+ expectedCompatibilityDate: "2022-01-14",
1599
+ expectedCompatibilityFlags: ["url_standard"],
1600
+ });
1601
+ mockSubDomainRequest();
1602
+ mockUpdateWorkerRequest({ enabled: true, env: "dev" });
1603
+
1604
+ await runWrangler(
1605
+ "publish ./index --env dev --legacy-env false --compatibility-date 2022-01-14 --compatibility-flags url_standard"
1606
+ );
1607
+
1608
+ expect(std.out).toMatchInlineSnapshot(`
1609
+ "Uploaded test-name (dev) (TIMINGS)
1610
+ Published test-name (dev) (TIMINGS)
1611
+ dev.test-name.test-sub-domain.workers.dev"
1612
+ `);
1613
+ expect(std.err).toMatchInlineSnapshot(`""`);
1614
+ });
1615
+
1616
+ it("should enable the workers.dev domain if workers_dev is undefined and subdomain is not already available", async () => {
1617
+ writeWranglerToml();
1618
+ writeWorkerSource();
1619
+ mockUploadWorkerRequest({ available_on_subdomain: false });
1620
+ mockSubDomainRequest();
1621
+ mockUpdateWorkerRequest({ enabled: true });
1622
+
1623
+ await runWrangler("publish ./index");
1624
+
1625
+ expect(std.out).toMatchInlineSnapshot(`
1626
+ "Uploaded test-name (TIMINGS)
1627
+ Published test-name (TIMINGS)
1628
+ test-name.test-sub-domain.workers.dev"
1629
+ `);
1630
+ expect(std.err).toMatchInlineSnapshot(`""`);
1631
+ });
1632
+
1633
+ it("should enable the workers.dev domain if workers_dev is true and subdomain is not already available", async () => {
1634
+ writeWranglerToml({ workers_dev: true });
1635
+ writeWorkerSource();
1636
+ mockUploadWorkerRequest({ available_on_subdomain: false });
1637
+ mockSubDomainRequest();
1638
+ mockUpdateWorkerRequest({ enabled: true });
1639
+
1640
+ await runWrangler("publish ./index");
1641
+
1642
+ expect(std.out).toMatchInlineSnapshot(`
1643
+ "Uploaded test-name (TIMINGS)
1644
+ Published test-name (TIMINGS)
1645
+ test-name.test-sub-domain.workers.dev"
1646
+ `);
1647
+ expect(std.err).toMatchInlineSnapshot(`""`);
1648
+ });
1649
+
1650
+ it("should error politely when publishing to workers_dev when there is no workers.dev subdomain", async () => {
1651
+ writeWranglerToml({
1652
+ workers_dev: true,
1653
+ });
1654
+ writeWorkerSource();
1655
+ mockUploadWorkerRequest();
1656
+ mockSubDomainRequest("does-not-exist", false);
1657
+
1658
+ await expect(runWrangler("publish ./index")).rejects
1659
+ .toThrowErrorMatchingInlineSnapshot(`
1660
+ "Error: You need to register a workers.dev subdomain before publishing to workers.dev
1661
+ You can either publish your worker to one or more routes by specifying them in wrangler.toml, or register a workers.dev subdomain here:
1662
+ https://dash.cloudflare.com/some-account-id/workers/onboarding"
1663
+ `);
1664
+ });
1665
+
1666
+ it("should not deploy to workers.dev if there are any routes defined", async () => {
1667
+ writeWranglerToml({
1668
+ routes: ["http://example.com/*"],
1669
+ });
1670
+ writeWorkerSource();
1671
+ mockSubDomainRequest();
1672
+ mockUploadWorkerRequest();
1673
+ mockUpdateWorkerRequest({
1674
+ enabled: false,
1675
+ });
1676
+ mockPublishRoutesRequest({ routes: ["http://example.com/*"] });
1677
+ await runWrangler("publish index.js");
1678
+
1679
+ expect(std.out).toMatchInlineSnapshot(`
1680
+ "Uploaded test-name (TIMINGS)
1681
+ Published test-name (TIMINGS)
1682
+ http://example.com/*"
1683
+ `);
1684
+ expect(std.err).toMatchInlineSnapshot(`""`);
1685
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1686
+ });
1687
+
1688
+ it("should not deploy to workers.dev if there are any routes defined (environments)", async () => {
1689
+ writeWranglerToml({
1690
+ routes: ["http://example.com/*"],
1691
+ env: {
1692
+ production: {
1693
+ routes: ["http://production.example.com/*"],
1694
+ },
1695
+ },
1696
+ });
1697
+ writeWorkerSource();
1698
+ mockSubDomainRequest();
1699
+ mockUploadWorkerRequest({ env: "production", legacyEnv: true });
1700
+ mockUpdateWorkerRequest({
1701
+ enabled: false,
1702
+ env: "production",
1703
+ legacyEnv: true,
1704
+ });
1705
+ mockPublishRoutesRequest({
1706
+ routes: ["http://production.example.com/*"],
1707
+ env: "production",
1708
+ legacyEnv: true,
1709
+ });
1710
+ await runWrangler("publish index.js --env production");
1711
+
1712
+ expect(std.out).toMatchInlineSnapshot(`
1713
+ "Uploaded test-name-production (TIMINGS)
1714
+ Published test-name-production (TIMINGS)
1715
+ http://production.example.com/*"
1716
+ `);
1717
+ expect(std.err).toMatchInlineSnapshot(`""`);
1718
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1719
+ });
1720
+
1721
+ it("should not deploy to workers.dev if there are any routes defined (only in environments)", async () => {
1722
+ writeWranglerToml({
1723
+ env: {
1724
+ production: {
1725
+ routes: ["http://production.example.com/*"],
1726
+ },
1727
+ },
1728
+ });
1729
+ writeWorkerSource();
1730
+ mockSubDomainRequest();
1731
+ mockUploadWorkerRequest({ env: "production", legacyEnv: true });
1732
+ mockUpdateWorkerRequest({
1733
+ enabled: false,
1734
+ env: "production",
1735
+ legacyEnv: true,
1736
+ });
1737
+ mockPublishRoutesRequest({
1738
+ routes: ["http://production.example.com/*"],
1739
+ env: "production",
1740
+ legacyEnv: true,
1741
+ });
1742
+ await runWrangler("publish index.js --env production");
1743
+
1744
+ expect(std.out).toMatchInlineSnapshot(`
1745
+ "Uploaded test-name-production (TIMINGS)
1746
+ Published test-name-production (TIMINGS)
1747
+ http://production.example.com/*"
1748
+ `);
1749
+ expect(std.err).toMatchInlineSnapshot(`""`);
1750
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1751
+ });
1752
+
1753
+ it("can deploy to both workers.dev and routes if both defined ", async () => {
1754
+ writeWranglerToml({
1755
+ workers_dev: true,
1756
+ routes: ["http://example.com/*"],
1757
+ });
1758
+ writeWorkerSource();
1759
+ mockSubDomainRequest();
1760
+ mockUploadWorkerRequest();
1761
+ mockUpdateWorkerRequest({
1762
+ enabled: false,
1763
+ });
1764
+ mockPublishRoutesRequest({
1765
+ routes: ["http://example.com/*"],
1766
+ });
1767
+ await runWrangler("publish index.js");
1768
+
1769
+ expect(std.out).toMatchInlineSnapshot(`
1770
+ "Uploaded test-name (TIMINGS)
1771
+ Published test-name (TIMINGS)
1772
+ test-name.test-sub-domain.workers.dev
1773
+ http://example.com/*"
1774
+ `);
1775
+ expect(std.err).toMatchInlineSnapshot(`""`);
1776
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1777
+ });
1778
+
1779
+ it("can deploy to both workers.dev and routes if both defined (environments: 1)", async () => {
1780
+ writeWranglerToml({
1781
+ workers_dev: true,
1782
+ env: {
1783
+ production: {
1784
+ routes: ["http://production.example.com/*"],
1785
+ },
1786
+ },
1787
+ });
1788
+ writeWorkerSource();
1789
+ mockSubDomainRequest();
1790
+ mockUploadWorkerRequest({ env: "production", legacyEnv: true });
1791
+ mockUpdateWorkerRequest({
1792
+ enabled: false,
1793
+ env: "production",
1794
+ legacyEnv: true,
1795
+ });
1796
+ mockPublishRoutesRequest({
1797
+ routes: ["http://production.example.com/*"],
1798
+ env: "production",
1799
+ legacyEnv: true,
1800
+ });
1801
+ await runWrangler("publish index.js --env production");
1802
+
1803
+ expect(std.out).toMatchInlineSnapshot(`
1804
+ "Uploaded test-name-production (TIMINGS)
1805
+ Published test-name-production (TIMINGS)
1806
+ test-name-production.test-sub-domain.workers.dev
1807
+ http://production.example.com/*"
1808
+ `);
1809
+ expect(std.err).toMatchInlineSnapshot(`""`);
1810
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1811
+ });
1812
+
1813
+ it("can deploy to both workers.dev and routes if both defined (environments: 2)", async () => {
1814
+ writeWranglerToml({
1815
+ env: {
1816
+ production: {
1817
+ workers_dev: true,
1818
+ routes: ["http://production.example.com/*"],
1819
+ },
1820
+ },
1821
+ });
1822
+ writeWorkerSource();
1823
+ mockSubDomainRequest();
1824
+ mockUploadWorkerRequest({ env: "production", legacyEnv: true });
1825
+ mockUpdateWorkerRequest({
1826
+ enabled: false,
1827
+ env: "production",
1828
+ legacyEnv: true,
1829
+ });
1830
+ mockPublishRoutesRequest({
1831
+ routes: ["http://production.example.com/*"],
1832
+ env: "production",
1833
+ legacyEnv: true,
1834
+ });
1835
+ await runWrangler("publish index.js --env production");
1836
+
1837
+ expect(std.out).toMatchInlineSnapshot(`
1838
+ "Uploaded test-name-production (TIMINGS)
1839
+ Published test-name-production (TIMINGS)
1840
+ test-name-production.test-sub-domain.workers.dev
1841
+ http://production.example.com/*"
1842
+ `);
1843
+ expect(std.err).toMatchInlineSnapshot(`""`);
1844
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1845
+ });
1846
+
1847
+ it("will deploy only to routes when workers_dev is false (environments 1) ", async () => {
1848
+ writeWranglerToml({
1849
+ workers_dev: false,
1850
+ env: {
1851
+ production: {
1852
+ routes: ["http://production.example.com/*"],
1853
+ },
1854
+ },
1855
+ });
1856
+ writeWorkerSource();
1857
+ mockSubDomainRequest();
1858
+ mockUploadWorkerRequest({ env: "production", legacyEnv: true });
1859
+ mockUpdateWorkerRequest({
1860
+ enabled: false,
1861
+ env: "production",
1862
+ legacyEnv: true,
1863
+ });
1864
+ mockPublishRoutesRequest({
1865
+ routes: ["http://production.example.com/*"],
1866
+ env: "production",
1867
+ legacyEnv: true,
1868
+ });
1869
+ await runWrangler("publish index.js --env production");
1870
+
1871
+ expect(std.out).toMatchInlineSnapshot(`
1872
+ "Uploaded test-name-production (TIMINGS)
1873
+ Published test-name-production (TIMINGS)
1874
+ http://production.example.com/*"
1875
+ `);
1876
+ expect(std.err).toMatchInlineSnapshot(`""`);
1877
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1878
+ });
1879
+
1880
+ it("will deploy only to routes when workers_dev is false (environments 2) ", async () => {
1881
+ writeWranglerToml({
1882
+ env: {
1883
+ production: {
1884
+ workers_dev: false,
1885
+ routes: ["http://production.example.com/*"],
1886
+ },
1887
+ },
1888
+ });
1889
+ writeWorkerSource();
1890
+ mockSubDomainRequest();
1891
+ mockUploadWorkerRequest({ env: "production", legacyEnv: true });
1892
+ mockUpdateWorkerRequest({
1893
+ enabled: false,
1894
+ env: "production",
1895
+ legacyEnv: true,
1896
+ });
1897
+ mockPublishRoutesRequest({
1898
+ routes: ["http://production.example.com/*"],
1899
+ env: "production",
1900
+ legacyEnv: true,
1901
+ });
1902
+ await runWrangler("publish index.js --env production");
1903
+
1904
+ expect(std.out).toMatchInlineSnapshot(`
1905
+ "Uploaded test-name-production (TIMINGS)
1906
+ Published test-name-production (TIMINGS)
1907
+ http://production.example.com/*"
1908
+ `);
1909
+ expect(std.err).toMatchInlineSnapshot(`""`);
1910
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1911
+ });
1912
+ });
1913
+
1914
+ describe("custom builds", () => {
1915
+ beforeEach(() => {
1916
+ // @ts-expect-error disable the mock we'd setup earlier
1917
+ // or else custom builds will timeout immediately
1918
+ global.setTimeout.mockRestore();
1919
+ });
1920
+ it("should run a custom build before publishing", async () => {
1921
+ writeWranglerToml({
1922
+ build: {
1923
+ command: `node -e "console.log('custom build'); require('fs').writeFileSync('index.js', 'export default { fetch(){ return new Response(123) } }')"`,
1924
+ },
1925
+ });
1926
+
1927
+ mockUploadWorkerRequest({
1928
+ expectedEntry: "return new Response(123)",
1929
+ });
1930
+ mockSubDomainRequest();
1931
+
1932
+ await runWrangler("publish index.js");
1933
+ expect(std.out).toMatchInlineSnapshot(`
1934
+ "running: node -e \\"console.log('custom build'); require('fs').writeFileSync('index.js', 'export default { fetch(){ return new Response(123) } }')\\"
1935
+ Uploaded test-name (TIMINGS)
1936
+ Published test-name (TIMINGS)
1937
+ test-name.test-sub-domain.workers.dev"
1938
+ `);
1939
+ expect(std.err).toMatchInlineSnapshot(`""`);
1940
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1941
+ });
1942
+
1943
+ if (process.platform !== "win32") {
1944
+ it("should run a custom build of multiple steps combined by && before publishing", async () => {
1945
+ writeWranglerToml({
1946
+ build: {
1947
+ command: `echo "custom build" && echo "export default { fetch(){ return new Response(123) } }" > index.js`,
1948
+ },
1949
+ });
1950
+
1951
+ mockUploadWorkerRequest({
1952
+ expectedEntry: "return new Response(123)",
1953
+ });
1954
+ mockSubDomainRequest();
1955
+
1956
+ await runWrangler("publish index.js");
1957
+ expect(std.out).toMatchInlineSnapshot(`
1958
+ "running: echo \\"custom build\\" && echo \\"export default { fetch(){ return new Response(123) } }\\" > index.js
1959
+ Uploaded test-name (TIMINGS)
1960
+ Published test-name (TIMINGS)
1961
+ test-name.test-sub-domain.workers.dev"
1962
+ `);
1963
+ expect(std.err).toMatchInlineSnapshot(`""`);
1964
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1965
+ });
1966
+ }
1967
+
1968
+ it("should throw an error if the entry doesn't exist after the build finishes", async () => {
1969
+ writeWranglerToml({
1970
+ main: "index.js",
1971
+ build: {
1972
+ command: `node -e "console.log('custom build');"`,
1973
+ },
1974
+ });
1975
+
1976
+ await expect(
1977
+ runWrangler("publish index.js")
1978
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
1979
+ `"Could not resolve \\"index.js\\" after running custom build: node -e \\"console.log('custom build');\\""`
1980
+ );
1981
+ expect(std.out).toMatchInlineSnapshot(
1982
+ `"running: node -e \\"console.log('custom build');\\""`
1983
+ );
1984
+ expect(std.err).toMatchInlineSnapshot(`
1985
+ "Could not resolve \\"index.js\\" after running custom build: node -e \\"console.log('custom build');\\"
1986
+
1987
+ %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
1988
+ `);
1989
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1990
+ });
1991
+ });
1992
+
1993
+ describe("bindings", () => {
1994
+ it("should allow bindings with different names", async () => {
1995
+ writeWranglerToml({
1996
+ durable_objects: {
1997
+ bindings: [
1998
+ {
1999
+ name: "DURABLE_OBJECT_ONE",
2000
+ class_name: "SomeDurableObject",
2001
+ script_name: "some-durable-object-worker",
2002
+ },
2003
+ {
2004
+ name: "DURABLE_OBJECT_TWO",
2005
+ class_name: "AnotherDurableObject",
2006
+ script_name: "another-durable-object-worker",
2007
+ },
2008
+ ],
2009
+ },
2010
+ kv_namespaces: [
2011
+ { binding: "KV_NAMESPACE_ONE", id: "kv-ns-one-id" },
2012
+ { binding: "KV_NAMESPACE_TWO", id: "kv-ns-two-id" },
2013
+ ],
2014
+ r2_buckets: [
2015
+ { binding: "R2_BUCKET_ONE", bucket_name: "r2-bucket-one-name" },
2016
+ { binding: "R2_BUCKET_TWO", bucket_name: "r2-bucket-two-name" },
2017
+ ],
2018
+ text_blobs: {
2019
+ TEXT_BLOB_ONE: "./my-entire-app-depends-on-this.cfg",
2020
+ TEXT_BLOB_TWO: "./the-entirety-of-human-knowledge.txt",
2021
+ },
2022
+ unsafe: {
2023
+ bindings: [
2024
+ {
2025
+ name: "UNSAFE_BINDING_ONE",
2026
+ type: "some unsafe thing",
2027
+ data: { some: { unsafe: "thing" } },
2028
+ },
2029
+ {
2030
+ name: "UNSAFE_BINDING_TWO",
2031
+ type: "another unsafe thing",
2032
+ data: 1337,
2033
+ },
2034
+ ],
2035
+ },
2036
+ vars: {
2037
+ ENV_VAR_ONE: 123,
2038
+ ENV_VAR_TWO: "Hello, I'm an environment variable",
2039
+ },
2040
+ wasm_modules: {
2041
+ WASM_MODULE_ONE: "./some_wasm.wasm",
2042
+ WASM_MODULE_TWO: "./more_wasm.wasm",
2043
+ },
2044
+ });
2045
+
2046
+ writeWorkerSource({ type: "sw" });
2047
+ fs.writeFileSync("./my-entire-app-depends-on-this.cfg", "config = value");
2048
+ fs.writeFileSync(
2049
+ "./the-entirety-of-human-knowledge.txt",
2050
+ "Everything's bigger in Texas"
2051
+ );
2052
+ fs.writeFileSync("./some_wasm.wasm", "some wasm");
2053
+ fs.writeFileSync("./more_wasm.wasm", "more wasm");
2054
+
2055
+ mockUploadWorkerRequest({
2056
+ expectedType: "sw",
2057
+ expectedBindings: [
2058
+ {
2059
+ name: "KV_NAMESPACE_ONE",
2060
+ namespace_id: "kv-ns-one-id",
2061
+ type: "kv_namespace",
2062
+ },
2063
+ {
2064
+ name: "KV_NAMESPACE_TWO",
2065
+ namespace_id: "kv-ns-two-id",
2066
+ type: "kv_namespace",
2067
+ },
2068
+ {
2069
+ class_name: "SomeDurableObject",
2070
+ name: "DURABLE_OBJECT_ONE",
2071
+ script_name: "some-durable-object-worker",
2072
+ type: "durable_object_namespace",
2073
+ },
2074
+ {
2075
+ class_name: "AnotherDurableObject",
2076
+ name: "DURABLE_OBJECT_TWO",
2077
+ script_name: "another-durable-object-worker",
2078
+ type: "durable_object_namespace",
2079
+ },
2080
+ {
2081
+ bucket_name: "r2-bucket-one-name",
2082
+ name: "R2_BUCKET_ONE",
2083
+ type: "r2_bucket",
2084
+ },
2085
+ {
2086
+ bucket_name: "r2-bucket-two-name",
2087
+ name: "R2_BUCKET_TWO",
2088
+ type: "r2_bucket",
2089
+ },
2090
+ { json: 123, name: "ENV_VAR_ONE", type: "json" },
2091
+ {
2092
+ name: "ENV_VAR_TWO",
2093
+ text: "Hello, I'm an environment variable",
2094
+ type: "plain_text",
2095
+ },
2096
+ {
2097
+ name: "WASM_MODULE_ONE",
2098
+ part: "WASM_MODULE_ONE",
2099
+ type: "wasm_module",
2100
+ },
2101
+ {
2102
+ name: "WASM_MODULE_TWO",
2103
+ part: "WASM_MODULE_TWO",
2104
+ type: "wasm_module",
2105
+ },
2106
+ { name: "TEXT_BLOB_ONE", part: "TEXT_BLOB_ONE", type: "text_blob" },
2107
+ { name: "TEXT_BLOB_TWO", part: "TEXT_BLOB_TWO", type: "text_blob" },
2108
+ {
2109
+ data: { some: { unsafe: "thing" } },
2110
+ name: "UNSAFE_BINDING_ONE",
2111
+ type: "some unsafe thing",
2112
+ },
2113
+ {
2114
+ data: 1337,
2115
+ name: "UNSAFE_BINDING_TWO",
2116
+ type: "another unsafe thing",
2117
+ },
2118
+ ],
2119
+ });
2120
+ mockSubDomainRequest();
2121
+
2122
+ await expect(runWrangler("publish index.js")).resolves.toBeUndefined();
2123
+ expect(std.out).toMatchInlineSnapshot(`
2124
+ "Uploaded test-name (TIMINGS)
2125
+ Published test-name (TIMINGS)
2126
+ test-name.test-sub-domain.workers.dev"
2127
+ `);
2128
+ expect(std.err).toMatchInlineSnapshot(`""`);
2129
+ expect(std.warn).toMatchInlineSnapshot(`
2130
+ "Processing wrangler.toml configuration:
2131
+ - \\"unsafe\\" fields are experimental and may change or break at any time."
2132
+ `);
2133
+ });
2134
+
2135
+ it("should error when bindings of different types have the same name", async () => {
2136
+ writeWranglerToml({
2137
+ durable_objects: {
2138
+ bindings: [
2139
+ {
2140
+ name: "CONFLICTING_NAME_ONE",
2141
+ class_name: "SomeDurableObject",
2142
+ script_name: "some-durable-object-worker",
2143
+ },
2144
+ {
2145
+ name: "CONFLICTING_NAME_TWO",
2146
+ class_name: "AnotherDurableObject",
2147
+ script_name: "another-durable-object-worker",
2148
+ },
2149
+ ],
2150
+ },
2151
+ kv_namespaces: [
2152
+ { binding: "CONFLICTING_NAME_ONE", id: "kv-ns-one-id" },
2153
+ { binding: "CONFLICTING_NAME_TWO", id: "kv-ns-two-id" },
2154
+ ],
2155
+ r2_buckets: [
2156
+ {
2157
+ binding: "CONFLICTING_NAME_ONE",
2158
+ bucket_name: "r2-bucket-one-name",
2159
+ },
2160
+ {
2161
+ binding: "CONFLICTING_NAME_THREE",
2162
+ bucket_name: "r2-bucket-two-name",
2163
+ },
2164
+ ],
2165
+ text_blobs: {
2166
+ CONFLICTING_NAME_THREE: "./my-entire-app-depends-on-this.cfg",
2167
+ CONFLICTING_NAME_FOUR: "./the-entirety-of-human-knowledge.txt",
2168
+ },
2169
+ unsafe: {
2170
+ bindings: [
2171
+ {
2172
+ name: "CONFLICTING_NAME_THREE",
2173
+ type: "some unsafe thing",
2174
+ data: { some: { unsafe: "thing" } },
2175
+ },
2176
+ {
2177
+ name: "CONFLICTING_NAME_FOUR",
2178
+ type: "another unsafe thing",
2179
+ data: 1337,
2180
+ },
2181
+ ],
2182
+ },
2183
+ vars: {
2184
+ ENV_VAR_ONE: 123,
2185
+ CONFLICTING_NAME_THREE: "Hello, I'm an environment variable",
2186
+ },
2187
+ wasm_modules: {
2188
+ WASM_MODULE_ONE: "./some_wasm.wasm",
2189
+ CONFLICTING_NAME_THREE: "./more_wasm.wasm",
2190
+ },
2191
+ });
2192
+
2193
+ writeWorkerSource({ type: "sw" });
2194
+ fs.writeFileSync("./my-entire-app-depends-on-this.cfg", "config = value");
2195
+ fs.writeFileSync(
2196
+ "./the-entirety-of-human-knowledge.txt",
2197
+ "Everything's bigger in Texas"
2198
+ );
2199
+ fs.writeFileSync("./some_wasm.wasm", "some wasm");
2200
+ fs.writeFileSync("./more_wasm.wasm", "more wasm");
2201
+
2202
+ await expect(runWrangler("publish index.js")).rejects
2203
+ .toMatchInlineSnapshot(`
2204
+ [Error: Processing wrangler.toml configuration:
2205
+ - CONFLICTING_NAME_ONE assigned to Durable Object, KV Namespace, and R2 Bucket bindings.
2206
+ - CONFLICTING_NAME_TWO assigned to Durable Object and KV Namespace bindings.
2207
+ - CONFLICTING_NAME_THREE assigned to R2 Bucket, Text Blob, Unsafe, Environment Variable, and WASM Module bindings.
2208
+ - CONFLICTING_NAME_FOUR assigned to Text Blob and Unsafe bindings.
2209
+ - Bindings must have unique names, so that they can all be referenced in the worker.
2210
+ Please change your bindings to have unique names.]
2211
+ `);
2212
+ expect(std.out).toMatchInlineSnapshot(`""`);
2213
+ expect(std.err).toMatchInlineSnapshot(`
2214
+ "Processing wrangler.toml configuration:
2215
+ - CONFLICTING_NAME_ONE assigned to Durable Object, KV Namespace, and R2 Bucket bindings.
2216
+ - CONFLICTING_NAME_TWO assigned to Durable Object and KV Namespace bindings.
2217
+ - CONFLICTING_NAME_THREE assigned to R2 Bucket, Text Blob, Unsafe, Environment Variable, and WASM Module bindings.
2218
+ - CONFLICTING_NAME_FOUR assigned to Text Blob and Unsafe bindings.
2219
+ - Bindings must have unique names, so that they can all be referenced in the worker.
2220
+ Please change your bindings to have unique names.
2221
+
2222
+ %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
2223
+ `);
2224
+ expect(std.warn).toMatchInlineSnapshot(`
2225
+ "Processing wrangler.toml configuration:
2226
+ - \\"unsafe\\" fields are experimental and may change or break at any time."
2227
+ `);
2228
+ });
2229
+
2230
+ it("should error when bindings of the same type have the same name", async () => {
2231
+ writeWranglerToml({
2232
+ durable_objects: {
2233
+ bindings: [
2234
+ {
2235
+ name: "CONFLICTING_DURABLE_OBJECT_NAME",
2236
+ class_name: "SomeDurableObject",
2237
+ script_name: "some-durable-object-worker",
2238
+ },
2239
+ {
2240
+ name: "CONFLICTING_DURABLE_OBJECT_NAME",
2241
+ class_name: "AnotherDurableObject",
2242
+ script_name: "another-durable-object-worker",
2243
+ },
2244
+ ],
2245
+ },
2246
+ kv_namespaces: [
2247
+ { binding: "CONFLICTING_KV_NAMESPACE_NAME", id: "kv-ns-one-id" },
2248
+ { binding: "CONFLICTING_KV_NAMESPACE_NAME", id: "kv-ns-two-id" },
2249
+ ],
2250
+ r2_buckets: [
2251
+ {
2252
+ binding: "CONFLICTING_R2_BUCKET_NAME",
2253
+ bucket_name: "r2-bucket-one-name",
2254
+ },
2255
+ {
2256
+ binding: "CONFLICTING_R2_BUCKET_NAME",
2257
+ bucket_name: "r2-bucket-two-name",
2258
+ },
2259
+ ],
2260
+ unsafe: {
2261
+ bindings: [
2262
+ {
2263
+ name: "CONFLICTING_UNSAFE_NAME",
2264
+ type: "some unsafe thing",
2265
+ data: { some: { unsafe: "thing" } },
2266
+ },
2267
+ {
2268
+ name: "CONFLICTING_UNSAFE_NAME",
2269
+ type: "another unsafe thing",
2270
+ data: 1337,
2271
+ },
2272
+ ],
2273
+ },
2274
+ // text_blobs, vars, and wasm_modules are fine because they're object literals,
2275
+ // and by definition cannot have two keys of the same name
2276
+ //
2277
+ // text_blobs: {
2278
+ // CONFLICTING_TEXT_BLOB_NAME: "./my-entire-app-depends-on-this.cfg",
2279
+ // CONFLICTING_TEXT_BLOB_NAME: "./the-entirety-of-human-knowledge.txt",
2280
+ // },
2281
+ // vars: {
2282
+ // CONFLICTING_VARS_NAME: 123,
2283
+ // CONFLICTING_VARS_NAME: "Hello, I'm an environment variable",
2284
+ // },
2285
+ // wasm_modules: {
2286
+ // CONFLICTING_WASM_MODULE_NAME: "./some_wasm.wasm",
2287
+ // CONFLICTING_WASM_MODULE_NAME: "./more_wasm.wasm",
2288
+ // },
2289
+ });
2290
+
2291
+ writeWorkerSource({ type: "sw" });
2292
+
2293
+ await expect(runWrangler("publish index.js")).rejects
2294
+ .toMatchInlineSnapshot(`
2295
+ [Error: Processing wrangler.toml configuration:
2296
+ - CONFLICTING_DURABLE_OBJECT_NAME assigned to multiple Durable Object bindings.
2297
+ - CONFLICTING_KV_NAMESPACE_NAME assigned to multiple KV Namespace bindings.
2298
+ - CONFLICTING_R2_BUCKET_NAME assigned to multiple R2 Bucket bindings.
2299
+ - CONFLICTING_UNSAFE_NAME assigned to multiple Unsafe bindings.
2300
+ - Bindings must have unique names, so that they can all be referenced in the worker.
2301
+ Please change your bindings to have unique names.]
2302
+ `);
2303
+ expect(std.out).toMatchInlineSnapshot(`""`);
2304
+ expect(std.err).toMatchInlineSnapshot(`
2305
+ "Processing wrangler.toml configuration:
2306
+ - CONFLICTING_DURABLE_OBJECT_NAME assigned to multiple Durable Object bindings.
2307
+ - CONFLICTING_KV_NAMESPACE_NAME assigned to multiple KV Namespace bindings.
2308
+ - CONFLICTING_R2_BUCKET_NAME assigned to multiple R2 Bucket bindings.
2309
+ - CONFLICTING_UNSAFE_NAME assigned to multiple Unsafe bindings.
2310
+ - Bindings must have unique names, so that they can all be referenced in the worker.
2311
+ Please change your bindings to have unique names.
2312
+
2313
+ %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
2314
+ `);
2315
+ expect(std.warn).toMatchInlineSnapshot(`
2316
+ "Processing wrangler.toml configuration:
2317
+ - \\"unsafe\\" fields are experimental and may change or break at any time."
2318
+ `);
2319
+ });
2320
+
2321
+ it("should error correctly when bindings of the same and different types use the same name", async () => {
2322
+ writeWranglerToml({
2323
+ durable_objects: {
2324
+ bindings: [
2325
+ {
2326
+ name: "CONFLICTING_DURABLE_OBJECT_NAME",
2327
+ class_name: "SomeDurableObject",
2328
+ script_name: "some-durable-object-worker",
2329
+ },
2330
+ {
2331
+ name: "CONFLICTING_DURABLE_OBJECT_NAME",
2332
+ class_name: "AnotherDurableObject",
2333
+ script_name: "another-durable-object-worker",
2334
+ },
2335
+ ],
2336
+ },
2337
+ kv_namespaces: [
2338
+ {
2339
+ binding: "CONFLICTING_KV_NAMESPACE_NAME",
2340
+ id: "kv-ns-one-id",
2341
+ },
2342
+ {
2343
+ binding: "CONFLICTING_KV_NAMESPACE_NAME",
2344
+ id: "kv-ns-two-id",
2345
+ },
2346
+ { binding: "CONFLICTING_NAME_ONE", id: "kv-ns-three-id" },
2347
+ { binding: "CONFLICTING_NAME_TWO", id: "kv-ns-four-id" },
2348
+ ],
2349
+ r2_buckets: [
2350
+ {
2351
+ binding: "CONFLICTING_R2_BUCKET_NAME",
2352
+ bucket_name: "r2-bucket-one-name",
2353
+ },
2354
+ {
2355
+ binding: "CONFLICTING_R2_BUCKET_NAME",
2356
+ bucket_name: "r2-bucket-two-name",
2357
+ },
2358
+ {
2359
+ binding: "CONFLICTING_NAME_THREE",
2360
+ bucket_name: "r2-bucket-three-name",
2361
+ },
2362
+ {
2363
+ binding: "CONFLICTING_NAME_FOUR",
2364
+ bucket_name: "r2-bucket-four-name",
2365
+ },
2366
+ ],
2367
+ text_blobs: {
2368
+ CONFLICTING_NAME_THREE: "./my-entire-app-depends-on-this.cfg",
2369
+ CONFLICTING_NAME_FOUR: "./the-entirety-of-human-knowledge.txt",
2370
+ },
2371
+ unsafe: {
2372
+ bindings: [
2373
+ {
2374
+ name: "CONFLICTING_UNSAFE_NAME",
2375
+ type: "some unsafe thing",
2376
+ data: { some: { unsafe: "thing" } },
2377
+ },
2378
+ {
2379
+ name: "CONFLICTING_UNSAFE_NAME",
2380
+ type: "another unsafe thing",
2381
+ data: 1337,
2382
+ },
2383
+ {
2384
+ name: "CONFLICTING_NAME_THREE",
2385
+ type: "yet another unsafe thing",
2386
+ data: "how is a string unsafe?",
2387
+ },
2388
+ {
2389
+ name: "CONFLICTING_NAME_FOUR",
2390
+ type: "a fourth unsafe thing",
2391
+ data: null,
2392
+ },
2393
+ ],
2394
+ },
2395
+ vars: {
2396
+ ENV_VAR_ONE: 123,
2397
+ CONFLICTING_NAME_THREE: "Hello, I'm an environment variable",
2398
+ },
2399
+ wasm_modules: {
2400
+ WASM_MODULE_ONE: "./some_wasm.wasm",
2401
+ CONFLICTING_NAME_THREE: "./more_wasm.wasm",
2402
+ },
2403
+ });
2404
+
2405
+ writeWorkerSource({ type: "sw" });
2406
+ fs.writeFileSync("./my-entire-app-depends-on-this.cfg", "config = value");
2407
+ fs.writeFileSync(
2408
+ "./the-entirety-of-human-knowledge.txt",
2409
+ "Everything's bigger in Texas"
2410
+ );
2411
+ fs.writeFileSync("./some_wasm.wasm", "some wasm");
2412
+ fs.writeFileSync("./more_wasm.wasm", "more wasm");
2413
+
2414
+ await expect(runWrangler("publish index.js")).rejects
2415
+ .toMatchInlineSnapshot(`
2416
+ [Error: Processing wrangler.toml configuration:
2417
+ - CONFLICTING_DURABLE_OBJECT_NAME assigned to multiple Durable Object bindings.
2418
+ - CONFLICTING_KV_NAMESPACE_NAME assigned to multiple KV Namespace bindings.
2419
+ - CONFLICTING_R2_BUCKET_NAME assigned to multiple R2 Bucket bindings.
2420
+ - CONFLICTING_NAME_THREE assigned to R2 Bucket, Text Blob, Unsafe, Environment Variable, and WASM Module bindings.
2421
+ - CONFLICTING_NAME_FOUR assigned to R2 Bucket, Text Blob, and Unsafe bindings.
2422
+ - CONFLICTING_UNSAFE_NAME assigned to multiple Unsafe bindings.
2423
+ - Bindings must have unique names, so that they can all be referenced in the worker.
2424
+ Please change your bindings to have unique names.]
2425
+ `);
2426
+ expect(std.out).toMatchInlineSnapshot(`""`);
2427
+ expect(std.err).toMatchInlineSnapshot(`
2428
+ "Processing wrangler.toml configuration:
2429
+ - CONFLICTING_DURABLE_OBJECT_NAME assigned to multiple Durable Object bindings.
2430
+ - CONFLICTING_KV_NAMESPACE_NAME assigned to multiple KV Namespace bindings.
2431
+ - CONFLICTING_R2_BUCKET_NAME assigned to multiple R2 Bucket bindings.
2432
+ - CONFLICTING_NAME_THREE assigned to R2 Bucket, Text Blob, Unsafe, Environment Variable, and WASM Module bindings.
2433
+ - CONFLICTING_NAME_FOUR assigned to R2 Bucket, Text Blob, and Unsafe bindings.
2434
+ - CONFLICTING_UNSAFE_NAME assigned to multiple Unsafe bindings.
2435
+ - Bindings must have unique names, so that they can all be referenced in the worker.
2436
+ Please change your bindings to have unique names.
2437
+
2438
+ %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
2439
+ `);
2440
+ expect(std.warn).toMatchInlineSnapshot(`
2441
+ "Processing wrangler.toml configuration:
2442
+ - \\"unsafe\\" fields are experimental and may change or break at any time."
2443
+ `);
2444
+ });
2445
+
2446
+ describe("[wasm_modules]", () => {
2447
+ it("should be able to define wasm modules for service-worker format workers", async () => {
2448
+ writeWranglerToml({
2449
+ wasm_modules: {
2450
+ TESTWASMNAME: "./path/to/test.wasm",
2451
+ },
2452
+ });
2453
+ writeWorkerSource({ type: "sw" });
2454
+ fs.mkdirSync("./path/to", { recursive: true });
2455
+ fs.writeFileSync("./path/to/test.wasm", "SOME WASM CONTENT");
2456
+ mockUploadWorkerRequest({
2457
+ expectedType: "sw",
2458
+ expectedModules: { TESTWASMNAME: "SOME WASM CONTENT" },
2459
+ expectedBindings: [
2460
+ { name: "TESTWASMNAME", part: "TESTWASMNAME", type: "wasm_module" },
2461
+ ],
2462
+ });
2463
+ mockSubDomainRequest();
2464
+ await runWrangler("publish index.js");
2465
+ expect(std.out).toMatchInlineSnapshot(`
2466
+ "Uploaded test-name (TIMINGS)
2467
+ Published test-name (TIMINGS)
2468
+ test-name.test-sub-domain.workers.dev"
2469
+ `);
2470
+ expect(std.err).toMatchInlineSnapshot(`""`);
2471
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2472
+ });
2473
+
2474
+ it("should error when defining wasm modules for modules format workers", async () => {
2475
+ writeWranglerToml({
2476
+ wasm_modules: {
2477
+ TESTWASMNAME: "./path/to/test.wasm",
2478
+ },
2479
+ });
2480
+ writeWorkerSource({ type: "esm" });
2481
+ fs.mkdirSync("./path/to", { recursive: true });
2482
+ fs.writeFileSync("./path/to/test.wasm", "SOME WASM CONTENT");
2483
+
2484
+ await expect(
2485
+ runWrangler("publish index.js")
2486
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
2487
+ `"You cannot configure [wasm_modules] with an ES module worker. Instead, import the .wasm module directly in your code"`
2488
+ );
2489
+ expect(std.out).toMatchInlineSnapshot(`""`);
2490
+ expect(std.err).toMatchInlineSnapshot(`
2491
+ "You cannot configure [wasm_modules] with an ES module worker. Instead, import the .wasm module directly in your code
2492
+
2493
+ %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
2494
+ `);
2495
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2496
+ });
2497
+
2498
+ it("should resolve wasm modules relative to the wrangler.toml file", async () => {
2499
+ fs.mkdirSync("./path/to/and/the/path/to/", { recursive: true });
2500
+ fs.writeFileSync(
2501
+ "./path/to/wrangler.toml",
2502
+ TOML.stringify({
2503
+ compatibility_date: "2022-01-12",
2504
+ name: "test-name",
2505
+ wasm_modules: {
2506
+ TESTWASMNAME: "./and/the/path/to/test.wasm",
2507
+ },
2508
+ }),
2509
+
2510
+ "utf-8"
2511
+ );
2512
+
2513
+ writeWorkerSource({ type: "sw" });
2514
+ fs.writeFileSync(
2515
+ "./path/to/and/the/path/to/test.wasm",
2516
+ "SOME WASM CONTENT"
2517
+ );
2518
+ mockUploadWorkerRequest({
2519
+ expectedType: "sw",
2520
+ expectedModules: { TESTWASMNAME: "SOME WASM CONTENT" },
2521
+ expectedBindings: [
2522
+ { name: "TESTWASMNAME", part: "TESTWASMNAME", type: "wasm_module" },
2523
+ ],
2524
+ expectedCompatibilityDate: "2022-01-12",
2525
+ });
2526
+ mockSubDomainRequest();
2527
+ await runWrangler("publish index.js --config ./path/to/wrangler.toml");
2528
+ expect(std.out).toMatchInlineSnapshot(`
2529
+ "Uploaded test-name (TIMINGS)
2530
+ Published test-name (TIMINGS)
2531
+ test-name.test-sub-domain.workers.dev"
2532
+ `);
2533
+ expect(std.err).toMatchInlineSnapshot(`""`);
2534
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2535
+ });
2536
+
2537
+ it("should be able to import .wasm modules from service-worker format workers", async () => {
2538
+ writeWranglerToml();
2539
+ fs.writeFileSync(
2540
+ "./index.js",
2541
+ "import TESTWASMNAME from './test.wasm';"
2542
+ );
2543
+ fs.writeFileSync("./test.wasm", "SOME WASM CONTENT");
2544
+ mockUploadWorkerRequest({
2545
+ expectedType: "sw",
2546
+ expectedModules: {
2547
+ __94b240d0d692281e6467aa42043986e5c7eea034_test_wasm:
2548
+ "SOME WASM CONTENT",
2549
+ },
2550
+ expectedBindings: [
2551
+ {
2552
+ name: "__94b240d0d692281e6467aa42043986e5c7eea034_test_wasm",
2553
+ part: "__94b240d0d692281e6467aa42043986e5c7eea034_test_wasm",
2554
+ type: "wasm_module",
2555
+ },
2556
+ ],
2557
+ });
2558
+ mockSubDomainRequest();
2559
+ await runWrangler("publish index.js");
2560
+ expect(std.out).toMatchInlineSnapshot(`
2561
+ "Uploaded test-name (TIMINGS)
2562
+ Published test-name (TIMINGS)
2563
+ test-name.test-sub-domain.workers.dev"
2564
+ `);
2565
+ expect(std.err).toMatchInlineSnapshot(`""`);
2566
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2567
+ });
2568
+ });
2569
+
2570
+ describe("[text_blobs]", () => {
2571
+ it("should be able to define text blobs for service-worker format workers", async () => {
2572
+ writeWranglerToml({
2573
+ text_blobs: {
2574
+ TESTTEXTBLOBNAME: "./path/to/text.file",
2575
+ },
2576
+ });
2577
+ writeWorkerSource({ type: "sw" });
2578
+ fs.mkdirSync("./path/to", { recursive: true });
2579
+ fs.writeFileSync("./path/to/text.file", "SOME TEXT CONTENT");
2580
+ mockUploadWorkerRequest({
2581
+ expectedType: "sw",
2582
+ expectedModules: { TESTTEXTBLOBNAME: "SOME TEXT CONTENT" },
2583
+ expectedBindings: [
2584
+ {
2585
+ name: "TESTTEXTBLOBNAME",
2586
+ part: "TESTTEXTBLOBNAME",
2587
+ type: "text_blob",
2588
+ },
2589
+ ],
2590
+ });
2591
+ mockSubDomainRequest();
2592
+ await runWrangler("publish index.js");
2593
+ expect(std.out).toMatchInlineSnapshot(`
2594
+ "Uploaded test-name (TIMINGS)
2595
+ Published test-name (TIMINGS)
2596
+ test-name.test-sub-domain.workers.dev"
2597
+ `);
2598
+ expect(std.err).toMatchInlineSnapshot(`""`);
2599
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2600
+ });
2601
+
2602
+ it("should error when defining text blobs for modules format workers", async () => {
2603
+ writeWranglerToml({
2604
+ text_blobs: {
2605
+ TESTTEXTBLOBNAME: "./path/to/text.file",
2606
+ },
2607
+ });
2608
+ writeWorkerSource({ type: "esm" });
2609
+ fs.mkdirSync("./path/to", { recursive: true });
2610
+ fs.writeFileSync("./path/to/text.file", "SOME TEXT CONTENT");
2611
+
2612
+ await expect(
2613
+ runWrangler("publish index.js")
2614
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
2615
+ `"You cannot configure [text_blobs] with an ES module worker. Instead, import the file directly in your code, and optionally configure \`[build.upload.rules]\` in your wrangler.toml"`
2616
+ );
2617
+ expect(std.out).toMatchInlineSnapshot(`""`);
2618
+ expect(std.err).toMatchInlineSnapshot(`
2619
+ "You cannot configure [text_blobs] with an ES module worker. Instead, import the file directly in your code, and optionally configure \`[build.upload.rules]\` in your wrangler.toml
2620
+
2621
+ %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
2622
+ `);
2623
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2624
+ });
2625
+
2626
+ it("should resolve text blobs relative to the wrangler.toml file", async () => {
2627
+ fs.mkdirSync("./path/to/and/the/path/to/", { recursive: true });
2628
+ fs.writeFileSync(
2629
+ "./path/to/wrangler.toml",
2630
+ TOML.stringify({
2631
+ compatibility_date: "2022-01-12",
2632
+ name: "test-name",
2633
+ text_blobs: {
2634
+ TESTTEXTBLOBNAME: "./and/the/path/to/text.file",
2635
+ },
2636
+ }),
2637
+
2638
+ "utf-8"
2639
+ );
2640
+
2641
+ writeWorkerSource({ type: "sw" });
2642
+ fs.writeFileSync(
2643
+ "./path/to/and/the/path/to/text.file",
2644
+ "SOME TEXT CONTENT"
2645
+ );
2646
+ mockUploadWorkerRequest({
2647
+ expectedType: "sw",
2648
+ expectedModules: { TESTTEXTBLOBNAME: "SOME TEXT CONTENT" },
2649
+ expectedBindings: [
2650
+ {
2651
+ name: "TESTTEXTBLOBNAME",
2652
+ part: "TESTTEXTBLOBNAME",
2653
+ type: "text_blob",
2654
+ },
2655
+ ],
2656
+ expectedCompatibilityDate: "2022-01-12",
2657
+ });
2658
+ mockSubDomainRequest();
2659
+ await runWrangler("publish index.js --config ./path/to/wrangler.toml");
2660
+ expect(std.out).toMatchInlineSnapshot(`
2661
+ "Uploaded test-name (TIMINGS)
2662
+ Published test-name (TIMINGS)
2663
+ test-name.test-sub-domain.workers.dev"
2664
+ `);
2665
+ expect(std.err).toMatchInlineSnapshot(`""`);
2666
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2667
+ });
2668
+ });
2669
+
2670
+ describe("[vars]", () => {
2671
+ it("should support json bindings", async () => {
2672
+ writeWranglerToml({
2673
+ vars: {
2674
+ text: "plain ol' string",
2675
+ count: 1,
2676
+ complex: { enabled: true, id: 123 },
2677
+ },
2678
+ });
2679
+ writeWorkerSource();
2680
+ mockSubDomainRequest();
2681
+ mockUploadWorkerRequest({
2682
+ expectedBindings: [
2683
+ { name: "text", type: "plain_text", text: "plain ol' string" },
2684
+ { name: "count", type: "json", json: 1 },
2685
+ {
2686
+ name: "complex",
2687
+ type: "json",
2688
+ json: { enabled: true, id: 123 },
2689
+ },
2690
+ ],
2691
+ });
2692
+
2693
+ await runWrangler("publish index.js");
2694
+ expect(std.out).toMatchInlineSnapshot(`
2695
+ "Uploaded test-name (TIMINGS)
2696
+ Published test-name (TIMINGS)
2697
+ test-name.test-sub-domain.workers.dev"
2698
+ `);
2699
+ expect(std.err).toMatchInlineSnapshot(`""`);
2700
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2701
+ });
2702
+ });
2703
+
2704
+ describe("[r2_buckets]", () => {
2705
+ it("should support r2 bucket bindings", async () => {
2706
+ writeWranglerToml({
2707
+ r2_buckets: [{ binding: "FOO", bucket_name: "foo-bucket" }],
2708
+ });
2709
+ writeWorkerSource();
2710
+ mockSubDomainRequest();
2711
+ mockUploadWorkerRequest({
2712
+ expectedBindings: [
2713
+ { bucket_name: "foo-bucket", name: "FOO", type: "r2_bucket" },
2714
+ ],
2715
+ });
2716
+
2717
+ await runWrangler("publish index.js");
2718
+ expect(std.out).toMatchInlineSnapshot(`
2719
+ "Uploaded test-name (TIMINGS)
2720
+ Published test-name (TIMINGS)
2721
+ test-name.test-sub-domain.workers.dev"
2722
+ `);
2723
+ expect(std.err).toMatchInlineSnapshot(`""`);
2724
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2725
+ });
2726
+ });
2727
+
2728
+ describe("[durable_objects]", () => {
2729
+ it("should support durable object bindings", async () => {
2730
+ writeWranglerToml({
2731
+ durable_objects: {
2732
+ bindings: [
2733
+ {
2734
+ name: "EXAMPLE_DO_BINDING",
2735
+ class_name: "ExampleDurableObject",
2736
+ },
2737
+ ],
2738
+ },
2739
+ });
2740
+ writeWorkerSource({ type: "esm" });
2741
+ mockSubDomainRequest();
2742
+ mockUploadWorkerRequest({
2743
+ expectedBindings: [
2744
+ {
2745
+ class_name: "ExampleDurableObject",
2746
+ name: "EXAMPLE_DO_BINDING",
2747
+ type: "durable_object_namespace",
2748
+ },
2749
+ ],
2750
+ });
2751
+
2752
+ await runWrangler("publish index.js");
2753
+ expect(std.out).toMatchInlineSnapshot(`
2754
+ "Uploaded test-name (TIMINGS)
2755
+ Published test-name (TIMINGS)
2756
+ test-name.test-sub-domain.workers.dev"
2757
+ `);
2758
+ expect(std.err).toMatchInlineSnapshot(`""`);
2759
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2760
+ });
2761
+
2762
+ it("should support service-workers binding to external durable objects", async () => {
2763
+ writeWranglerToml({
2764
+ durable_objects: {
2765
+ bindings: [
2766
+ {
2767
+ name: "EXAMPLE_DO_BINDING",
2768
+ class_name: "ExampleDurableObject",
2769
+ script_name: "example-do-binding-worker",
2770
+ },
2771
+ ],
2772
+ },
2773
+ });
2774
+ writeWorkerSource({ type: "sw" });
2775
+ mockSubDomainRequest();
2776
+ mockUploadWorkerRequest({
2777
+ expectedType: "sw",
2778
+ expectedBindings: [
2779
+ {
2780
+ name: "EXAMPLE_DO_BINDING",
2781
+ class_name: "ExampleDurableObject",
2782
+ script_name: "example-do-binding-worker",
2783
+ type: "durable_object_namespace",
2784
+ },
2785
+ ],
2786
+ });
2787
+
2788
+ await runWrangler("publish index.js");
2789
+ expect(std.out).toMatchInlineSnapshot(`
2790
+ "Uploaded test-name (TIMINGS)
2791
+ Published test-name (TIMINGS)
2792
+ test-name.test-sub-domain.workers.dev"
2793
+ `);
2794
+ expect(std.err).toMatchInlineSnapshot(`""`);
2795
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2796
+ });
2797
+
2798
+ it("should support module workers implementing durable objects", async () => {
2799
+ writeWranglerToml({
2800
+ durable_objects: {
2801
+ bindings: [
2802
+ {
2803
+ name: "EXAMPLE_DO_BINDING",
2804
+ class_name: "ExampleDurableObject",
2805
+ },
2806
+ ],
2807
+ },
2808
+ });
2809
+ writeWorkerSource({ type: "esm" });
2810
+ mockSubDomainRequest();
2811
+ mockUploadWorkerRequest({
2812
+ expectedType: "esm",
2813
+ expectedBindings: [
2814
+ {
2815
+ name: "EXAMPLE_DO_BINDING",
2816
+ class_name: "ExampleDurableObject",
2817
+ type: "durable_object_namespace",
2818
+ },
2819
+ ],
2820
+ });
2821
+
2822
+ await runWrangler("publish index.js");
2823
+ expect(std.out).toMatchInlineSnapshot(`
2824
+ "Uploaded test-name (TIMINGS)
2825
+ Published test-name (TIMINGS)
2826
+ test-name.test-sub-domain.workers.dev"
2827
+ `);
2828
+ expect(std.err).toMatchInlineSnapshot(`""`);
2829
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2830
+ });
2831
+
2832
+ it("should error when detecting service workers implementing durable objects", async () => {
2833
+ writeWranglerToml({
2834
+ durable_objects: {
2835
+ bindings: [
2836
+ {
2837
+ name: "EXAMPLE_DO_BINDING",
2838
+ class_name: "ExampleDurableObject",
2839
+ },
2840
+ ],
2841
+ },
2842
+ });
2843
+ writeWorkerSource({ type: "sw" });
2844
+ mockSubDomainRequest();
2845
+
2846
+ await expect(runWrangler("publish index.js")).rejects
2847
+ .toThrowErrorMatchingInlineSnapshot(`
2848
+ "You seem to be trying to use Durable Objects in a Worker written with Service Worker syntax.
2849
+ You can use Durable Objects defined in other Workers by specifying a \`script_name\` in your wrangler.toml, where \`script_name\` is the name of the Worker that implements that Durable Object. For example:
2850
+ { name = EXAMPLE_DO_BINDING, class_name = ExampleDurableObject } ==> { name = EXAMPLE_DO_BINDING, class_name = ExampleDurableObject, script_name = example-do-binding-worker }
2851
+ Alternatively, migrate your worker to ES Module syntax to implement a Durable Object in this Worker:
2852
+ https://developers.cloudflare.com/workers/learning/migrating-to-module-workers/"
2853
+ `);
2854
+ });
2855
+ });
2856
+
2857
+ describe("[unsafe]", () => {
2858
+ it("should warn if using unsafe bindings", async () => {
2859
+ writeWranglerToml({
2860
+ unsafe: {
2861
+ bindings: [
2862
+ {
2863
+ name: "my-binding",
2864
+ type: "binding-type",
2865
+ param: "binding-param",
2866
+ },
2867
+ ],
2868
+ },
2869
+ });
2870
+ writeWorkerSource();
2871
+ mockSubDomainRequest();
2872
+ mockUploadWorkerRequest({
2873
+ expectedBindings: [
2874
+ {
2875
+ name: "my-binding",
2876
+ type: "binding-type",
2877
+ param: "binding-param",
2878
+ },
2879
+ ],
2880
+ });
2881
+
2882
+ await runWrangler("publish index.js");
2883
+ expect(std.out).toMatchInlineSnapshot(`
2884
+ "Uploaded test-name (TIMINGS)
2885
+ Published test-name (TIMINGS)
2886
+ test-name.test-sub-domain.workers.dev"
2887
+ `);
2888
+ expect(std.err).toMatchInlineSnapshot(`""`);
2889
+ expect(std.warn).toMatchInlineSnapshot(`
2890
+ "Processing wrangler.toml configuration:
2891
+ - \\"unsafe\\" fields are experimental and may change or break at any time."
2892
+ `);
2893
+ });
2894
+ it("should warn if using unsafe bindings already handled by wrangler", async () => {
2895
+ writeWranglerToml({
2896
+ unsafe: {
2897
+ bindings: [
2898
+ {
2899
+ name: "my-binding",
2900
+ type: "plain_text",
2901
+ text: "text",
2902
+ },
2903
+ ],
2904
+ },
2905
+ });
2906
+ writeWorkerSource();
2907
+ mockSubDomainRequest();
2908
+ mockUploadWorkerRequest({
2909
+ expectedBindings: [
2910
+ {
2911
+ name: "my-binding",
2912
+ type: "plain_text",
2913
+ text: "text",
2914
+ },
2915
+ ],
2916
+ });
2917
+
2918
+ await runWrangler("publish index.js");
2919
+ expect(std.out).toMatchInlineSnapshot(`
2920
+ "Uploaded test-name (TIMINGS)
2921
+ Published test-name (TIMINGS)
2922
+ test-name.test-sub-domain.workers.dev"
2923
+ `);
2924
+ expect(std.err).toMatchInlineSnapshot(`""`);
2925
+ expect(std.warn).toMatchInlineSnapshot(`
2926
+ "Processing wrangler.toml configuration:
2927
+ - \\"unsafe\\" fields are experimental and may change or break at any time.
2928
+ - \\"unsafe.bindings[0]\\": {\\"name\\":\\"my-binding\\",\\"type\\":\\"plain_text\\",\\"text\\":\\"text\\"}
2929
+ - The binding type \\"plain_text\\" is directly supported by wrangler.
2930
+ Consider migrating this unsafe binding to a format for 'plain_text' bindings that is supported by wrangler for optimal support.
2931
+ For more details, see https://developers.cloudflare.com/workers/cli-wrangler/configuration"
2932
+ `);
2933
+ });
2934
+ });
2935
+ });
2936
+
2937
+ describe("upload rules", () => {
2938
+ it("should be able to define rules for uploading non-js modules (sw)", async () => {
2939
+ writeWranglerToml({
2940
+ rules: [{ type: "Text", globs: ["**/*.file"], fallthrough: true }],
2941
+ });
2942
+ fs.writeFileSync("./index.js", `import TEXT from './text.file';`);
2943
+ fs.writeFileSync("./text.file", "SOME TEXT CONTENT");
2944
+ mockSubDomainRequest();
2945
+ mockUploadWorkerRequest({
2946
+ expectedType: "sw",
2947
+ expectedBindings: [
2948
+ {
2949
+ name: "__2d91d1c4dd6e57d4f5432187ab7c25f45a8973f0_text_file",
2950
+ part: "__2d91d1c4dd6e57d4f5432187ab7c25f45a8973f0_text_file",
2951
+ type: "text_blob",
2952
+ },
2953
+ ],
2954
+ expectedModules: {
2955
+ __2d91d1c4dd6e57d4f5432187ab7c25f45a8973f0_text_file:
2956
+ "SOME TEXT CONTENT",
2957
+ },
2958
+ });
2959
+ await runWrangler("publish index.js");
2960
+ expect(std.out).toMatchInlineSnapshot(`
2961
+ "Uploaded test-name (TIMINGS)
2962
+ Published test-name (TIMINGS)
2963
+ test-name.test-sub-domain.workers.dev"
2964
+ `);
2965
+ expect(std.err).toMatchInlineSnapshot(`""`);
2966
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2967
+ });
2968
+
2969
+ it("should be able to define rules for uploading non-js modules (esm)", async () => {
2970
+ writeWranglerToml({
2971
+ rules: [{ type: "Text", globs: ["**/*.file"], fallthrough: true }],
2972
+ });
2973
+ fs.writeFileSync(
2974
+ "./index.js",
2975
+ `import TEXT from './text.file'; export default {};`
2976
+ );
2977
+ fs.writeFileSync("./text.file", "SOME TEXT CONTENT");
2978
+ mockSubDomainRequest();
2979
+ mockUploadWorkerRequest({
2980
+ expectedType: "esm",
2981
+ expectedBindings: [],
2982
+ expectedModules: {
2983
+ "./2d91d1c4dd6e57d4f5432187ab7c25f45a8973f0-text.file":
2984
+ "SOME TEXT CONTENT",
2985
+ },
2986
+ });
2987
+ await runWrangler("publish index.js");
2988
+ expect(std.out).toMatchInlineSnapshot(`
2989
+ "Uploaded test-name (TIMINGS)
2990
+ Published test-name (TIMINGS)
2991
+ test-name.test-sub-domain.workers.dev"
2992
+ `);
2993
+ expect(std.err).toMatchInlineSnapshot(`""`);
2994
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2995
+ });
2996
+
2997
+ it("should log a deprecation warning when using `build.upload.rules`", async () => {
2998
+ writeWranglerToml({
2999
+ build: {
3000
+ upload: {
3001
+ rules: [{ type: "Text", globs: ["**/*.file"], fallthrough: true }],
3002
+ },
3003
+ },
3004
+ });
3005
+ fs.writeFileSync(
3006
+ "./index.js",
3007
+ `import TEXT from './text.file'; export default {};`
3008
+ );
3009
+ fs.writeFileSync("./text.file", "SOME TEXT CONTENT");
3010
+ mockSubDomainRequest();
3011
+ mockUploadWorkerRequest({
3012
+ expectedType: "esm",
3013
+ expectedBindings: [],
3014
+ expectedModules: {
3015
+ "./2d91d1c4dd6e57d4f5432187ab7c25f45a8973f0-text.file":
3016
+ "SOME TEXT CONTENT",
3017
+ },
3018
+ });
3019
+ await runWrangler("publish index.js");
3020
+ expect(std.out).toMatchInlineSnapshot(`
3021
+ "Uploaded test-name (TIMINGS)
3022
+ Published test-name (TIMINGS)
3023
+ test-name.test-sub-domain.workers.dev"
3024
+ `);
3025
+ expect(std.err).toMatchInlineSnapshot(`""`);
3026
+ expect(std.warn).toMatchInlineSnapshot(`
3027
+ "Processing wrangler.toml configuration:
3028
+ - DEPRECATION: The \`build.upload.rules\` config field is no longer used, the rules should be specified via the \`rules\` config field. Delete the \`build.upload\` field from the configuration file, and add this:
3029
+ \`\`\`
3030
+ [[rules]]
3031
+ type = \\"Text\\"
3032
+ globs = [ \\"**/*.file\\" ]
3033
+ fallthrough = true
3034
+ \`\`\`"
3035
+ `);
3036
+ });
3037
+
3038
+ it("should be able to use fallthrough:true for multiple rules", async () => {
3039
+ writeWranglerToml({
3040
+ rules: [
3041
+ { type: "Text", globs: ["**/*.file"], fallthrough: true },
3042
+ { type: "Text", globs: ["**/*.other"], fallthrough: true },
3043
+ ],
3044
+ });
3045
+ fs.writeFileSync(
3046
+ "./index.js",
3047
+ `import TEXT from './text.file'; import OTHER from './other.other'; export default {};`
3048
+ );
3049
+ fs.writeFileSync("./text.file", "SOME TEXT CONTENT");
3050
+ fs.writeFileSync("./other.other", "SOME OTHER TEXT CONTENT");
3051
+ mockSubDomainRequest();
3052
+ mockUploadWorkerRequest({
3053
+ expectedType: "esm",
3054
+ expectedBindings: [],
3055
+ expectedModules: {
3056
+ "./2d91d1c4dd6e57d4f5432187ab7c25f45a8973f0-text.file":
3057
+ "SOME TEXT CONTENT",
3058
+ "./16347a01366873ed80fe45115119de3c92ab8db0-other.other":
3059
+ "SOME OTHER TEXT CONTENT",
3060
+ },
3061
+ });
3062
+ await runWrangler("publish index.js");
3063
+ expect(std.out).toMatchInlineSnapshot(`
3064
+ "Uploaded test-name (TIMINGS)
3065
+ Published test-name (TIMINGS)
3066
+ test-name.test-sub-domain.workers.dev"
3067
+ `);
3068
+ expect(std.err).toMatchInlineSnapshot(`""`);
3069
+ expect(std.warn).toMatchInlineSnapshot(`""`);
3070
+ });
3071
+
3072
+ it("should be able to use fallthrough:false for multiple rules", async () => {
3073
+ writeWranglerToml({
3074
+ rules: [
3075
+ { type: "Text", globs: ["**/*.file"], fallthrough: false },
3076
+ { type: "Text", globs: ["**/*.other"] },
3077
+ ],
3078
+ });
3079
+ fs.writeFileSync(
3080
+ "./index.js",
3081
+ `import TEXT from './text.file'; import OTHER from './other.other'; export default {};`
3082
+ );
3083
+ fs.writeFileSync("./text.file", "SOME TEXT CONTENT");
3084
+ fs.writeFileSync("./other.other", "SOME OTHER TEXT CONTENT");
3085
+
3086
+ // We throw an error when we come across a file that matched a rule
3087
+ // but was skipped because of fallthrough = false
3088
+ let err: Error | undefined;
3089
+ try {
3090
+ await runWrangler("publish index.js");
3091
+ } catch (e) {
3092
+ err = e as Error;
3093
+ }
3094
+ expect(err?.message).toMatch(
3095
+ `The file ./other.other matched a module rule in your configuration ({"type":"Text","globs":["**/*.other"]}), but was ignored because a previous rule with the same type was not marked as \`fallthrough = true\`.`
3096
+ );
3097
+ });
3098
+
3099
+ it("should warn when multiple rules for the same type do not have fallback defined", async () => {
3100
+ writeWranglerToml({
3101
+ rules: [
3102
+ { type: "Text", globs: ["**/*.file"] },
3103
+ { type: "Text", globs: ["**/*.other"] },
3104
+ ],
3105
+ });
3106
+ fs.writeFileSync(
3107
+ "./index.js",
3108
+ `import TEXT from './text.file'; import OTHER from './other.other'; export default {};`
3109
+ );
3110
+ fs.writeFileSync("./text.file", "SOME TEXT CONTENT");
3111
+ fs.writeFileSync("./other.other", "SOME OTHER TEXT CONTENT");
3112
+
3113
+ // We throw an error when we come across a file that matched a rule
3114
+ // but was skipped because of fallthrough = false
3115
+ let err: Error | undefined;
3116
+ try {
3117
+ await runWrangler("publish index.js");
3118
+ } catch (e) {
3119
+ err = e as Error;
3120
+ }
3121
+ expect(err?.message).toMatch(
3122
+ `The file ./other.other matched a module rule in your configuration ({"type":"Text","globs":["**/*.other"]}), but was ignored because a previous rule with the same type was not marked as \`fallthrough = true\`.`
3123
+ );
3124
+ // and the warnings because fallthrough was not explicitly set
3125
+ expect(std.warn).toMatchInlineSnapshot(`
3126
+ "The module rule at position 1 ({\\"type\\":\\"Text\\",\\"globs\\":[\\"**/*.other\\"]}) has the same type as a previous rule (at position 0, {\\"type\\":\\"Text\\",\\"globs\\":[\\"**/*.file\\"]}). This rule will be ignored. To the previous rule, add \`fallthrough = true\` to allow this one to also be used, or \`fallthrough = false\` to silence this warning.
3127
+ The default module rule {\\"type\\":\\"Text\\",\\"globs\\":[\\"**/*.txt\\",\\"**/*.html\\"]} has the same type as a previous rule (at position 0, {\\"type\\":\\"Text\\",\\"globs\\":[\\"**/*.file\\"]}). This rule will be ignored. To the previous rule, add \`fallthrough = true\` to allow the default one to also be used, or \`fallthrough = false\` to silence this warning."
3128
+ `);
3129
+ });
3130
+
3131
+ describe("inject process.env.NODE_ENV", () => {
3132
+ let actualProcessEnvNodeEnv: string | undefined;
3133
+ beforeEach(() => {
3134
+ actualProcessEnvNodeEnv = process.env.NODE_ENV;
3135
+ process.env.NODE_ENV = "some-node-env";
3136
+ });
3137
+ afterEach(() => {
3138
+ process.env.NODE_ENV = actualProcessEnvNodeEnv;
3139
+ });
3140
+ it("should replace `process.env.NODE_ENV` in scripts", async () => {
3141
+ writeWranglerToml();
3142
+ fs.writeFileSync(
3143
+ "./index.js",
3144
+ `export default {
3145
+ fetch(){
3146
+ return new Response(process.env.NODE_ENV);
3147
+ }
3148
+ }`
3149
+ );
3150
+ mockSubDomainRequest();
3151
+ mockUploadWorkerRequest({
3152
+ expectedEntry: `return new Response("some-node-env");`,
3153
+ });
3154
+ await runWrangler("publish index.js");
3155
+ expect(std.out).toMatchInlineSnapshot(`
3156
+ "Uploaded test-name (TIMINGS)
3157
+ Published test-name (TIMINGS)
3158
+ test-name.test-sub-domain.workers.dev"
3159
+ `);
3160
+ expect(std.err).toMatchInlineSnapshot(`""`);
3161
+ expect(std.warn).toMatchInlineSnapshot(`""`);
3162
+ });
3163
+ });
3164
+ });
3165
+
3166
+ describe("legacy module specifiers", () => {
3167
+ it("should work with legacy module specifiers, with a deprecation warning (1)", async () => {
3168
+ writeWranglerToml({
3169
+ rules: [{ type: "Text", globs: ["**/*.file"], fallthrough: false }],
3170
+ });
3171
+ fs.writeFileSync(
3172
+ "./index.js",
3173
+ `import TEXT from 'text.file'; export default {};`
3174
+ );
3175
+ fs.writeFileSync("./text.file", "SOME TEXT CONTENT");
3176
+ mockSubDomainRequest();
3177
+ mockUploadWorkerRequest({
3178
+ expectedModules: {
3179
+ "./2d91d1c4dd6e57d4f5432187ab7c25f45a8973f0-text.file":
3180
+ "SOME TEXT CONTENT",
3181
+ },
3182
+ });
3183
+ await runWrangler("publish index.js");
3184
+ expect(std.out).toMatchInlineSnapshot(`
3185
+ "Uploaded test-name (TIMINGS)
3186
+ Published test-name (TIMINGS)
3187
+ test-name.test-sub-domain.workers.dev"
3188
+ `);
3189
+ expect(std.err).toMatchInlineSnapshot(`""`);
3190
+ expect(std.warn).toMatchInlineSnapshot(
3191
+ `"Deprecation warning: detected a legacy module import in \\"./index.js\\". This will stop working in the future. Replace references to \\"text.file\\" with \\"./text.file\\";"`
3192
+ );
3193
+ });
3194
+ });
3195
+
3196
+ it("should work with legacy module specifiers, with a deprecation warning (2)", async () => {
3197
+ writeWranglerToml();
3198
+ fs.writeFileSync(
3199
+ "./index.js",
3200
+ `import WASM from 'index.wasm'; export default {};`
3201
+ );
3202
+ fs.writeFileSync("./index.wasm", "SOME WASM CONTENT");
3203
+ mockSubDomainRequest();
3204
+ mockUploadWorkerRequest({
3205
+ expectedModules: {
3206
+ "./94b240d0d692281e6467aa42043986e5c7eea034-index.wasm":
3207
+ "SOME WASM CONTENT",
3208
+ },
3209
+ });
3210
+ await runWrangler("publish index.js");
3211
+ expect(std.out).toMatchInlineSnapshot(`
3212
+ "Uploaded test-name (TIMINGS)
3213
+ Published test-name (TIMINGS)
3214
+ test-name.test-sub-domain.workers.dev"
3215
+ `);
3216
+ expect(std.err).toMatchInlineSnapshot(`""`);
3217
+ expect(std.warn).toMatchInlineSnapshot(
3218
+ `"Deprecation warning: detected a legacy module import in \\"./index.js\\". This will stop working in the future. Replace references to \\"index.wasm\\" with \\"./index.wasm\\";"`
3219
+ );
3220
+ });
3221
+
3222
+ it("should not match regular module specifiers when there aren't any possible legacy module matches", async () => {
3223
+ // see https://github.com/cloudflare/wrangler2/issues/655 for bug details
3224
+
3225
+ fs.writeFileSync(
3226
+ "./index.js",
3227
+ `import inner from './inner/index.js'; export default {};`
3228
+ );
3229
+ fs.mkdirSync("./inner", { recursive: true });
3230
+ fs.writeFileSync("./inner/index.js", `export default 123`);
3231
+ mockSubDomainRequest();
3232
+ mockUploadWorkerRequest();
3233
+
3234
+ await runWrangler(
3235
+ "publish index.js --compatibility-date 2022-03-17 --name test-name"
3236
+ );
3237
+ expect(std.out).toMatchInlineSnapshot(`
3238
+ "Uploaded test-name (TIMINGS)
3239
+ Published test-name (TIMINGS)
3240
+ test-name.test-sub-domain.workers.dev"
3241
+ `);
3242
+ expect(std.err).toMatchInlineSnapshot(`""`);
3243
+ expect(std.warn).toMatchInlineSnapshot(`""`);
3244
+ });
3245
+ });
3246
+
3247
+ /** Write a mock Worker script to disk. */
3248
+ function writeWorkerSource({
3249
+ basePath = ".",
3250
+ format = "js",
3251
+ type = "esm",
3252
+ }: {
3253
+ basePath?: string;
3254
+ format?: "js" | "ts" | "jsx" | "tsx" | "mjs";
3255
+ type?: "esm" | "sw";
3256
+ } = {}) {
3257
+ if (basePath !== ".") {
3258
+ fs.mkdirSync(basePath, { recursive: true });
3259
+ }
3260
+ fs.writeFileSync(
3261
+ `${basePath}/index.${format}`,
3262
+ type === "esm"
3263
+ ? `import { foo } from "./another";
3264
+ export default {
3265
+ async fetch(request) {
3266
+ return new Response('Hello' + foo);
3267
+ },
3268
+ };`
3269
+ : `import { foo } from "./another";
3270
+ addEventListener('fetch', event => {
3271
+ event.respondWith(new Response('Hello' + foo));
3272
+ })`
3273
+ );
3274
+ fs.writeFileSync(`${basePath}/another.${format}`, `export const foo = 100;`);
3275
+ }
3276
+
3277
+ /** Write mock assets to the file system so they can be uploaded. */
3278
+ function writeAssets(assets: { filePath: string; content: string }[]) {
3279
+ for (const asset of assets) {
3280
+ fs.mkdirSync(path.dirname(asset.filePath), { recursive: true });
3281
+ fs.writeFileSync(asset.filePath, asset.content);
3282
+ }
3283
+ }
3284
+
3285
+ /** Create a mock handler for the request to upload a worker script. */
3286
+ function mockUploadWorkerRequest({
3287
+ available_on_subdomain = true,
3288
+ expectedEntry,
3289
+ expectedType = "esm",
3290
+ expectedBindings,
3291
+ expectedModules = {},
3292
+ expectedCompatibilityDate,
3293
+ expectedCompatibilityFlags,
3294
+ env = undefined,
3295
+ legacyEnv = false,
3296
+ }: {
3297
+ available_on_subdomain?: boolean;
3298
+ expectedEntry?: string;
3299
+ expectedType?: "esm" | "sw";
3300
+ expectedBindings?: unknown;
3301
+ expectedModules?: Record<string, string>;
3302
+ expectedCompatibilityDate?: string;
3303
+ expectedCompatibilityFlags?: string[];
3304
+ env?: string;
3305
+ legacyEnv?: boolean;
3306
+ } = {}) {
3307
+ setMockResponse(
3308
+ env && !legacyEnv
3309
+ ? "/accounts/:accountId/workers/services/:scriptName/environments/:envName"
3310
+ : "/accounts/:accountId/workers/scripts/:scriptName",
3311
+ "PUT",
3312
+ async ([_url, accountId, scriptName, envName], { body }, queryParams) => {
3313
+ expect(accountId).toEqual("some-account-id");
3314
+ expect(scriptName).toEqual(
3315
+ legacyEnv && env ? `test-name-${env}` : "test-name"
3316
+ );
3317
+ if (!legacyEnv) {
3318
+ expect(envName).toEqual(env);
3319
+ }
3320
+ expect(queryParams.get("available_on_subdomain")).toEqual("true");
3321
+ const formBody = body as FormData;
3322
+ if (expectedEntry !== undefined) {
3323
+ expect(await (formBody.get("index.js") as File).text()).toMatch(
3324
+ expectedEntry
3325
+ );
3326
+ }
3327
+ const metadata = JSON.parse(
3328
+ formBody.get("metadata") as string
3329
+ ) as WorkerMetadata;
3330
+ if (expectedType === "esm") {
3331
+ expect(metadata.main_module).toEqual("index.js");
3332
+ } else {
3333
+ expect(metadata.body_part).toEqual("index.js");
3334
+ }
3335
+ if (expectedBindings !== undefined) {
3336
+ expect(metadata.bindings).toEqual(expectedBindings);
3337
+ }
3338
+ if (expectedCompatibilityDate !== undefined) {
3339
+ expect(metadata.compatibility_date).toEqual(expectedCompatibilityDate);
3340
+ }
3341
+ if (expectedCompatibilityFlags !== undefined) {
3342
+ expect(metadata.compatibility_flags).toEqual(
3343
+ expectedCompatibilityFlags
3344
+ );
3345
+ }
3346
+ for (const [name, content] of Object.entries(expectedModules)) {
3347
+ expect(await (formBody.get(name) as File).text()).toEqual(content);
3348
+ }
3349
+
3350
+ return { available_on_subdomain };
3351
+ }
3352
+ );
3353
+ }
3354
+
3355
+ /** Create a mock handler for the request to get the account's subdomain. */
3356
+ function mockSubDomainRequest(
3357
+ subdomain = "test-sub-domain",
3358
+ registeredWorkersDev = true
3359
+ ) {
3360
+ if (registeredWorkersDev) {
3361
+ setMockResponse("/accounts/:accountId/workers/subdomain", "GET", () => {
3362
+ return { subdomain };
3363
+ });
3364
+ } else {
3365
+ setMockRawResponse("/accounts/:accountId/workers/subdomain", "GET", () => {
3366
+ return createFetchResult(null, false, [
3367
+ { code: 10007, message: "haven't registered workers.dev" },
3368
+ ]);
3369
+ });
3370
+ }
3371
+ }
3372
+
3373
+ /** Create a mock handler to toggle a <script>.<user>.workers.dev subdomain */
3374
+ function mockUpdateWorkerRequest({
3375
+ env,
3376
+ enabled,
3377
+ legacyEnv = false,
3378
+ }: {
3379
+ enabled: boolean;
3380
+ env?: string | undefined;
3381
+ legacyEnv?: boolean | undefined;
3382
+ }) {
3383
+ const requests = { count: 0 };
3384
+ const servicesOrScripts = env && !legacyEnv ? "services" : "scripts";
3385
+ const environment = env && !legacyEnv ? "/environments/:envName" : "";
3386
+ setMockResponse(
3387
+ `/accounts/:accountId/workers/${servicesOrScripts}/:scriptName${environment}/subdomain`,
3388
+ "POST",
3389
+ ([_url, accountId, scriptName, envName], { body }) => {
3390
+ expect(accountId).toEqual("some-account-id");
3391
+ expect(scriptName).toEqual(
3392
+ legacyEnv && env ? `test-name-${env}` : "test-name"
3393
+ );
3394
+ if (!legacyEnv) {
3395
+ expect(envName).toEqual(env);
3396
+ }
3397
+ expect(JSON.parse(body as string)).toEqual({ enabled });
3398
+ return null;
3399
+ }
3400
+ );
3401
+ return requests;
3402
+ }
3403
+
3404
+ function mockPublishRoutesRequest({
3405
+ routes,
3406
+ env = undefined,
3407
+ legacyEnv = false,
3408
+ }: {
3409
+ routes: string[];
3410
+ env?: string | undefined;
3411
+ legacyEnv?: boolean | undefined;
3412
+ }) {
3413
+ const servicesOrScripts = env && !legacyEnv ? "services" : "scripts";
3414
+ const environment = env && !legacyEnv ? "/environments/:envName" : "";
3415
+
3416
+ setMockResponse(
3417
+ `/accounts/:accountId/workers/${servicesOrScripts}/:scriptName${environment}/routes`,
3418
+ "PUT",
3419
+ ([_url, accountId, scriptName, envName], { body }) => {
3420
+ expect(accountId).toEqual("some-account-id");
3421
+ expect(scriptName).toEqual(
3422
+ legacyEnv && env ? `test-name-${env}` : "test-name"
3423
+ );
3424
+ if (!legacyEnv) {
3425
+ expect(envName).toEqual(env);
3426
+ }
3427
+
3428
+ expect(JSON.parse(body as string)).toEqual(
3429
+ routes.map((pattern) => ({ pattern }))
3430
+ );
3431
+ return null;
3432
+ }
3433
+ );
3434
+ }
3435
+
3436
+ /** Create a mock handler for the request to get a list of all KV namespaces. */
3437
+ function mockListKVNamespacesRequest(...namespaces: KVNamespaceInfo[]) {
3438
+ setMockResponse(
3439
+ "/accounts/:accountId/storage/kv/namespaces",
3440
+ "GET",
3441
+ ([_url, accountId]) => {
3442
+ expect(accountId).toEqual("some-account-id");
3443
+ return namespaces;
3444
+ }
3445
+ );
3446
+ }
3447
+
3448
+ /** Create a mock handler for the request that tries to do a bulk upload of assets to a KV namespace. */
1187
3449
  function mockUploadAssetsToKVRequest(
1188
3450
  expectedNamespaceId: string,
1189
- assets: { filePath: string; content: string }[]
3451
+ assets: {
3452
+ filePath: string;
3453
+ content: string;
3454
+ expiration?: number;
3455
+ expiration_ttl?: number;
3456
+ }[]
1190
3457
  ) {
1191
3458
  setMockResponse(
1192
3459
  "/accounts/:accountId/storage/kv/namespaces/:namespaceId/bulk",
@@ -1215,8 +3482,28 @@ function mockUploadAssetsToKVRequest(
1215
3482
  expect(Buffer.from(upload.value, "base64").toString()).toEqual(
1216
3483
  asset.content
1217
3484
  );
3485
+ expect(upload.expiration).toEqual(asset.expiration);
3486
+ expect(upload.expiration_ttl).toEqual(asset.expiration_ttl);
1218
3487
  }
1219
3488
  return null;
1220
3489
  }
1221
3490
  );
1222
3491
  }
3492
+
3493
+ /** Create a mock handler for thr request that does a bulk delete of unused assets */
3494
+ function mockDeleteUnusedAssetsRequest(
3495
+ expectedNamespaceId: string,
3496
+ assets: string[]
3497
+ ) {
3498
+ setMockResponse(
3499
+ "/accounts/:accountId/storage/kv/namespaces/:namespaceId/bulk",
3500
+ "DELETE",
3501
+ ([_url, accountId, namespaceId], { body }) => {
3502
+ expect(accountId).toEqual("some-account-id");
3503
+ expect(namespaceId).toEqual(expectedNamespaceId);
3504
+ const deletes = JSON.parse(body as string);
3505
+ expect(assets).toEqual(deletes);
3506
+ return null;
3507
+ }
3508
+ );
3509
+ }