wrangler 2.6.2 → 2.7.0

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 (128) hide show
  1. package/bin/wrangler.js +9 -1
  2. package/miniflare-dist/index.mjs +1 -1
  3. package/package.json +12 -10
  4. package/src/__tests__/api-dev.test.ts +65 -36
  5. package/src/__tests__/api-devregistry.test.js +14 -6
  6. package/src/__tests__/configuration.test.ts +2 -31
  7. package/src/__tests__/{d1.test.ts → d1/d1.test.ts} +48 -5
  8. package/src/__tests__/d1/splitter.test.ts +255 -0
  9. package/src/__tests__/delete.test.ts +5 -2
  10. package/src/__tests__/deployments.test.ts +20 -6
  11. package/src/__tests__/dev.test.tsx +52 -19
  12. package/src/__tests__/generate.test.ts +7 -4
  13. package/src/__tests__/helpers/mock-auth-domain.ts +20 -0
  14. package/src/__tests__/helpers/mock-cfetch.ts +2 -57
  15. package/src/__tests__/helpers/mock-dialogs.ts +70 -86
  16. package/src/__tests__/helpers/mock-oauth-flow.ts +64 -49
  17. package/src/__tests__/helpers/mock-process.ts +8 -13
  18. package/src/__tests__/helpers/msw/blob-worker.cjs +19 -0
  19. package/src/__tests__/helpers/msw/read-file-sync.js +61 -0
  20. package/src/__tests__/index.test.ts +46 -44
  21. package/src/__tests__/init.test.ts +761 -537
  22. package/src/__tests__/jest.setup.ts +20 -24
  23. package/src/__tests__/kv.test.ts +286 -173
  24. package/src/__tests__/logout.test.ts +1 -1
  25. package/src/__tests__/metrics.test.ts +5 -7
  26. package/src/__tests__/middleware.scheduled.test.ts +40 -30
  27. package/src/__tests__/middleware.test.ts +144 -120
  28. package/src/__tests__/pages.test.ts +1617 -1161
  29. package/src/__tests__/publish.test.ts +174 -125
  30. package/src/__tests__/r2.test.ts +2 -2
  31. package/src/__tests__/secret.test.ts +183 -126
  32. package/src/__tests__/tail.test.ts +6 -0
  33. package/src/__tests__/tsconfig-sanity.ts +12 -0
  34. package/src/__tests__/tsconfig.json +8 -0
  35. package/src/__tests__/tsconfig.tsbuildinfo +1 -0
  36. package/src/__tests__/whoami.test.tsx +1 -96
  37. package/src/api/dev.ts +78 -41
  38. package/src/api/index.ts +1 -1
  39. package/src/{bundle-reporter.tsx → bundle-reporter.ts} +0 -0
  40. package/src/cfetch/index.ts +0 -2
  41. package/src/cfetch/internal.ts +6 -15
  42. package/src/cli.ts +2 -2
  43. package/src/config/validation.ts +1 -2
  44. package/src/create-worker-upload-form.ts +2 -2
  45. package/src/d1/{delete.tsx → delete.ts} +0 -0
  46. package/src/d1/execute.tsx +8 -37
  47. package/src/d1/migrations/apply.tsx +29 -19
  48. package/src/d1/migrations/{index.tsx → index.ts} +0 -0
  49. package/src/d1/splitter.ts +161 -0
  50. package/src/d1/{types.tsx → types.ts} +0 -0
  51. package/src/delete.ts +3 -8
  52. package/src/deployments.ts +6 -0
  53. package/src/deprecated/index.ts +2 -295
  54. package/src/dev/dev.tsx +2 -2
  55. package/src/dev/{get-local-persistence-path.tsx → get-local-persistence-path.ts} +0 -0
  56. package/src/dev/local.tsx +16 -4
  57. package/src/dev/remote.tsx +28 -1
  58. package/src/dev/start-server.ts +19 -11
  59. package/src/dev/use-esbuild.ts +1 -1
  60. package/src/{dev-registry.tsx → dev-registry.ts} +0 -0
  61. package/src/dev.tsx +21 -2
  62. package/src/dialogs.ts +136 -0
  63. package/src/dispatch-namespace.ts +1 -1
  64. package/src/docs/index.ts +3 -0
  65. package/src/environment-variables/factory.ts +88 -0
  66. package/src/environment-variables/misc-variables.ts +30 -0
  67. package/src/generate/index.ts +300 -0
  68. package/src/{index.tsx → index.ts} +10 -13
  69. package/src/init.ts +92 -52
  70. package/src/jest.d.ts +4 -0
  71. package/src/logger.ts +15 -3
  72. package/src/metrics/metrics-config.ts +1 -1
  73. package/src/miniflare-cli/assets.ts +4 -0
  74. package/src/miniflare-cli/index.ts +1 -5
  75. package/src/miniflare-cli/tsconfig.json +9 -0
  76. package/src/miniflare-cli/tsconfig.tsbuildinfo +1 -0
  77. package/src/miniflare-cli/types.ts +11 -0
  78. package/src/pages/{build.tsx → build.ts} +0 -0
  79. package/src/pages/{deployment-tails.tsx → deployment-tails.ts} +0 -0
  80. package/src/pages/{dev.tsx → dev.ts} +53 -55
  81. package/src/pages/functions/buildWorker.ts +1 -1
  82. package/src/pages/functions/tsconfig.json +8 -0
  83. package/src/pages/functions/tsconfig.tsbuildinfo +1 -0
  84. package/src/pages/{functions.tsx → functions.ts} +0 -0
  85. package/src/pages/{hash.tsx → hash.ts} +0 -0
  86. package/src/pages/{index.tsx → index.ts} +0 -0
  87. package/src/pages/projects.tsx +3 -5
  88. package/src/pages/publish.tsx +5 -4
  89. package/src/pages/upload.tsx +1 -1
  90. package/src/publish/publish.ts +9 -7
  91. package/src/pubsub/{pubsub-commands.tsx → pubsub-commands.ts} +1 -1
  92. package/src/secret/index.ts +1 -1
  93. package/src/{sites.tsx → sites.ts} +0 -0
  94. package/src/tail/index.ts +2 -3
  95. package/src/tsconfig-sanity.ts +16 -0
  96. package/src/user/access.ts +0 -1
  97. package/src/user/auth-variables.ts +113 -0
  98. package/src/user/choose-account.tsx +1 -31
  99. package/src/user/index.ts +0 -1
  100. package/src/user/{user.tsx → user.ts} +107 -73
  101. package/src/{whoami.tsx → whoami.ts} +37 -71
  102. package/templates/__tests__/tsconfig-sanity.ts +12 -0
  103. package/templates/__tests__/tsconfig.json +8 -0
  104. package/templates/__tests__/tsconfig.tsbuildinfo +1 -0
  105. package/templates/d1-beta-facade.js +36 -0
  106. package/templates/facade.d.ts +14 -0
  107. package/templates/first-party-worker-module-facade.ts +4 -3
  108. package/templates/format-dev-errors.ts +7 -6
  109. package/templates/init-tests/test-jest-new-worker.js +3 -5
  110. package/templates/init-tests/test-vitest-new-worker.js +3 -5
  111. package/templates/init-tests/test-vitest-new-worker.ts +25 -0
  112. package/templates/middleware/loader-modules.ts +0 -2
  113. package/templates/middleware/loader-sw.ts +6 -0
  114. package/templates/pages-dev-pipeline.ts +4 -1
  115. package/templates/pages-shim.ts +4 -1
  116. package/templates/pages-template-plugin.ts +12 -7
  117. package/templates/serve-static-assets.ts +16 -14
  118. package/templates/tsconfig-sanity.ts +11 -0
  119. package/templates/tsconfig.init.json +106 -0
  120. package/templates/tsconfig.json +5 -103
  121. package/templates/tsconfig.tsbuildinfo +1 -0
  122. package/wrangler-dist/cli.d.ts +58 -60
  123. package/wrangler-dist/cli.js +34440 -55514
  124. package/wrangler-dist/wasm-sync.wasm +0 -0
  125. package/src/__tests__/dialogs.test.tsx +0 -40
  126. package/src/dialogs.tsx +0 -168
  127. package/src/environment-variables.ts +0 -50
  128. package/src/user/env-vars.ts +0 -46
@@ -1,37 +1,34 @@
1
+ /* eslint-disable no-shadow */
2
+ import { Blob } from "node:buffer";
1
3
  import { mkdirSync, writeFileSync } from "node:fs";
2
4
  import { chdir } from "node:process";
5
+ import { MockedRequest, rest } from "msw";
6
+ import { FormData } from "undici";
3
7
  import { ROUTES_SPEC_VERSION } from "../pages/constants";
4
8
  import { isRoutesJSONSpec } from "../pages/functions/routes-validation";
5
9
  import { version } from "./../../package.json";
6
10
  import { mockAccountId, mockApiToken } from "./helpers/mock-account-id";
7
- import {
8
- createFetchResult,
9
- setMockRawResponse,
10
- setMockResponse,
11
- unsetAllMocks,
12
- } from "./helpers/mock-cfetch";
13
11
  import { mockConsoleMethods } from "./helpers/mock-console";
12
+ import { msw } from "./helpers/msw";
13
+ import { FileReaderSync } from "./helpers/msw/read-file-sync";
14
14
  import { runInTempDir } from "./helpers/run-in-tmp";
15
15
  import { runWrangler } from "./helpers/run-wrangler";
16
16
  import type { Deployment, Project, UploadPayloadFile } from "../pages/types";
17
- import type { FormData, RequestInit } from "undici";
18
-
19
- // Asserting within mock responses get swallowed, so run them out-of-band
20
- const outOfBandTests: (() => void)[] = [];
21
- function assertLater(fn: () => void) {
22
- outOfBandTests.push(fn);
23
- }
17
+ import type { RestRequest } from "msw";
24
18
 
25
19
  function mockGetToken(jwt: string) {
26
- return setMockResponse(
27
- "/accounts/:accountId/pages/projects/foo/upload-token",
28
- async ([_url, accountId]) => {
29
- assertLater(() => {
30
- expect(accountId).toEqual("some-account-id");
31
- });
32
-
33
- return { jwt };
34
- }
20
+ msw.use(
21
+ rest.get(
22
+ "*/accounts/:accountId/pages/projects/foo/upload-token",
23
+ (req, res, ctx) => {
24
+ expect(req.params.accountId).toEqual("some-account-id");
25
+
26
+ return res(
27
+ ctx.status(200),
28
+ ctx.json({ success: true, errors: [], messages: [], result: { jwt } })
29
+ );
30
+ }
31
+ )
35
32
  );
36
33
  }
37
34
 
@@ -41,12 +38,6 @@ describe("pages", () => {
41
38
  function endEventLoop() {
42
39
  return new Promise((resolve) => setImmediate(resolve));
43
40
  }
44
- beforeEach(() => {
45
- outOfBandTests.length = 0;
46
- });
47
- afterEach(() => {
48
- outOfBandTests.forEach((fn) => fn());
49
- });
50
41
 
51
42
  beforeEach(() => {
52
43
  // @ts-expect-error we're using a very simple setTimeout mock here
@@ -54,6 +45,13 @@ describe("pages", () => {
54
45
  setImmediate(fn);
55
46
  });
56
47
  });
48
+ afterEach(async () => {
49
+ // Force a tick to ensure that all promises resolve
50
+ await endEventLoop();
51
+ // Reset MSW after tick to ensure that all requests have been handled
52
+ msw.resetHandlers();
53
+ msw.restoreHandlers();
54
+ });
57
55
 
58
56
  it("should should display a list of available subcommands, for pages with no subcommand", async () => {
59
57
  await runWrangler("pages");
@@ -124,28 +122,33 @@ describe("pages", () => {
124
122
  mockAccountId();
125
123
  mockApiToken();
126
124
 
127
- afterEach(() => {
128
- unsetAllMocks();
129
- });
130
-
131
125
  function mockListRequest(projects: unknown[]) {
132
126
  const requests = { count: 0 };
133
- setMockResponse(
134
- "/accounts/:accountId/pages/projects",
135
- ([_url, accountId], init, query) => {
136
- requests.count++;
137
- const pageSize = Number(query.get("per_page"));
138
- const page = Number(query.get("page"));
139
- const expectedPageSize = 10;
140
- const expectedPage = requests.count;
141
- assertLater(() => {
142
- expect(accountId).toEqual("some-account-id");
127
+ msw.use(
128
+ rest.get(
129
+ "*/accounts/:accountId/pages/projects",
130
+ async (req, res, ctx) => {
131
+ requests.count++;
132
+ const pageSize = Number(req.url.searchParams.get("per_page"));
133
+ const page = Number(req.url.searchParams.get("page"));
134
+ const expectedPageSize = 10;
135
+ const expectedPage = requests.count;
136
+ expect(req.params.accountId).toEqual("some-account-id");
143
137
  expect(pageSize).toEqual(expectedPageSize);
144
138
  expect(page).toEqual(expectedPage);
145
- expect(init).toEqual({});
146
- });
147
- return projects.slice((page - 1) * pageSize, page * pageSize);
148
- }
139
+ expect(await req.text()).toEqual("");
140
+
141
+ return res(
142
+ ctx.status(200),
143
+ ctx.json({
144
+ success: true,
145
+ errors: [],
146
+ messages: [],
147
+ result: projects.slice((page - 1) * pageSize, page * pageSize),
148
+ })
149
+ );
150
+ }
151
+ )
149
152
  );
150
153
  return requests;
151
154
  }
@@ -210,29 +213,34 @@ describe("pages", () => {
210
213
  mockAccountId();
211
214
  mockApiToken();
212
215
 
213
- afterEach(() => {
214
- unsetAllMocks();
215
- });
216
-
217
216
  it("should create a project with a production branch", async () => {
218
- setMockResponse(
219
- "/accounts/:accountId/pages/projects",
220
- ([_url, accountId], init) => {
221
- const body = JSON.parse(init.body as string);
222
- assertLater(() => {
223
- expect(accountId).toEqual("some-account-id");
224
- expect(init.method).toEqual("POST");
217
+ msw.use(
218
+ rest.post(
219
+ "*/accounts/:accountId/pages/projects",
220
+ async (req, res, ctx) => {
221
+ const body = await req.json();
222
+
223
+ expect(req.params.accountId).toEqual("some-account-id");
225
224
  expect(body).toEqual({
226
225
  name: "a-new-project",
227
226
  production_branch: "main",
228
227
  });
229
- });
230
- return {
231
- name: "a-new-project",
232
- subdomain: "a-new-project.pages.dev",
233
- production_branch: "main",
234
- };
235
- }
228
+
229
+ return res.once(
230
+ ctx.status(200),
231
+ ctx.json({
232
+ success: true,
233
+ errors: [],
234
+ messages: [],
235
+ result: {
236
+ name: "a-new-project",
237
+ subdomain: "a-new-project.pages.dev",
238
+ production_branch: "main",
239
+ },
240
+ })
241
+ );
242
+ }
243
+ )
236
244
  );
237
245
  await runWrangler(
238
246
  "pages project create a-new-project --production-branch=main"
@@ -248,21 +256,28 @@ describe("pages", () => {
248
256
  mockAccountId();
249
257
  mockApiToken();
250
258
 
251
- afterEach(() => {
252
- unsetAllMocks();
253
- });
254
259
  function mockListRequest(deployments: unknown[]) {
255
260
  const requests = { count: 0 };
256
- setMockResponse(
257
- "/accounts/:accountId/pages/projects/:project/deployments",
258
- ([_url, accountId, project]) => {
259
- requests.count++;
260
- assertLater(() => {
261
- expect(project).toEqual("images");
262
- expect(accountId).toEqual("some-account-id");
263
- });
264
- return deployments;
265
- }
261
+ msw.use(
262
+ rest.get(
263
+ "*/accounts/:accountId/pages/projects/:project/deployments",
264
+ (req, res, ctx) => {
265
+ requests.count++;
266
+
267
+ expect(req.params.project).toEqual("images");
268
+ expect(req.params.accountId).toEqual("some-account-id");
269
+
270
+ return res.once(
271
+ ctx.status(200),
272
+ ctx.json({
273
+ success: true,
274
+ errors: [],
275
+ messages: [],
276
+ result: deployments,
277
+ })
278
+ );
279
+ }
280
+ )
266
281
  );
267
282
  return requests;
268
283
  }
@@ -302,13 +317,13 @@ describe("pages", () => {
302
317
  mockApiToken();
303
318
  runInTempDir();
304
319
 
320
+ //TODO Abstract MSW handlers that repeat to this level - JACOB
305
321
  beforeEach(() => {
306
322
  actualProcessEnvCI = process.env.CI;
307
323
  process.env.CI = "true";
308
324
  });
309
325
 
310
326
  afterEach(() => {
311
- unsetAllMocks();
312
327
  process.env.CI = actualProcessEnvCI;
313
328
  });
314
329
 
@@ -343,33 +358,34 @@ describe("pages", () => {
343
358
 
344
359
  it("should upload a directory of files", async () => {
345
360
  writeFileSync("logo.png", "foobar");
346
-
347
361
  mockGetToken("<<funfetti-auth-jwt>>");
348
362
 
349
- setMockResponse(
350
- "/pages/assets/check-missing",
351
- "POST",
352
- async (_, init) => {
353
- const body = JSON.parse(init.body as string) as { hashes: string[] };
354
- assertLater(() => {
355
- expect(init.headers).toMatchObject({
356
- Authorization: "Bearer <<funfetti-auth-jwt>>",
357
- });
358
- expect(body).toMatchObject({
359
- hashes: ["2082190357cfd3617ccfe04f340c6247"],
360
- });
361
- });
362
- return body.hashes;
363
- }
364
- );
363
+ msw.use(
364
+ rest.post("*/pages/assets/check-missing", async (req, res, ctx) => {
365
+ const body = await req.json();
365
366
 
366
- setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
367
- assertLater(() => {
368
- expect(init.headers).toMatchObject({
369
- Authorization: "Bearer <<funfetti-auth-jwt>>",
367
+ expect(req.headers.get("Authorization")).toBe(
368
+ "Bearer <<funfetti-auth-jwt>>"
369
+ );
370
+ expect(body).toMatchObject({
371
+ hashes: ["2082190357cfd3617ccfe04f340c6247"],
370
372
  });
371
- const body = JSON.parse(init.body as string) as UploadPayloadFile[];
372
- expect(body).toMatchObject([
373
+
374
+ return res.once(
375
+ ctx.status(200),
376
+ ctx.json({
377
+ success: true,
378
+ errors: [],
379
+ messages: [],
380
+ result: body.hashes,
381
+ })
382
+ );
383
+ }),
384
+ rest.post("*/pages/assets/upload", async (req, res, ctx) => {
385
+ expect(req.headers.get("Authorization")).toMatchInlineSnapshot(
386
+ `"Bearer <<funfetti-auth-jwt>>"`
387
+ );
388
+ expect(await req.json()).toMatchObject([
373
389
  {
374
390
  key: "2082190357cfd3617ccfe04f340c6247",
375
391
  value: Buffer.from("foobar").toString("base64"),
@@ -379,39 +395,55 @@ describe("pages", () => {
379
395
  base64: true,
380
396
  },
381
397
  ]);
382
- });
383
- });
384
-
385
- setMockResponse(
386
- "/accounts/:accountId/pages/projects/foo/deployments",
387
- async ([_url, accountId], init) => {
388
- assertLater(() => {
389
- expect(accountId).toEqual("some-account-id");
390
- expect(init.method).toEqual("POST");
391
- const body = init.body as FormData;
392
- const manifest = JSON.parse(body.get("manifest") as string);
393
- expect(manifest).toMatchInlineSnapshot(`
394
- Object {
395
- "/logo.png": "2082190357cfd3617ccfe04f340c6247",
396
- }
397
- `);
398
- });
399
-
400
- return {
401
- url: "https://abcxyz.foo.pages.dev/",
402
- };
403
- }
404
- );
405
-
406
- setMockResponse(
407
- "/accounts/:accountId/pages/projects/foo",
408
- "GET",
409
- async ([_url, accountId]) => {
410
- assertLater(() => {
411
- expect(accountId).toEqual("some-account-id");
412
- });
413
- return { deployment_configs: { production: {}, preview: {} } };
398
+ return res.once(
399
+ ctx.status(200),
400
+ ctx.json({ success: true, errors: [], messages: [], result: null })
401
+ );
402
+ }),
403
+ rest.post(
404
+ "*/accounts/:accountId/pages/projects/foo/deployments",
405
+ async (req, res, ctx) => {
406
+ expect(req.params.accountId).toEqual("some-account-id");
407
+ expect(await (req as RestRequestWithFormData).formData())
408
+ .toMatchInlineSnapshot(`
409
+ FormData {
410
+ Symbol(state): Array [
411
+ Object {
412
+ "name": "manifest",
413
+ "value": "{\\"/logo.png\\":\\"2082190357cfd3617ccfe04f340c6247\\"}",
414
+ },
415
+ ],
414
416
  }
417
+ `);
418
+ return res.once(
419
+ ctx.status(200),
420
+ ctx.json({
421
+ success: true,
422
+ errors: [],
423
+ messages: [],
424
+ result: {
425
+ url: "https://abcxyz.foo.pages.dev/",
426
+ },
427
+ })
428
+ );
429
+ }
430
+ ),
431
+ rest.get(
432
+ "*/accounts/:accountId/pages/projects/foo",
433
+ async (req, res, ctx) => {
434
+ expect(req.params.accountId).toEqual("some-account-id");
435
+
436
+ return res.once(
437
+ ctx.status(200),
438
+ ctx.json({
439
+ success: true,
440
+ errors: [],
441
+ messages: [],
442
+ result: { deployment_configs: { production: {}, preview: {} } },
443
+ })
444
+ );
445
+ }
446
+ )
415
447
  );
416
448
 
417
449
  await runWrangler("pages publish . --project-name=foo");
@@ -428,84 +460,35 @@ describe("pages", () => {
428
460
 
429
461
  mockGetToken("<<funfetti-auth-jwt>>");
430
462
 
431
- setMockResponse(
432
- "/pages/assets/check-missing",
433
- "POST",
434
- async (_, init) => {
435
- const body = JSON.parse(init.body as string) as { hashes: string[] };
436
- assertLater(() => {
437
- expect(init.headers).toMatchObject({
438
- Authorization: "Bearer <<funfetti-auth-jwt>>",
439
- });
440
- expect(body).toMatchObject({
441
- hashes: ["1a98fb08af91aca4a7df1764a2c4ddb0"],
442
- });
443
- });
444
- return body.hashes;
445
- }
446
- );
447
-
448
463
  // Accumulate multiple requests then assert afterwards
449
- const requests: RequestInit[] = [];
450
- setMockRawResponse("/pages/assets/upload", "POST", async (_, init) => {
451
- requests.push(init);
452
-
453
- if (requests.length < 2) {
454
- return createFetchResult(null, false, [
455
- {
456
- code: 800000,
457
- message: "Something exploded, please retry",
458
- },
459
- ]);
460
- } else {
461
- return createFetchResult(null, true);
462
- }
463
- });
464
-
465
- setMockResponse(
466
- "/accounts/:accountId/pages/projects/foo/deployments",
467
- async ([_url, accountId], init) => {
468
- assertLater(() => {
469
- expect(accountId).toEqual("some-account-id");
470
- expect(init.method).toEqual("POST");
471
- const body = init.body as FormData;
472
- const manifest = JSON.parse(body.get("manifest") as string);
473
- expect(manifest).toMatchInlineSnapshot(`
474
- Object {
475
- "/logo.txt": "1a98fb08af91aca4a7df1764a2c4ddb0",
476
- }
477
- `);
478
- });
479
-
480
- return {
481
- url: "https://abcxyz.foo.pages.dev/",
482
- };
483
- }
484
- );
485
-
486
- setMockResponse(
487
- "/accounts/:accountId/pages/projects/foo",
488
- "GET",
489
- async ([_url, accountId]) => {
490
- assertLater(() => {
491
- expect(accountId).toEqual("some-account-id");
492
- });
493
- return { deployment_configs: { production: {}, preview: {} } };
494
- }
495
- );
496
-
497
- await runWrangler("pages publish . --project-name=foo");
464
+ const requests: RestRequest[] = [];
465
+ msw.use(
466
+ rest.post("*/pages/assets/check-missing", async (req, res, ctx) => {
467
+ const body = await req.json();
498
468
 
499
- // Assert two identical requests
500
- expect(requests.length).toBe(2);
501
- for (const init of requests) {
502
- assertLater(() => {
503
- expect(init.headers).toMatchObject({
504
- Authorization: "Bearer <<funfetti-auth-jwt>>",
469
+ expect(req.headers.get("Authorization")).toBe(
470
+ "Bearer <<funfetti-auth-jwt>>"
471
+ );
472
+ expect(body).toMatchObject({
473
+ hashes: ["1a98fb08af91aca4a7df1764a2c4ddb0"],
505
474
  });
506
475
 
507
- const body = JSON.parse(init.body as string) as UploadPayloadFile[];
508
- expect(body).toMatchObject([
476
+ return res.once(
477
+ ctx.status(200),
478
+ ctx.json({
479
+ success: true,
480
+ errors: [],
481
+ messages: [],
482
+ result: body.hashes,
483
+ })
484
+ );
485
+ }),
486
+ rest.post("*/pages/assets/upload", async (req, res, ctx) => {
487
+ requests.push(req);
488
+ expect(req.headers.get("Authorization")).toBe(
489
+ "Bearer <<funfetti-auth-jwt>>"
490
+ );
491
+ expect(await req.json()).toMatchObject([
509
492
  {
510
493
  key: "1a98fb08af91aca4a7df1764a2c4ddb0",
511
494
  value: Buffer.from("foobar").toString("base64"),
@@ -515,8 +498,80 @@ describe("pages", () => {
515
498
  base64: true,
516
499
  },
517
500
  ]);
518
- });
519
- }
501
+
502
+ if (requests.length < 2) {
503
+ return res(
504
+ ctx.status(200),
505
+ ctx.json({
506
+ success: false,
507
+ errors: [
508
+ {
509
+ code: 800000,
510
+ message: "Something exploded, please retry",
511
+ },
512
+ ],
513
+ messages: [],
514
+ result: null,
515
+ })
516
+ );
517
+ } else {
518
+ return res(
519
+ ctx.status(200),
520
+ ctx.json({
521
+ success: true,
522
+ errors: [],
523
+ messages: [],
524
+ result: null,
525
+ })
526
+ );
527
+ }
528
+ }),
529
+ rest.post(
530
+ "*/accounts/:accountId/pages/projects/foo/deployments",
531
+ async (req, res, ctx) => {
532
+ expect(req.params.accountId).toEqual("some-account-id");
533
+ expect(await (req as RestRequestWithFormData).formData())
534
+ .toMatchInlineSnapshot(`
535
+ FormData {
536
+ Symbol(state): Array [
537
+ Object {
538
+ "name": "manifest",
539
+ "value": "{\\"/logo.txt\\":\\"1a98fb08af91aca4a7df1764a2c4ddb0\\"}",
540
+ },
541
+ ],
542
+ }
543
+ `);
544
+
545
+ return res.once(
546
+ ctx.status(200),
547
+ ctx.json({
548
+ success: true,
549
+ errors: [],
550
+ messages: [],
551
+ result: { url: "https://abcxyz.foo.pages.dev/" },
552
+ })
553
+ );
554
+ }
555
+ ),
556
+ rest.get(
557
+ "*/accounts/:accountId/pages/projects/foo",
558
+ async (req, res, ctx) => {
559
+ expect(req.params.accountId).toEqual("some-account-id");
560
+
561
+ return res.once(
562
+ ctx.status(200),
563
+ ctx.json({
564
+ success: true,
565
+ errors: [],
566
+ messages: [],
567
+ result: { deployment_configs: { production: {}, preview: {} } },
568
+ })
569
+ );
570
+ }
571
+ )
572
+ );
573
+
574
+ await runWrangler("pages publish . --project-name=foo");
520
575
 
521
576
  expect(std.out).toMatchInlineSnapshot(`
522
577
  "✨ Success! Uploaded 1 files (TIMINGS)
@@ -527,104 +582,125 @@ describe("pages", () => {
527
582
 
528
583
  it("should refetch a JWT if it expires while uploading", async () => {
529
584
  writeFileSync("logo.txt", "foobar");
585
+ mockGetToken("<<funfetti-auth-jwt>>");
530
586
 
531
- const cancelMockGetToken = mockGetToken("<<funfetti-auth-jwt>>");
587
+ const requests: RestRequest[] = [];
588
+ msw.use(
589
+ rest.post("*/pages/assets/check-missing", async (req, res, ctx) => {
590
+ const body = (await req.json()) as { hashes: string[] };
532
591
 
533
- setMockResponse(
534
- "/pages/assets/check-missing",
535
- "POST",
536
- async (_, init) => {
537
- const body = JSON.parse(init.body as string) as { hashes: string[] };
538
- assertLater(() => {
539
- expect(init.headers).toMatchObject({
540
- Authorization: "Bearer <<funfetti-auth-jwt>>",
541
- });
542
- expect(body).toMatchObject({
543
- hashes: ["1a98fb08af91aca4a7df1764a2c4ddb0"],
544
- });
592
+ expect(req.headers.get("Authorization")).toBe(
593
+ "Bearer <<funfetti-auth-jwt>>"
594
+ );
595
+ expect(body).toMatchObject({
596
+ hashes: ["1a98fb08af91aca4a7df1764a2c4ddb0"],
545
597
  });
546
- return body.hashes;
547
- }
548
- );
549
598
 
550
- // Accumulate multiple requests then assert afterwards
551
- const requests: RequestInit[] = [];
552
- setMockRawResponse("/pages/assets/upload", "POST", async (_, init) => {
553
- requests.push(init);
554
-
555
- // Fail just the first request
556
- if (requests.length < 2) {
557
- cancelMockGetToken();
558
- mockGetToken("<<funfetti-auth-jwt2>>");
559
- return createFetchResult(null, false, [
599
+ return res.once(
600
+ ctx.status(200),
601
+ ctx.json({
602
+ success: true,
603
+ errors: [],
604
+ messages: [],
605
+ result: body.hashes,
606
+ })
607
+ );
608
+ }),
609
+ rest.post("*/pages/assets/upload", async (req, res, ctx) => {
610
+ requests.push(req);
611
+ expect(await req.json()).toMatchObject([
560
612
  {
561
- code: 8000013,
562
- message: "Authorization failed",
613
+ key: "1a98fb08af91aca4a7df1764a2c4ddb0",
614
+ value: Buffer.from("foobar").toString("base64"),
615
+ metadata: {
616
+ contentType: "text/plain",
617
+ },
618
+ base64: true,
563
619
  },
564
620
  ]);
565
- } else {
566
- return createFetchResult(null, true);
567
- }
568
- });
569
-
570
- setMockResponse(
571
- "/accounts/:accountId/pages/projects/foo/deployments",
572
- async ([_url, accountId], init) => {
573
- assertLater(() => {
574
- expect(accountId).toEqual("some-account-id");
575
- expect(init.method).toEqual("POST");
576
- const body = init.body as FormData;
577
- const manifest = JSON.parse(body.get("manifest") as string);
578
- expect(manifest).toMatchInlineSnapshot(`
579
- Object {
580
- "/logo.txt": "1a98fb08af91aca4a7df1764a2c4ddb0",
581
- }
582
- `);
583
- });
584
-
585
- return {
586
- url: "https://abcxyz.foo.pages.dev/",
587
- };
621
+ // Fail just the first request
622
+ if (requests.length < 2) {
623
+ mockGetToken("<<funfetti-auth-jwt2>>");
624
+ return res(
625
+ ctx.status(200),
626
+ ctx.json({
627
+ success: false,
628
+ errors: [
629
+ {
630
+ code: 8000013,
631
+ message: "Authorization failed",
632
+ },
633
+ ],
634
+ messages: [],
635
+ result: null,
636
+ })
637
+ );
638
+ } else {
639
+ return res(
640
+ ctx.status(200),
641
+ ctx.json({
642
+ success: true,
643
+ errors: [],
644
+ messages: [],
645
+ result: null,
646
+ })
647
+ );
648
+ }
649
+ }),
650
+ rest.post(
651
+ "*/accounts/:accountId/pages/projects/foo/deployments",
652
+ async (req, res, ctx) => {
653
+ expect(req.params.accountId).toEqual("some-account-id");
654
+ expect(await (req as RestRequestWithFormData).formData())
655
+ .toMatchInlineSnapshot(`
656
+ FormData {
657
+ Symbol(state): Array [
658
+ Object {
659
+ "name": "manifest",
660
+ "value": "{\\"/logo.txt\\":\\"1a98fb08af91aca4a7df1764a2c4ddb0\\"}",
661
+ },
662
+ ],
588
663
  }
589
- );
664
+ `);
590
665
 
591
- setMockResponse(
592
- "/accounts/:accountId/pages/projects/foo",
593
- "GET",
594
- async ([_url, accountId]) => {
595
- assertLater(() => {
596
- expect(accountId).toEqual("some-account-id");
597
- });
598
- return { deployment_configs: { production: {}, preview: {} } };
599
- }
666
+ return res.once(
667
+ ctx.status(200),
668
+ ctx.json({
669
+ success: true,
670
+ errors: [],
671
+ messages: [],
672
+ result: { url: "https://abcxyz.foo.pages.dev/" },
673
+ })
674
+ );
675
+ }
676
+ ),
677
+ rest.get(
678
+ "*/accounts/:accountId/pages/projects/foo",
679
+ async (req, res, ctx) => {
680
+ expect(req.params.accountId).toEqual("some-account-id");
681
+
682
+ return res.once(
683
+ ctx.status(200),
684
+ ctx.json({
685
+ success: true,
686
+ errors: [],
687
+ messages: [],
688
+ result: { deployment_configs: { production: {}, preview: {} } },
689
+ })
690
+ );
691
+ }
692
+ )
600
693
  );
601
694
 
602
695
  await runWrangler("pages publish . --project-name=foo");
603
696
 
604
- // Assert two requests
605
- expect(requests.length).toBe(2);
606
-
607
- expect(requests[0].headers).toMatchObject({
608
- Authorization: "Bearer <<funfetti-auth-jwt>>",
609
- });
610
-
611
- expect(requests[1].headers).toMatchObject({
612
- Authorization: "Bearer <<funfetti-auth-jwt2>>",
613
- });
697
+ expect(requests[0].headers.get("Authorization")).toBe(
698
+ "Bearer <<funfetti-auth-jwt>>"
699
+ );
614
700
 
615
- for (const init of requests) {
616
- const body = JSON.parse(init.body as string) as UploadPayloadFile[];
617
- expect(body).toMatchObject([
618
- {
619
- key: "1a98fb08af91aca4a7df1764a2c4ddb0",
620
- value: Buffer.from("foobar").toString("base64"),
621
- metadata: {
622
- contentType: "text/plain",
623
- },
624
- base64: true,
625
- },
626
- ]);
627
- }
701
+ expect(requests[1].headers.get("Authorization")).toBe(
702
+ "Bearer <<funfetti-auth-jwt2>>"
703
+ );
628
704
 
629
705
  expect(std.out).toMatchInlineSnapshot(`
630
706
  "✨ Success! Uploaded 1 files (TIMINGS)
@@ -641,80 +717,110 @@ describe("pages", () => {
641
717
 
642
718
  mockGetToken("<<funfetti-auth-jwt>>");
643
719
 
644
- setMockResponse(
645
- "/pages/assets/check-missing",
646
- "POST",
647
- async (_, init) => {
648
- const body = JSON.parse(init.body as string) as { hashes: string[] };
649
- assertLater(() => {
650
- expect(init.headers).toMatchObject({
651
- Authorization: "Bearer <<funfetti-auth-jwt>>",
652
- });
653
- expect(body).toMatchObject({
654
- hashes: expect.arrayContaining([
655
- "d96fef225537c9f5e44a3cb27fd0b492",
656
- "2082190357cfd3617ccfe04f340c6247",
657
- "6be321bef99e758250dac034474ddbb8",
658
- "1a98fb08af91aca4a7df1764a2c4ddb0",
659
- ]),
660
- });
661
- });
662
- return body.hashes;
663
- }
664
- );
665
-
666
720
  // Accumulate multiple requests then assert afterwards
667
- const requests: RequestInit[] = [];
668
- setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
669
- requests.push(init);
670
- });
721
+ const requests: RestRequest[] = [];
722
+ const bodies: UploadPayloadFile[][] = [];
723
+ msw.use(
724
+ rest.post("*/pages/assets/check-missing", async (req, res, ctx) => {
725
+ const body = (await req.json()) as {
726
+ hashes: string[];
727
+ };
671
728
 
672
- setMockResponse(
673
- "/accounts/:accountId/pages/projects/foo/deployments",
674
- async ([_url, accountId], init) => {
675
- assertLater(() => {
676
- expect(accountId).toEqual("some-account-id");
677
- expect(init.method).toEqual("POST");
678
- const body = init.body as FormData;
679
- const manifest = JSON.parse(body.get("manifest") as string);
680
- expect(manifest).toMatchInlineSnapshot(`
681
- Object {
682
- "/logo.html": "d96fef225537c9f5e44a3cb27fd0b492",
683
- "/logo.js": "6be321bef99e758250dac034474ddbb8",
684
- "/logo.png": "2082190357cfd3617ccfe04f340c6247",
685
- "/logo.txt": "1a98fb08af91aca4a7df1764a2c4ddb0",
686
- }
687
- `);
729
+ expect(req.headers.get("Authorization")).toBe(
730
+ "Bearer <<funfetti-auth-jwt>>"
731
+ );
732
+ expect(body).toMatchObject({
733
+ hashes: expect.arrayContaining([
734
+ "d96fef225537c9f5e44a3cb27fd0b492",
735
+ "2082190357cfd3617ccfe04f340c6247",
736
+ "6be321bef99e758250dac034474ddbb8",
737
+ "1a98fb08af91aca4a7df1764a2c4ddb0",
738
+ ]),
688
739
  });
689
740
 
690
- return {
691
- url: "https://abcxyz.foo.pages.dev/",
692
- };
693
- }
694
- );
741
+ return res.once(
742
+ ctx.status(200),
743
+ ctx.json({
744
+ success: true,
745
+ errors: [],
746
+ messages: [],
747
+ result: body.hashes,
748
+ })
749
+ );
750
+ }),
751
+ rest.post("*/pages/assets/upload", async (req, res, ctx) => {
752
+ requests.push(req);
695
753
 
696
- setMockResponse(
697
- "/accounts/:accountId/pages/projects/foo",
698
- "GET",
699
- async ([_url, accountId]) => {
700
- assertLater(() => {
701
- expect(accountId).toEqual("some-account-id");
702
- });
703
- return { deployment_configs: { production: {}, preview: {} } };
704
- }
754
+ expect(req.headers.get("Authorization")).toBe(
755
+ "Bearer <<funfetti-auth-jwt>>"
756
+ );
757
+ bodies.push((await req.json()) as UploadPayloadFile[]);
758
+
759
+ return res(
760
+ ctx.status(200),
761
+ ctx.json({
762
+ success: true,
763
+ errors: [],
764
+ messages: [],
765
+ result: null,
766
+ })
767
+ );
768
+ }),
769
+ rest.post(
770
+ "*/accounts/:accountId/pages/projects/foo/deployments",
771
+ async (req, res, ctx) => {
772
+ expect(req.params.accountId).toEqual("some-account-id");
773
+
774
+ const body = await (req as RestRequestWithFormData).formData();
775
+ const manifest = JSON.parse(body.get("manifest") as string);
776
+
777
+ expect(manifest).toMatchInlineSnapshot(`
778
+ Object {
779
+ "/logo.html": "d96fef225537c9f5e44a3cb27fd0b492",
780
+ "/logo.js": "6be321bef99e758250dac034474ddbb8",
781
+ "/logo.png": "2082190357cfd3617ccfe04f340c6247",
782
+ "/logo.txt": "1a98fb08af91aca4a7df1764a2c4ddb0",
783
+ }
784
+ `);
785
+
786
+ return res.once(
787
+ ctx.status(200),
788
+ ctx.json({
789
+ success: true,
790
+ errors: [],
791
+ messages: [],
792
+ result: {
793
+ url: "https://abcxyz.foo.pages.dev/",
794
+ },
795
+ })
796
+ );
797
+ }
798
+ ),
799
+ rest.get(
800
+ "*/accounts/:accountId/pages/projects/foo",
801
+ async (req, res, ctx) => {
802
+ expect(req.params.accountId).toEqual("some-account-id");
803
+
804
+ return res.once(
805
+ ctx.status(200),
806
+ ctx.json({
807
+ success: true,
808
+ errors: [],
809
+ messages: [],
810
+ result: {
811
+ deployment_configs: { production: {}, preview: {} },
812
+ },
813
+ })
814
+ );
815
+ }
816
+ )
705
817
  );
706
818
 
707
819
  await runWrangler("pages publish . --project-name=foo");
708
820
 
709
821
  // We have 3 buckets, so expect 3 uploads
710
822
  expect(requests.length).toBe(3);
711
- const bodies: UploadPayloadFile[][] = [];
712
- for (const init of requests) {
713
- expect(init.headers).toMatchObject({
714
- Authorization: "Bearer <<funfetti-auth-jwt>>",
715
- });
716
- bodies.push(JSON.parse(init.body as string) as UploadPayloadFile[]);
717
- }
823
+
718
824
  // One bucket should end up with 2 files
719
825
  expect(bodies.map((b) => b.length).sort()).toEqual([1, 1, 2]);
720
826
  // But we don't know the order, so flatten and test without ordering
@@ -764,82 +870,105 @@ describe("pages", () => {
764
870
 
765
871
  mockGetToken("<<funfetti-auth-jwt>>");
766
872
 
767
- setMockResponse(
768
- "/pages/assets/check-missing",
769
- "POST",
770
- async (_, init) => {
771
- const body = JSON.parse(init.body as string) as {
873
+ // Accumulate multiple requests then assert afterwards
874
+ const requests: RestRequest[] = [];
875
+ const bodies: UploadPayloadFile[][] = [];
876
+ msw.use(
877
+ rest.post("*/pages/assets/check-missing", async (req, res, ctx) => {
878
+ const body = (await req.json()) as {
772
879
  hashes: string[];
773
880
  };
774
- assertLater(() => {
775
- expect(init.headers).toMatchObject({
776
- Authorization: "Bearer <<funfetti-auth-jwt>>",
777
- });
778
- expect(body).toMatchObject({
779
- hashes: expect.arrayContaining([
780
- "d96fef225537c9f5e44a3cb27fd0b492",
781
- "2082190357cfd3617ccfe04f340c6247",
782
- "6be321bef99e758250dac034474ddbb8",
783
- "1a98fb08af91aca4a7df1764a2c4ddb0",
784
- ]),
785
- });
881
+
882
+ expect(req.headers.get("Authorization")).toBe(
883
+ "Bearer <<funfetti-auth-jwt>>"
884
+ );
885
+ expect(body).toMatchObject({
886
+ hashes: expect.arrayContaining([
887
+ "d96fef225537c9f5e44a3cb27fd0b492",
888
+ "2082190357cfd3617ccfe04f340c6247",
889
+ "6be321bef99e758250dac034474ddbb8",
890
+ "1a98fb08af91aca4a7df1764a2c4ddb0",
891
+ ]),
786
892
  });
787
- return body.hashes;
788
- }
789
- );
790
893
 
791
- // Accumulate multiple requests then assert afterwards
792
- const requests: RequestInit[] = [];
793
- setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
794
- requests.push(init);
795
- });
894
+ return res.once(
895
+ ctx.status(200),
896
+ ctx.json({
897
+ success: true,
898
+ errors: [],
899
+ messages: [],
900
+ result: body.hashes,
901
+ })
902
+ );
903
+ }),
904
+ rest.post("*/pages/assets/upload", async (req, res, ctx) => {
905
+ requests.push(req);
796
906
 
797
- setMockResponse(
798
- "/accounts/:accountId/pages/projects/foo/deployments",
799
- async ([_url, accountId], init) => {
800
- assertLater(() => {
801
- expect(accountId).toEqual("some-account-id");
802
- expect(init.method).toEqual("POST");
803
- const body = init.body as FormData;
907
+ expect(req.headers.get("Authorization")).toBe(
908
+ "Bearer <<funfetti-auth-jwt>>"
909
+ );
910
+ bodies.push((await req.json()) as UploadPayloadFile[]);
911
+
912
+ return res(
913
+ ctx.status(200),
914
+ ctx.json({
915
+ success: true,
916
+ errors: [],
917
+ messages: [],
918
+ result: null,
919
+ })
920
+ );
921
+ }),
922
+ rest.post(
923
+ "*/accounts/:accountId/pages/projects/foo/deployments",
924
+ async (req, res, ctx) => {
925
+ expect(req.params.accountId).toEqual("some-account-id");
926
+ const body = await (req as RestRequestWithFormData).formData();
804
927
  const manifest = JSON.parse(body.get("manifest") as string);
805
928
  expect(manifest).toMatchInlineSnapshot(`
806
- Object {
807
- "/imgs/logo.png": "2082190357cfd3617ccfe04f340c6247",
808
- "/logo.html": "d96fef225537c9f5e44a3cb27fd0b492",
809
- "/logo.js": "6be321bef99e758250dac034474ddbb8",
810
- "/logo.txt": "1a98fb08af91aca4a7df1764a2c4ddb0",
811
- }
812
- `);
813
- });
814
-
815
- return {
816
- url: "https://abcxyz.foo.pages.dev/",
817
- };
818
- }
819
- );
820
-
821
- setMockResponse(
822
- "/accounts/:accountId/pages/projects/foo",
823
- "GET",
824
- async ([_url, accountId]) => {
825
- assertLater(() => {
826
- expect(accountId).toEqual("some-account-id");
827
- });
828
- return { deployment_configs: { production: {}, preview: {} } };
829
- }
929
+ Object {
930
+ "/imgs/logo.png": "2082190357cfd3617ccfe04f340c6247",
931
+ "/logo.html": "d96fef225537c9f5e44a3cb27fd0b492",
932
+ "/logo.js": "6be321bef99e758250dac034474ddbb8",
933
+ "/logo.txt": "1a98fb08af91aca4a7df1764a2c4ddb0",
934
+ }
935
+ `);
936
+
937
+ return res.once(
938
+ ctx.status(200),
939
+ ctx.json({
940
+ success: true,
941
+ errors: [],
942
+ messages: [],
943
+ result: { url: "https://abcxyz.foo.pages.dev/" },
944
+ })
945
+ );
946
+ }
947
+ ),
948
+ rest.get(
949
+ "*/accounts/:accountId/pages/projects/foo",
950
+ async (req, res, ctx) => {
951
+ expect(req.params.accountId).toEqual("some-account-id");
952
+
953
+ return res.once(
954
+ ctx.status(200),
955
+ ctx.json({
956
+ success: true,
957
+ errors: [],
958
+ messages: [],
959
+ result: {
960
+ deployment_configs: { production: {}, preview: {} },
961
+ },
962
+ })
963
+ );
964
+ }
965
+ )
830
966
  );
831
967
 
832
968
  await runWrangler(`pages publish public --project-name=foo`);
833
969
 
834
970
  // We have 3 buckets, so expect 3 uploads
835
971
  expect(requests.length).toBe(3);
836
- const bodies: UploadPayloadFile[][] = [];
837
- for (const init of requests) {
838
- expect(init.headers).toMatchObject({
839
- Authorization: "Bearer <<funfetti-auth-jwt>>",
840
- });
841
- bodies.push(JSON.parse(init.body as string) as UploadPayloadFile[]);
842
- }
843
972
  // One bucket should end up with 2 files
844
973
  expect(bodies.map((b) => b.length).sort()).toEqual([1, 1, 2]);
845
974
  // But we don't know the order, so flatten and test without ordering
@@ -889,83 +1018,106 @@ describe("pages", () => {
889
1018
 
890
1019
  mockGetToken("<<funfetti-auth-jwt>>");
891
1020
 
892
- setMockResponse(
893
- "/pages/assets/check-missing",
894
- "POST",
895
- async (_, init) => {
896
- const body = JSON.parse(init.body as string) as {
1021
+ // Accumulate multiple requests then assert afterwards
1022
+ const requests: RestRequest[] = [];
1023
+ const bodies: UploadPayloadFile[][] = [];
1024
+ msw.use(
1025
+ rest.post("*/pages/assets/check-missing", async (req, res, ctx) => {
1026
+ const body = (await req.json()) as {
897
1027
  hashes: string[];
898
1028
  };
899
- assertLater(() => {
900
- expect(init.headers).toMatchObject({
901
- Authorization: "Bearer <<funfetti-auth-jwt>>",
902
- });
903
- expect(body).toMatchObject({
904
- hashes: expect.arrayContaining([
905
- "d96fef225537c9f5e44a3cb27fd0b492",
906
- "2082190357cfd3617ccfe04f340c6247",
907
- "6be321bef99e758250dac034474ddbb8",
908
- "1a98fb08af91aca4a7df1764a2c4ddb0",
909
- ]),
910
- });
1029
+
1030
+ expect(req.headers.get("Authorization")).toBe(
1031
+ "Bearer <<funfetti-auth-jwt>>"
1032
+ );
1033
+ expect(body).toMatchObject({
1034
+ hashes: expect.arrayContaining([
1035
+ "d96fef225537c9f5e44a3cb27fd0b492",
1036
+ "2082190357cfd3617ccfe04f340c6247",
1037
+ "6be321bef99e758250dac034474ddbb8",
1038
+ "1a98fb08af91aca4a7df1764a2c4ddb0",
1039
+ ]),
911
1040
  });
912
- return body.hashes;
913
- }
914
- );
915
1041
 
916
- // Accumulate multiple requests then assert afterwards
917
- const requests: RequestInit[] = [];
918
- setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
919
- requests.push(init);
920
- });
1042
+ return res.once(
1043
+ ctx.status(200),
1044
+ ctx.json({
1045
+ success: true,
1046
+ errors: [],
1047
+ messages: [],
1048
+ result: body.hashes,
1049
+ })
1050
+ );
1051
+ }),
1052
+ rest.post("*/pages/assets/upload", async (req, res, ctx) => {
1053
+ requests.push(req);
1054
+
1055
+ expect(req.headers.get("Authorization")).toBe(
1056
+ "Bearer <<funfetti-auth-jwt>>"
1057
+ );
1058
+ bodies.push((await req.json()) as UploadPayloadFile[]);
1059
+
1060
+ return res(
1061
+ ctx.status(200),
1062
+ ctx.json({
1063
+ success: true,
1064
+ errors: [],
1065
+ messages: [],
1066
+ result: null,
1067
+ })
1068
+ );
1069
+ }),
1070
+ rest.post(
1071
+ "*/accounts/:accountId/pages/projects/foo/deployments",
1072
+ async (req, res, ctx) => {
1073
+ expect(req.params.accountId).toEqual("some-account-id");
921
1074
 
922
- setMockResponse(
923
- "/accounts/:accountId/pages/projects/foo/deployments",
924
- async ([_url, accountId], init) => {
925
- assertLater(() => {
926
- expect(accountId).toEqual("some-account-id");
927
- expect(init.method).toEqual("POST");
928
- const body = init.body as FormData;
1075
+ const body = await (req as RestRequestWithFormData).formData();
929
1076
  const manifest = JSON.parse(body.get("manifest") as string);
930
1077
  expect(manifest).toMatchInlineSnapshot(`
931
- Object {
932
- "/imgs/logo.png": "2082190357cfd3617ccfe04f340c6247",
933
- "/logo.html": "d96fef225537c9f5e44a3cb27fd0b492",
934
- "/logo.js": "6be321bef99e758250dac034474ddbb8",
935
- "/logo.txt": "1a98fb08af91aca4a7df1764a2c4ddb0",
936
- }
937
- `);
938
- });
939
-
940
- return {
941
- url: "https://abcxyz.foo.pages.dev/",
942
- };
943
- }
944
- );
945
-
946
- setMockResponse(
947
- "/accounts/:accountId/pages/projects/foo",
948
- "GET",
949
- async ([_url, accountId]) => {
950
- assertLater(() => {
951
- expect(accountId).toEqual("some-account-id");
952
- });
953
- return { deployment_configs: { production: {}, preview: {} } };
954
- }
1078
+ Object {
1079
+ "/imgs/logo.png": "2082190357cfd3617ccfe04f340c6247",
1080
+ "/logo.html": "d96fef225537c9f5e44a3cb27fd0b492",
1081
+ "/logo.js": "6be321bef99e758250dac034474ddbb8",
1082
+ "/logo.txt": "1a98fb08af91aca4a7df1764a2c4ddb0",
1083
+ }
1084
+ `);
1085
+
1086
+ return res.once(
1087
+ ctx.status(200),
1088
+ ctx.json({
1089
+ success: true,
1090
+ errors: [],
1091
+ messages: [],
1092
+ result: { url: "https://abcxyz.foo.pages.dev/" },
1093
+ })
1094
+ );
1095
+ }
1096
+ ),
1097
+ rest.get(
1098
+ "*/accounts/:accountId/pages/projects/foo",
1099
+ async (req, res, ctx) => {
1100
+ expect(req.params.accountId).toEqual("some-account-id");
1101
+
1102
+ return res.once(
1103
+ ctx.status(200),
1104
+ ctx.json({
1105
+ success: true,
1106
+ errors: [],
1107
+ messages: [],
1108
+ result: {
1109
+ deployment_configs: { production: {}, preview: {} },
1110
+ },
1111
+ })
1112
+ );
1113
+ }
1114
+ )
955
1115
  );
956
1116
 
957
1117
  chdir("public");
958
1118
  await runWrangler(`pages publish . --project-name=foo`);
959
-
960
1119
  // We have 3 buckets, so expect 3 uploads
961
1120
  expect(requests.length).toBe(3);
962
- const bodies: UploadPayloadFile[][] = [];
963
- for (const init of requests) {
964
- expect(init.headers).toMatchObject({
965
- Authorization: "Bearer <<funfetti-auth-jwt>>",
966
- });
967
- bodies.push(JSON.parse(init.body as string) as UploadPayloadFile[]);
968
- }
969
1121
  // One bucket should end up with 2 files
970
1122
  expect(bodies.map((b) => b.length).sort()).toEqual([1, 1, 2]);
971
1123
  // But we don't know the order, so flatten and test without ordering
@@ -1013,29 +1165,35 @@ describe("pages", () => {
1013
1165
 
1014
1166
  mockGetToken("<<funfetti-auth-jwt>>");
1015
1167
 
1016
- setMockResponse(
1017
- "/pages/assets/check-missing",
1018
- "POST",
1019
- async (_, init) => {
1020
- const body = JSON.parse(init.body as string) as { hashes: string[] };
1021
- assertLater(() => {
1022
- expect(init.headers).toMatchObject({
1023
- Authorization: "Bearer <<funfetti-auth-jwt>>",
1024
- });
1025
- expect(body).toMatchObject({
1026
- hashes: ["7b764dacfd211bebd8077828a7ddefd7"],
1027
- });
1028
- });
1029
- return body.hashes;
1030
- }
1031
- );
1168
+ msw.use(
1169
+ rest.post("*/pages/assets/check-missing", async (req, res, ctx) => {
1170
+ const body = (await req.json()) as {
1171
+ hashes: string[];
1172
+ };
1032
1173
 
1033
- setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
1034
- assertLater(() => {
1035
- expect(init.headers).toMatchObject({
1036
- Authorization: "Bearer <<funfetti-auth-jwt>>",
1174
+ expect(req.headers.get("Authorization")).toBe(
1175
+ "Bearer <<funfetti-auth-jwt>>"
1176
+ );
1177
+ expect(body).toMatchObject({
1178
+ hashes: ["7b764dacfd211bebd8077828a7ddefd7"],
1037
1179
  });
1038
- const body = JSON.parse(init.body as string) as UploadPayloadFile[];
1180
+
1181
+ return res.once(
1182
+ ctx.status(200),
1183
+ ctx.json({
1184
+ success: true,
1185
+ errors: [],
1186
+ messages: [],
1187
+ result: body.hashes,
1188
+ })
1189
+ );
1190
+ }),
1191
+
1192
+ rest.post("*/pages/assets/upload", async (req, res, ctx) => {
1193
+ expect(req.headers.get("Authorization")).toBe(
1194
+ "Bearer <<funfetti-auth-jwt>>"
1195
+ );
1196
+ const body = (await req.json()) as UploadPayloadFile[];
1039
1197
  expect(body).toMatchObject([
1040
1198
  {
1041
1199
  key: "7b764dacfd211bebd8077828a7ddefd7",
@@ -1046,25 +1204,50 @@ describe("pages", () => {
1046
1204
  base64: true,
1047
1205
  },
1048
1206
  ]);
1049
- });
1050
- });
1051
-
1052
- setMockResponse(
1053
- "/accounts/:accountId/pages/projects/foo/deployments",
1054
- async () => ({
1055
- url: "https://abcxyz.foo.pages.dev/",
1056
- })
1057
- );
1058
-
1059
- setMockResponse(
1060
- "/accounts/:accountId/pages/projects/foo",
1061
- "GET",
1062
- async ([_url, accountId]) => {
1063
- assertLater(() => {
1064
- expect(accountId).toEqual("some-account-id");
1065
- });
1066
- return { deployment_configs: { production: {}, preview: {} } };
1067
- }
1207
+ return res.once(
1208
+ ctx.status(200),
1209
+ ctx.json({
1210
+ success: true,
1211
+ errors: [],
1212
+ messages: [],
1213
+ result: null,
1214
+ })
1215
+ );
1216
+ }),
1217
+ rest.post(
1218
+ "*/accounts/:accountId/pages/projects/foo/deployments",
1219
+ async (req, res, ctx) => {
1220
+ expect(req.params.accountId).toEqual("some-account-id");
1221
+
1222
+ return res.once(
1223
+ ctx.status(200),
1224
+ ctx.json({
1225
+ success: true,
1226
+ errors: [],
1227
+ messages: [],
1228
+ result: { url: "https://abcxyz.foo.pages.dev/" },
1229
+ })
1230
+ );
1231
+ }
1232
+ ),
1233
+ rest.get(
1234
+ "*/accounts/:accountId/pages/projects/foo",
1235
+ async (req, res, ctx) => {
1236
+ expect(req.params.accountId).toEqual("some-account-id");
1237
+
1238
+ return res.once(
1239
+ ctx.status(200),
1240
+ ctx.json({
1241
+ success: true,
1242
+ errors: [],
1243
+ messages: [],
1244
+ result: {
1245
+ deployment_configs: { production: {}, preview: {} },
1246
+ },
1247
+ })
1248
+ );
1249
+ }
1250
+ )
1068
1251
  );
1069
1252
 
1070
1253
  await runWrangler("pages publish . --project-name=foo");
@@ -1103,30 +1286,35 @@ describe("pages", () => {
1103
1286
 
1104
1287
  mockGetToken("<<funfetti-auth-jwt>>");
1105
1288
 
1106
- setMockResponse(
1107
- "/pages/assets/check-missing",
1108
- "POST",
1109
- async (_, init) => {
1110
- const body = JSON.parse(init.body as string) as { hashes: string[] };
1111
- assertLater(() => {
1112
- expect(init.headers).toMatchObject({
1113
- Authorization: "Bearer <<funfetti-auth-jwt>>",
1114
- });
1115
- expect(body).toMatchObject({
1116
- hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1117
- });
1118
- });
1119
- return body.hashes;
1120
- }
1121
- );
1289
+ msw.use(
1290
+ rest.post("*/pages/assets/check-missing", async (req, res, ctx) => {
1291
+ const body = (await req.json()) as {
1292
+ hashes: string[];
1293
+ };
1122
1294
 
1123
- setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
1124
- assertLater(() => {
1125
- expect(init.headers).toMatchObject({
1126
- Authorization: "Bearer <<funfetti-auth-jwt>>",
1295
+ expect(req.headers.get("Authorization")).toBe(
1296
+ "Bearer <<funfetti-auth-jwt>>"
1297
+ );
1298
+ expect(body).toMatchObject({
1299
+ hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1127
1300
  });
1128
- const body = JSON.parse(init.body as string) as UploadPayloadFile[];
1129
- expect(body).toMatchObject([
1301
+
1302
+ return res.once(
1303
+ ctx.status(200),
1304
+ ctx.json({
1305
+ success: true,
1306
+ errors: [],
1307
+ messages: [],
1308
+ result: body.hashes,
1309
+ })
1310
+ );
1311
+ }),
1312
+ rest.post("*/pages/assets/upload", async (req, res, ctx) => {
1313
+ expect(req.headers.get("Authorization")).toBe(
1314
+ "Bearer <<funfetti-auth-jwt>>"
1315
+ );
1316
+
1317
+ expect(await req.json()).toMatchObject([
1130
1318
  {
1131
1319
  key: "13a03eaf24ae98378acd36ea00f77f2f",
1132
1320
  value: Buffer.from("This is a readme").toString("base64"),
@@ -1136,46 +1324,51 @@ describe("pages", () => {
1136
1324
  base64: true,
1137
1325
  },
1138
1326
  ]);
1139
- });
1140
- });
1327
+ return res.once(
1328
+ ctx.status(200),
1329
+ ctx.json({
1330
+ success: true,
1331
+ errors: [],
1332
+ messages: [],
1333
+ result: true,
1334
+ })
1335
+ );
1336
+ }),
1337
+ rest.post(`*/pages/assets/upsert-hashes`, async (req, res, ctx) => {
1338
+ expect(req.headers.get("Authorization")).toBe(
1339
+ "Bearer <<funfetti-auth-jwt>>"
1340
+ );
1141
1341
 
1142
- setMockResponse(
1143
- `/pages/assets/upsert-hashes`,
1144
- "POST",
1145
- async (_, init) => {
1146
- assertLater(() => {
1147
- expect(init.headers).toMatchObject({
1148
- Authorization: "Bearer <<funfetti-auth-jwt>>",
1149
- });
1150
- const body = JSON.parse(init.body as string) as UploadPayloadFile[];
1151
- expect(body).toMatchObject({
1152
- hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1153
- });
1342
+ expect(await req.json()).toMatchObject({
1343
+ hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1154
1344
  });
1155
1345
 
1156
- return Promise.resolve(true);
1157
- }
1158
- );
1346
+ return res.once(
1347
+ ctx.status(200),
1348
+ ctx.json({
1349
+ success: true,
1350
+ errors: [],
1351
+ messages: [],
1352
+ result: true,
1353
+ })
1354
+ );
1355
+ }),
1159
1356
 
1160
- setMockResponse(
1161
- "/accounts/:accountId/pages/projects/foo/deployments",
1162
- async ([_url, accountId], init) => {
1163
- assertLater(async () => {
1164
- expect(accountId).toEqual("some-account-id");
1165
- expect(init.method).toEqual("POST");
1166
- const body = init.body as FormData;
1357
+ rest.post(
1358
+ "*/accounts/:accountId/pages/projects/foo/deployments",
1359
+ async (req, res, ctx) => {
1360
+ expect(req.params.accountId).toEqual("some-account-id");
1361
+ const body = await (req as RestRequestWithFormData).formData();
1167
1362
  const manifest = JSON.parse(body.get("manifest") as string);
1168
1363
 
1169
1364
  // for Functions projects, we auto-generate a `_worker.js`,
1170
1365
  // `functions-filepath-routing-config.json`, and `_routes.json`
1171
1366
  // file, based on the contents of `/functions`
1172
- const generatedWorkerJS = body.get("_worker.js") as Blob;
1173
- const generatedRoutesJSON = await (
1174
- body.get("_routes.json") as Blob
1175
- ).text();
1176
- const generatedFilepathRoutingConfig = await (
1177
- body.get("functions-filepath-routing-config.json") as Blob
1178
- ).text();
1367
+ const generatedWorkerJS = body.get("_worker.js") as string;
1368
+ const generatedRoutesJSON = body.get("_routes.json") as string;
1369
+ const generatedFilepathRoutingConfig = body.get(
1370
+ "functions-filepath-routing-config.json"
1371
+ ) as string;
1179
1372
 
1180
1373
  // make sure this is all we uploaded
1181
1374
  expect([...body.keys()]).toEqual([
@@ -1186,10 +1379,10 @@ describe("pages", () => {
1186
1379
  ]);
1187
1380
 
1188
1381
  expect(manifest).toMatchInlineSnapshot(`
1189
- Object {
1190
- "/README.md": "13a03eaf24ae98378acd36ea00f77f2f",
1191
- }
1192
- `);
1382
+ Object {
1383
+ "/README.md": "13a03eaf24ae98378acd36ea00f77f2f",
1384
+ }
1385
+ `);
1193
1386
 
1194
1387
  // the contents of the generated `_worker.js` file is pretty massive, so I don't
1195
1388
  // think snapshot testing makes much sense here. Plus, calling
@@ -1198,7 +1391,7 @@ describe("pages", () => {
1198
1391
  // file contents is too big). So for now, let's test that _worker.js was indeed
1199
1392
  // generated and that the file size is greater than zero
1200
1393
  expect(generatedWorkerJS).not.toBeNull();
1201
- expect(generatedWorkerJS.size).toBeGreaterThan(0);
1394
+ expect(generatedWorkerJS.length).toBeGreaterThan(0);
1202
1395
 
1203
1396
  const maybeRoutesJSONSpec = JSON.parse(generatedRoutesJSON);
1204
1397
  expect(isRoutesJSONSpec(maybeRoutesJSONSpec)).toBe(true);
@@ -1227,23 +1420,38 @@ describe("pages", () => {
1227
1420
  ],
1228
1421
  baseURL: "/",
1229
1422
  });
1230
- });
1231
-
1232
- return {
1233
- url: "https://abcxyz.foo.pages.dev/",
1234
- };
1235
- }
1236
- );
1237
1423
 
1238
- setMockResponse(
1239
- "/accounts/:accountId/pages/projects/foo",
1240
- "GET",
1241
- async ([_url, accountId]) => {
1242
- assertLater(() => {
1243
- expect(accountId).toEqual("some-account-id");
1244
- });
1245
- return { deployment_configs: { production: {}, preview: {} } };
1246
- }
1424
+ return res.once(
1425
+ ctx.status(200),
1426
+ ctx.json({
1427
+ success: true,
1428
+ errors: [],
1429
+ messages: [],
1430
+ result: {
1431
+ url: "https://abcxyz.foo.pages.dev/",
1432
+ },
1433
+ })
1434
+ );
1435
+ }
1436
+ ),
1437
+ rest.get(
1438
+ "*/accounts/:accountId/pages/projects/foo",
1439
+ async (req, res, ctx) => {
1440
+ expect(req.params.accountId).toEqual("some-account-id");
1441
+
1442
+ return res.once(
1443
+ ctx.status(200),
1444
+ ctx.json({
1445
+ success: true,
1446
+ errors: [],
1447
+ messages: [],
1448
+ result: {
1449
+ deployment_configs: { production: {}, preview: {} },
1450
+ },
1451
+ })
1452
+ );
1453
+ }
1454
+ )
1247
1455
  );
1248
1456
 
1249
1457
  await runWrangler("pages publish public --project-name=foo");
@@ -1278,30 +1486,35 @@ describe("pages", () => {
1278
1486
 
1279
1487
  mockGetToken("<<funfetti-auth-jwt>>");
1280
1488
 
1281
- setMockResponse(
1282
- "/pages/assets/check-missing",
1283
- "POST",
1284
- async (_, init) => {
1285
- const body = JSON.parse(init.body as string) as { hashes: string[] };
1286
- assertLater(() => {
1287
- expect(init.headers).toMatchObject({
1288
- Authorization: "Bearer <<funfetti-auth-jwt>>",
1289
- });
1290
- expect(body).toMatchObject({
1291
- hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1292
- });
1293
- });
1294
- return body.hashes;
1295
- }
1296
- );
1489
+ msw.use(
1490
+ rest.post("*/pages/assets/check-missing", async (req, res, ctx) => {
1491
+ const body = (await req.json()) as {
1492
+ hashes: string[];
1493
+ };
1297
1494
 
1298
- setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
1299
- assertLater(() => {
1300
- expect(init.headers).toMatchObject({
1301
- Authorization: "Bearer <<funfetti-auth-jwt>>",
1495
+ expect(req.headers.get("Authorization")).toBe(
1496
+ "Bearer <<funfetti-auth-jwt>>"
1497
+ );
1498
+ expect(body).toMatchObject({
1499
+ hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1302
1500
  });
1303
- const body = JSON.parse(init.body as string) as UploadPayloadFile[];
1304
- expect(body).toMatchObject([
1501
+
1502
+ return res.once(
1503
+ ctx.status(200),
1504
+ ctx.json({
1505
+ success: true,
1506
+ errors: [],
1507
+ messages: [],
1508
+ result: body.hashes,
1509
+ })
1510
+ );
1511
+ }),
1512
+ rest.post("*/pages/assets/upload", async (req, res, ctx) => {
1513
+ expect(req.headers.get("Authorization")).toBe(
1514
+ "Bearer <<funfetti-auth-jwt>>"
1515
+ );
1516
+
1517
+ expect(await req.json()).toMatchObject([
1305
1518
  {
1306
1519
  key: "13a03eaf24ae98378acd36ea00f77f2f",
1307
1520
  value: Buffer.from("This is a readme").toString("base64"),
@@ -1311,56 +1524,75 @@ describe("pages", () => {
1311
1524
  base64: true,
1312
1525
  },
1313
1526
  ]);
1314
- });
1315
- });
1316
-
1317
- setMockResponse(
1318
- "/accounts/:accountId/pages/projects/foo/deployments",
1319
- async ([_url, accountId], init) => {
1320
- assertLater(async () => {
1321
- expect(accountId).toEqual("some-account-id");
1322
- expect(init.method).toEqual("POST");
1323
- const body = init.body as FormData;
1527
+ return res.once(
1528
+ ctx.status(200),
1529
+ ctx.json({
1530
+ success: true,
1531
+ errors: [],
1532
+ messages: [],
1533
+ result: true,
1534
+ })
1535
+ );
1536
+ }),
1537
+ rest.post(
1538
+ "*/accounts/:accountId/pages/projects/foo/deployments",
1539
+ async (req, res, ctx) => {
1540
+ expect(req.params.accountId).toEqual("some-account-id");
1541
+ const body = await (req as RestRequestWithFormData).formData();
1324
1542
  const manifest = JSON.parse(body.get("manifest") as string);
1325
- const customWorkerJS = await (
1326
- body.get("_worker.js") as Blob
1327
- ).text();
1543
+ const customWorkerJS = body.get("_worker.js");
1328
1544
 
1329
1545
  // make sure this is all we uploaded
1330
- expect([...body.keys()]).toEqual(["manifest", "_worker.js"]);
1546
+ expect([...body.keys()].sort()).toEqual(
1547
+ ["manifest", "_worker.js"].sort()
1548
+ );
1331
1549
 
1332
1550
  expect(manifest).toMatchInlineSnapshot(`
1333
- Object {
1334
- "/README.md": "13a03eaf24ae98378acd36ea00f77f2f",
1335
- }
1336
- `);
1551
+ Object {
1552
+ "/README.md": "13a03eaf24ae98378acd36ea00f77f2f",
1553
+ }
1554
+ `);
1337
1555
 
1338
1556
  expect(customWorkerJS).toMatchInlineSnapshot(`
1339
- "
1340
- export default {
1341
- async fetch(request, env) {
1342
- const url = new URL(request.url);
1343
- return url.pathname.startsWith('/api/') ? new Response('Ok') : env.ASSETS.fetch(request);
1344
- };
1345
1557
  "
1346
- `);
1347
- });
1348
-
1349
- return {
1350
- url: "https://abcxyz.foo.pages.dev/",
1351
- };
1352
- }
1353
- );
1354
-
1355
- setMockResponse(
1356
- "/accounts/:accountId/pages/projects/foo",
1357
- "GET",
1358
- async ([_url, accountId]) => {
1359
- assertLater(() => {
1360
- expect(accountId).toEqual("some-account-id");
1361
- });
1362
- return { deployment_configs: { production: {}, preview: {} } };
1363
- }
1558
+ export default {
1559
+ async fetch(request, env) {
1560
+ const url = new URL(request.url);
1561
+ return url.pathname.startsWith('/api/') ? new Response('Ok') : env.ASSETS.fetch(request);
1562
+ };
1563
+ "
1564
+ `);
1565
+ return res.once(
1566
+ ctx.status(200),
1567
+ ctx.json({
1568
+ success: true,
1569
+ errors: [],
1570
+ messages: [],
1571
+ result: {
1572
+ url: "https://abcxyz.foo.pages.dev/",
1573
+ },
1574
+ })
1575
+ );
1576
+ }
1577
+ ),
1578
+ rest.get(
1579
+ "*/accounts/:accountId/pages/projects/foo",
1580
+ async (req, res, ctx) => {
1581
+ expect(req.params.accountId).toEqual("some-account-id");
1582
+
1583
+ return res.once(
1584
+ ctx.status(200),
1585
+ ctx.json({
1586
+ success: true,
1587
+ errors: [],
1588
+ messages: [],
1589
+ result: {
1590
+ deployment_configs: { production: {}, preview: {} },
1591
+ },
1592
+ })
1593
+ );
1594
+ }
1595
+ )
1364
1596
  );
1365
1597
 
1366
1598
  await runWrangler("pages publish public --project-name=foo");
@@ -1414,31 +1646,35 @@ describe("pages", () => {
1414
1646
  );
1415
1647
 
1416
1648
  mockGetToken("<<funfetti-auth-jwt>>");
1649
+ msw.use(
1650
+ rest.post("*/pages/assets/check-missing", async (req, res, ctx) => {
1651
+ const body = (await req.json()) as {
1652
+ hashes: string[];
1653
+ };
1417
1654
 
1418
- setMockResponse(
1419
- "/pages/assets/check-missing",
1420
- "POST",
1421
- async (_, init) => {
1422
- const body = JSON.parse(init.body as string) as { hashes: string[] };
1423
- assertLater(() => {
1424
- expect(init.headers).toMatchObject({
1425
- Authorization: "Bearer <<funfetti-auth-jwt>>",
1426
- });
1427
- expect(body).toMatchObject({
1428
- hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1429
- });
1655
+ expect(req.headers.get("Authorization")).toBe(
1656
+ "Bearer <<funfetti-auth-jwt>>"
1657
+ );
1658
+ expect(body).toMatchObject({
1659
+ hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1430
1660
  });
1431
- return body.hashes;
1432
- }
1433
- );
1434
1661
 
1435
- setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
1436
- assertLater(() => {
1437
- expect(init.headers).toMatchObject({
1438
- Authorization: "Bearer <<funfetti-auth-jwt>>",
1439
- });
1440
- const body = JSON.parse(init.body as string) as UploadPayloadFile[];
1441
- expect(body).toMatchObject([
1662
+ return res.once(
1663
+ ctx.status(200),
1664
+ ctx.json({
1665
+ success: true,
1666
+ errors: [],
1667
+ messages: [],
1668
+ result: body.hashes,
1669
+ })
1670
+ );
1671
+ }),
1672
+ rest.post("*/pages/assets/upload", async (req, res, ctx) => {
1673
+ expect(req.headers.get("Authorization")).toBe(
1674
+ "Bearer <<funfetti-auth-jwt>>"
1675
+ );
1676
+
1677
+ expect(await req.json()).toMatchObject([
1442
1678
  {
1443
1679
  key: "13a03eaf24ae98378acd36ea00f77f2f",
1444
1680
  value: Buffer.from("This is a readme").toString("base64"),
@@ -1448,60 +1684,67 @@ describe("pages", () => {
1448
1684
  base64: true,
1449
1685
  },
1450
1686
  ]);
1451
- });
1452
- });
1453
1687
 
1454
- setMockResponse(
1455
- `/pages/assets/upsert-hashes`,
1456
- "POST",
1457
- async (_, init) => {
1458
- assertLater(() => {
1459
- expect(init.headers).toMatchObject({
1460
- Authorization: "Bearer <<funfetti-auth-jwt>>",
1461
- });
1462
- const body = JSON.parse(init.body as string) as UploadPayloadFile[];
1463
- expect(body).toMatchObject({
1464
- hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1465
- });
1466
- });
1688
+ return res.once(
1689
+ ctx.status(200),
1690
+ ctx.json({
1691
+ success: true,
1692
+ errors: [],
1693
+ messages: [],
1694
+ result: null,
1695
+ })
1696
+ );
1697
+ }),
1698
+ rest.post(`*/pages/assets/upsert-hashes`, async (req, res, ctx) => {
1699
+ expect(req.headers.get("Authorization")).toBe(
1700
+ "Bearer <<funfetti-auth-jwt>>"
1701
+ );
1467
1702
 
1468
- return Promise.resolve(true);
1469
- }
1470
- );
1703
+ expect(await req.json()).toMatchObject({
1704
+ hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1705
+ });
1471
1706
 
1472
- setMockResponse(
1473
- "/accounts/:accountId/pages/projects/foo/deployments",
1474
- async ([_url, accountId], init) => {
1475
- assertLater(async () => {
1476
- expect(accountId).toEqual("some-account-id");
1477
- expect(init.method).toEqual("POST");
1478
- const body = init.body as FormData;
1707
+ return res.once(
1708
+ ctx.status(200),
1709
+ ctx.json({
1710
+ success: true,
1711
+ errors: [],
1712
+ messages: [],
1713
+ result: true,
1714
+ })
1715
+ );
1716
+ }),
1717
+ rest.post(
1718
+ "*/accounts/:accountId/pages/projects/foo/deployments",
1719
+ async (req, res, ctx) => {
1720
+ expect(req.params.accountId).toEqual("some-account-id");
1721
+ const body = await (req as RestRequestWithFormData).formData();
1479
1722
  const manifest = JSON.parse(body.get("manifest") as string);
1480
- const generatedWorkerJS = body.get("_worker.js") as Blob;
1481
- const customRoutesJSON = await (
1482
- body.get("_routes.json") as Blob
1483
- ).text();
1484
- const generatedFilepathRoutingConfig = await (
1485
- body.get("functions-filepath-routing-config.json") as Blob
1486
- ).text();
1723
+ const generatedWorkerJS = body.get("_worker.js") as string;
1724
+ const customRoutesJSON = body.get("_routes.json") as string;
1725
+ const generatedFilepathRoutingConfig = body.get(
1726
+ "functions-filepath-routing-config.json"
1727
+ ) as string;
1487
1728
 
1488
1729
  // make sure this is all we uploaded
1489
- expect([...body.keys()]).toEqual([
1490
- "manifest",
1491
- "functions-filepath-routing-config.json",
1492
- "_worker.js",
1493
- "_routes.json",
1494
- ]);
1730
+ expect([...body.keys()].sort()).toEqual(
1731
+ [
1732
+ "manifest",
1733
+ "functions-filepath-routing-config.json",
1734
+ "_worker.js",
1735
+ "_routes.json",
1736
+ ].sort()
1737
+ );
1495
1738
 
1496
1739
  expect(manifest).toMatchInlineSnapshot(`
1497
- Object {
1498
- "/README.md": "13a03eaf24ae98378acd36ea00f77f2f",
1499
- }
1500
- `);
1740
+ Object {
1741
+ "/README.md": "13a03eaf24ae98378acd36ea00f77f2f",
1742
+ }
1743
+ `);
1501
1744
 
1502
1745
  // file content of generated `_worker.js` is too massive to snapshot test
1503
1746
  expect(generatedWorkerJS).not.toBeNull();
1504
- expect(generatedWorkerJS.size).toBeGreaterThan(0);
1747
+ expect(generatedWorkerJS.length).toBeGreaterThan(0);
1505
1748
 
1506
1749
  const customRoutes = JSON.parse(customRoutesJSON);
1507
1750
  expect(customRoutes).toMatchObject({
@@ -1518,7 +1761,6 @@ describe("pages", () => {
1518
1761
  // The actual shape doesn't matter that much since this
1519
1762
  // is only used for display in Dash, but it's still useful for
1520
1763
  // tracking unexpected changes to this config.
1521
- console.log(generatedFilepathRoutingConfig);
1522
1764
  expect(parsedFilepathRoutingConfig).toStrictEqual({
1523
1765
  routes: [
1524
1766
  {
@@ -1536,23 +1778,38 @@ describe("pages", () => {
1536
1778
  ],
1537
1779
  baseURL: "/",
1538
1780
  });
1539
- });
1540
-
1541
- return {
1542
- url: "https://abcxyz.foo.pages.dev/",
1543
- };
1544
- }
1545
- );
1546
1781
 
1547
- setMockResponse(
1548
- "/accounts/:accountId/pages/projects/foo",
1549
- "GET",
1550
- async ([_url, accountId]) => {
1551
- assertLater(() => {
1552
- expect(accountId).toEqual("some-account-id");
1553
- });
1554
- return { deployment_configs: { production: {}, preview: {} } };
1555
- }
1782
+ return res.once(
1783
+ ctx.status(200),
1784
+ ctx.json({
1785
+ success: true,
1786
+ errors: [],
1787
+ messages: [],
1788
+ result: {
1789
+ url: "https://abcxyz.foo.pages.dev/",
1790
+ },
1791
+ })
1792
+ );
1793
+ }
1794
+ ),
1795
+ rest.get(
1796
+ "*/accounts/:accountId/pages/projects/foo",
1797
+ async (req, res, ctx) => {
1798
+ expect(req.params.accountId).toEqual("some-account-id");
1799
+
1800
+ return res.once(
1801
+ ctx.status(200),
1802
+ ctx.json({
1803
+ success: true,
1804
+ errors: [],
1805
+ messages: [],
1806
+ result: {
1807
+ deployment_configs: { production: {}, preview: {} },
1808
+ },
1809
+ })
1810
+ );
1811
+ }
1812
+ )
1556
1813
  );
1557
1814
 
1558
1815
  await runWrangler("pages publish public --project-name=foo");
@@ -1604,31 +1861,35 @@ describe("pages", () => {
1604
1861
  );
1605
1862
 
1606
1863
  mockGetToken("<<funfetti-auth-jwt>>");
1864
+ msw.use(
1865
+ rest.post("*/pages/assets/check-missing", async (req, res, ctx) => {
1866
+ const body = (await req.json()) as {
1867
+ hashes: string[];
1868
+ };
1607
1869
 
1608
- setMockResponse(
1609
- "/pages/assets/check-missing",
1610
- "POST",
1611
- async (_, init) => {
1612
- const body = JSON.parse(init.body as string) as { hashes: string[] };
1613
- assertLater(() => {
1614
- expect(init.headers).toMatchObject({
1615
- Authorization: "Bearer <<funfetti-auth-jwt>>",
1616
- });
1617
- expect(body).toMatchObject({
1618
- hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1619
- });
1870
+ expect(req.headers.get("Authorization")).toBe(
1871
+ "Bearer <<funfetti-auth-jwt>>"
1872
+ );
1873
+ expect(body).toMatchObject({
1874
+ hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1620
1875
  });
1621
- return body.hashes;
1622
- }
1623
- );
1624
1876
 
1625
- setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
1626
- assertLater(() => {
1627
- expect(init.headers).toMatchObject({
1628
- Authorization: "Bearer <<funfetti-auth-jwt>>",
1629
- });
1630
- const body = JSON.parse(init.body as string) as UploadPayloadFile[];
1631
- expect(body).toMatchObject([
1877
+ return res.once(
1878
+ ctx.status(200),
1879
+ ctx.json({
1880
+ success: true,
1881
+ errors: [],
1882
+ messages: [],
1883
+ result: body.hashes,
1884
+ })
1885
+ );
1886
+ }),
1887
+ rest.post("*/pages/assets/upload", async (req, res, ctx) => {
1888
+ expect(req.headers.get("Authorization")).toBe(
1889
+ "Bearer <<funfetti-auth-jwt>>"
1890
+ );
1891
+
1892
+ expect(await req.json()).toMatchObject([
1632
1893
  {
1633
1894
  key: "13a03eaf24ae98378acd36ea00f77f2f",
1634
1895
  value: Buffer.from("This is a readme").toString("base64"),
@@ -1638,18 +1899,35 @@ describe("pages", () => {
1638
1899
  base64: true,
1639
1900
  },
1640
1901
  ]);
1641
- });
1642
- });
1643
1902
 
1644
- setMockResponse(
1645
- "/accounts/:accountId/pages/projects/foo",
1646
- "GET",
1647
- async ([_url, accountId]) => {
1648
- assertLater(() => {
1649
- expect(accountId).toEqual("some-account-id");
1650
- });
1651
- return { deployment_configs: { production: {}, preview: {} } };
1652
- }
1903
+ return res.once(
1904
+ ctx.status(200),
1905
+ ctx.json({
1906
+ success: true,
1907
+ errors: [],
1908
+ messages: [],
1909
+ result: null,
1910
+ })
1911
+ );
1912
+ }),
1913
+ rest.get(
1914
+ "*/accounts/:accountId/pages/projects/foo",
1915
+ async (req, res, ctx) => {
1916
+ expect(req.params.accountId).toEqual("some-account-id");
1917
+
1918
+ return res.once(
1919
+ ctx.status(200),
1920
+ ctx.json({
1921
+ success: true,
1922
+ errors: [],
1923
+ messages: [],
1924
+ result: {
1925
+ deployment_configs: { production: {}, preview: {} },
1926
+ },
1927
+ })
1928
+ );
1929
+ }
1930
+ )
1653
1931
  );
1654
1932
 
1655
1933
  await expect(runWrangler("pages publish public --project-name=foo"))
@@ -1697,30 +1975,35 @@ and that at least one include rule is provided.
1697
1975
 
1698
1976
  mockGetToken("<<funfetti-auth-jwt>>");
1699
1977
 
1700
- setMockResponse(
1701
- "/pages/assets/check-missing",
1702
- "POST",
1703
- async (_, init) => {
1704
- const body = JSON.parse(init.body as string) as { hashes: string[] };
1705
- assertLater(() => {
1706
- expect(init.headers).toMatchObject({
1707
- Authorization: "Bearer <<funfetti-auth-jwt>>",
1708
- });
1709
- expect(body).toMatchObject({
1710
- hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1711
- });
1712
- });
1713
- return body.hashes;
1714
- }
1715
- );
1978
+ msw.use(
1979
+ rest.post("*/pages/assets/check-missing", async (req, res, ctx) => {
1980
+ const body = (await req.json()) as {
1981
+ hashes: string[];
1982
+ };
1716
1983
 
1717
- setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
1718
- assertLater(() => {
1719
- expect(init.headers).toMatchObject({
1720
- Authorization: "Bearer <<funfetti-auth-jwt>>",
1984
+ expect(req.headers.get("Authorization")).toBe(
1985
+ "Bearer <<funfetti-auth-jwt>>"
1986
+ );
1987
+ expect(body).toMatchObject({
1988
+ hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1721
1989
  });
1722
- const body = JSON.parse(init.body as string) as UploadPayloadFile[];
1723
- expect(body).toMatchObject([
1990
+
1991
+ return res.once(
1992
+ ctx.status(200),
1993
+ ctx.json({
1994
+ success: true,
1995
+ errors: [],
1996
+ messages: [],
1997
+ result: body.hashes,
1998
+ })
1999
+ );
2000
+ }),
2001
+ rest.post("*/pages/assets/upload", async (req, res, ctx) => {
2002
+ expect(req.headers.get("Authorization")).toBe(
2003
+ "Bearer <<funfetti-auth-jwt>>"
2004
+ );
2005
+
2006
+ expect(await req.json()).toMatchObject([
1724
2007
  {
1725
2008
  key: "13a03eaf24ae98378acd36ea00f77f2f",
1726
2009
  value: Buffer.from("This is a readme").toString("base64"),
@@ -1730,41 +2013,44 @@ and that at least one include rule is provided.
1730
2013
  base64: true,
1731
2014
  },
1732
2015
  ]);
1733
- });
1734
- });
1735
2016
 
1736
- setMockResponse(
1737
- `/pages/assets/upsert-hashes`,
1738
- "POST",
1739
- async (_, init) => {
1740
- assertLater(() => {
1741
- expect(init.headers).toMatchObject({
1742
- Authorization: "Bearer <<funfetti-auth-jwt>>",
1743
- });
1744
- const body = JSON.parse(init.body as string) as UploadPayloadFile[];
1745
- expect(body).toMatchObject({
1746
- hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1747
- });
2017
+ return res.once(
2018
+ ctx.status(200),
2019
+ ctx.json({
2020
+ success: true,
2021
+ errors: [],
2022
+ messages: [],
2023
+ result: null,
2024
+ })
2025
+ );
2026
+ }),
2027
+ rest.post(`*/pages/assets/upsert-hashes`, async (req, res, ctx) => {
2028
+ expect(req.headers.get("Authorization")).toBe(
2029
+ "Bearer <<funfetti-auth-jwt>>"
2030
+ );
2031
+
2032
+ expect(await req.json()).toMatchObject({
2033
+ hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1748
2034
  });
1749
2035
 
1750
- return Promise.resolve(true);
1751
- }
1752
- );
2036
+ return res.once(
2037
+ ctx.status(200),
2038
+ ctx.json({
2039
+ success: true,
2040
+ errors: [],
2041
+ messages: [],
2042
+ result: true,
2043
+ })
2044
+ );
2045
+ }),
2046
+ rest.post(
2047
+ "*/accounts/:accountId/pages/projects/foo/deployments",
2048
+ async (req, res, ctx) => {
2049
+ const body = await (req as RestRequestWithFormData).formData();
1753
2050
 
1754
- setMockResponse(
1755
- "/accounts/:accountId/pages/projects/foo/deployments",
1756
- async ([_url, accountId], init) => {
1757
- assertLater(async () => {
1758
- expect(accountId).toEqual("some-account-id");
1759
- expect(init.method).toEqual("POST");
1760
- const body = init.body as FormData;
1761
2051
  const manifest = JSON.parse(body.get("manifest") as string);
1762
- const customWorkerJS = await (
1763
- body.get("_worker.js") as Blob
1764
- ).text();
1765
- const customRoutesJSON = await (
1766
- body.get("_routes.json") as Blob
1767
- ).text();
2052
+ const customWorkerJS = body.get("_worker.js") as string;
2053
+ const customRoutesJSON = body.get("_routes.json") as string;
1768
2054
 
1769
2055
  // make sure this is all we uploaded
1770
2056
  expect([...body.keys()]).toEqual([
@@ -1772,47 +2058,61 @@ and that at least one include rule is provided.
1772
2058
  "_worker.js",
1773
2059
  "_routes.json",
1774
2060
  ]);
1775
-
2061
+ expect(req.params.accountId).toEqual("some-account-id");
1776
2062
  expect(manifest).toMatchInlineSnapshot(`
1777
- Object {
1778
- "/README.md": "13a03eaf24ae98378acd36ea00f77f2f",
1779
- }
1780
- `);
2063
+ Object {
2064
+ "/README.md": "13a03eaf24ae98378acd36ea00f77f2f",
2065
+ }
2066
+ `);
1781
2067
 
1782
2068
  expect(customWorkerJS).toMatchInlineSnapshot(`
1783
- "
1784
- export default {
1785
- async fetch(request, env) {
1786
- const url = new URL(request.url);
1787
- return url.pathname.startsWith('/api/') ? new Response('Ok') : env.ASSETS.fetch(request);
1788
- };
1789
2069
  "
1790
- `);
1791
-
1792
- const customRoutes = JSON.parse(customRoutesJSON);
1793
- expect(customRoutes).toMatchObject({
2070
+ export default {
2071
+ async fetch(request, env) {
2072
+ const url = new URL(request.url);
2073
+ return url.pathname.startsWith('/api/') ? new Response('Ok') : env.ASSETS.fetch(request);
2074
+ };
2075
+ "
2076
+ `);
2077
+
2078
+ expect(JSON.parse(customRoutesJSON)).toMatchObject({
1794
2079
  version: ROUTES_SPEC_VERSION,
1795
2080
  description: "Custom _routes.json file",
1796
2081
  include: ["/api/*"],
1797
2082
  exclude: [],
1798
2083
  });
1799
- });
1800
-
1801
- return {
1802
- url: "https://abcxyz.foo.pages.dev/",
1803
- };
1804
- }
1805
- );
1806
2084
 
1807
- setMockResponse(
1808
- "/accounts/:accountId/pages/projects/foo",
1809
- "GET",
1810
- async ([_url, accountId]) => {
1811
- assertLater(() => {
1812
- expect(accountId).toEqual("some-account-id");
1813
- });
1814
- return { deployment_configs: { production: {}, preview: {} } };
1815
- }
2085
+ return res.once(
2086
+ ctx.status(200),
2087
+ ctx.json({
2088
+ success: true,
2089
+ errors: [],
2090
+ messages: [],
2091
+ result: {
2092
+ url: "https://abcxyz.foo.pages.dev/",
2093
+ },
2094
+ })
2095
+ );
2096
+ }
2097
+ ),
2098
+ rest.get(
2099
+ "*/accounts/:accountId/pages/projects/foo",
2100
+ async (req, res, ctx) => {
2101
+ expect(req.params.accountId).toEqual("some-account-id");
2102
+
2103
+ return res.once(
2104
+ ctx.status(200),
2105
+ ctx.json({
2106
+ success: true,
2107
+ errors: [],
2108
+ messages: [],
2109
+ result: {
2110
+ deployment_configs: { production: {}, preview: {} },
2111
+ },
2112
+ })
2113
+ );
2114
+ }
2115
+ )
1816
2116
  );
1817
2117
 
1818
2118
  await runWrangler("pages publish public --project-name=foo");
@@ -1864,30 +2164,35 @@ and that at least one include rule is provided.
1864
2164
 
1865
2165
  mockGetToken("<<funfetti-auth-jwt>>");
1866
2166
 
1867
- setMockResponse(
1868
- "/pages/assets/check-missing",
1869
- "POST",
1870
- async (_, init) => {
1871
- const body = JSON.parse(init.body as string) as { hashes: string[] };
1872
- assertLater(() => {
1873
- expect(init.headers).toMatchObject({
1874
- Authorization: "Bearer <<funfetti-auth-jwt>>",
1875
- });
1876
- expect(body).toMatchObject({
1877
- hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1878
- });
1879
- });
1880
- return body.hashes;
1881
- }
1882
- );
2167
+ msw.use(
2168
+ rest.post("*/pages/assets/check-missing", async (req, res, ctx) => {
2169
+ const body = (await req.json()) as {
2170
+ hashes: string[];
2171
+ };
1883
2172
 
1884
- setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
1885
- assertLater(() => {
1886
- expect(init.headers).toMatchObject({
1887
- Authorization: "Bearer <<funfetti-auth-jwt>>",
2173
+ expect(req.headers.get("Authorization")).toBe(
2174
+ "Bearer <<funfetti-auth-jwt>>"
2175
+ );
2176
+ expect(body).toMatchObject({
2177
+ hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1888
2178
  });
1889
- const body = JSON.parse(init.body as string) as UploadPayloadFile[];
1890
- expect(body).toMatchObject([
2179
+
2180
+ return res.once(
2181
+ ctx.status(200),
2182
+ ctx.json({
2183
+ success: true,
2184
+ errors: [],
2185
+ messages: [],
2186
+ result: body.hashes,
2187
+ })
2188
+ );
2189
+ }),
2190
+ rest.post("*/pages/assets/upload", async (req, res, ctx) => {
2191
+ expect(req.headers.get("Authorization")).toBe(
2192
+ "Bearer <<funfetti-auth-jwt>>"
2193
+ );
2194
+
2195
+ expect(await req.json()).toMatchObject([
1891
2196
  {
1892
2197
  key: "13a03eaf24ae98378acd36ea00f77f2f",
1893
2198
  value: Buffer.from("This is a readme").toString("base64"),
@@ -1897,18 +2202,35 @@ and that at least one include rule is provided.
1897
2202
  base64: true,
1898
2203
  },
1899
2204
  ]);
1900
- });
1901
- });
1902
2205
 
1903
- setMockResponse(
1904
- "/accounts/:accountId/pages/projects/foo",
1905
- "GET",
1906
- async ([_url, accountId]) => {
1907
- assertLater(() => {
1908
- expect(accountId).toEqual("some-account-id");
1909
- });
1910
- return { deployment_configs: { production: {}, preview: {} } };
1911
- }
2206
+ return res.once(
2207
+ ctx.status(200),
2208
+ ctx.json({
2209
+ success: true,
2210
+ errors: [],
2211
+ messages: [],
2212
+ result: null,
2213
+ })
2214
+ );
2215
+ }),
2216
+
2217
+ rest.get(
2218
+ "*/accounts/:accountId/pages/projects/foo",
2219
+ async (req, res, ctx) => {
2220
+ expect(req.params.accountId).toEqual("some-account-id");
2221
+ return res.once(
2222
+ ctx.status(200),
2223
+ ctx.json({
2224
+ success: true,
2225
+ errors: [],
2226
+ messages: [],
2227
+ result: {
2228
+ deployment_configs: { production: {}, preview: {} },
2229
+ },
2230
+ })
2231
+ );
2232
+ }
2233
+ )
1912
2234
  );
1913
2235
 
1914
2236
  await expect(runWrangler("pages publish public --project-name=foo"))
@@ -1954,30 +2276,35 @@ and that at least one include rule is provided.
1954
2276
 
1955
2277
  mockGetToken("<<funfetti-auth-jwt>>");
1956
2278
 
1957
- setMockResponse(
1958
- "/pages/assets/check-missing",
1959
- "POST",
1960
- async (_, init) => {
1961
- const body = JSON.parse(init.body as string) as { hashes: string[] };
1962
- assertLater(() => {
1963
- expect(init.headers).toMatchObject({
1964
- Authorization: "Bearer <<funfetti-auth-jwt>>",
1965
- });
1966
- expect(body).toMatchObject({
1967
- hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1968
- });
1969
- });
1970
- return body.hashes;
1971
- }
1972
- );
2279
+ msw.use(
2280
+ rest.post("*/pages/assets/check-missing", async (req, res, ctx) => {
2281
+ const body = (await req.json()) as {
2282
+ hashes: string[];
2283
+ };
1973
2284
 
1974
- setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
1975
- assertLater(() => {
1976
- expect(init.headers).toMatchObject({
1977
- Authorization: "Bearer <<funfetti-auth-jwt>>",
2285
+ expect(req.headers.get("Authorization")).toBe(
2286
+ "Bearer <<funfetti-auth-jwt>>"
2287
+ );
2288
+ expect(body).toMatchObject({
2289
+ hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1978
2290
  });
1979
- const body = JSON.parse(init.body as string) as UploadPayloadFile[];
1980
- expect(body).toMatchObject([
2291
+
2292
+ return res.once(
2293
+ ctx.status(200),
2294
+ ctx.json({
2295
+ success: true,
2296
+ errors: [],
2297
+ messages: [],
2298
+ result: body.hashes,
2299
+ })
2300
+ );
2301
+ }),
2302
+ rest.post("*/pages/assets/upload", async (req, res, ctx) => {
2303
+ expect(req.headers.get("Authorization")).toBe(
2304
+ "Bearer <<funfetti-auth-jwt>>"
2305
+ );
2306
+
2307
+ expect(await req.json()).toMatchObject([
1981
2308
  {
1982
2309
  key: "13a03eaf24ae98378acd36ea00f77f2f",
1983
2310
  value: Buffer.from("This is a readme").toString("base64"),
@@ -1987,56 +2314,76 @@ and that at least one include rule is provided.
1987
2314
  base64: true,
1988
2315
  },
1989
2316
  ]);
1990
- });
1991
- });
1992
2317
 
1993
- setMockResponse(
1994
- "/accounts/:accountId/pages/projects/foo/deployments",
1995
- async ([_url, accountId], init) => {
1996
- assertLater(async () => {
1997
- expect(accountId).toEqual("some-account-id");
1998
- expect(init.method).toEqual("POST");
1999
- const body = init.body as FormData;
2318
+ return res.once(
2319
+ ctx.status(200),
2320
+ ctx.json({
2321
+ success: true,
2322
+ errors: [],
2323
+ messages: [],
2324
+ result: null,
2325
+ })
2326
+ );
2327
+ }),
2328
+
2329
+ rest.post(
2330
+ "*/accounts/:accountId/pages/projects/foo/deployments",
2331
+ async (req, res, ctx) => {
2332
+ const body = await (req as RestRequestWithFormData).formData();
2000
2333
  const manifest = JSON.parse(body.get("manifest") as string);
2001
- const customWorkerJS = await (
2002
- body.get("_worker.js") as Blob
2003
- ).text();
2334
+ const customWorkerJS = body.get("_worker.js");
2004
2335
 
2336
+ expect(req.params.accountId).toEqual("some-account-id");
2005
2337
  // make sure this is all we uploaded
2006
- expect([...body.keys()]).toEqual(["manifest", "_worker.js"]);
2007
-
2338
+ expect([...body.keys()].sort()).toEqual(
2339
+ ["manifest", "_worker.js"].sort()
2340
+ );
2008
2341
  expect(manifest).toMatchInlineSnapshot(`
2009
- Object {
2010
- "/README.md": "13a03eaf24ae98378acd36ea00f77f2f",
2011
- }
2012
- `);
2013
-
2342
+ Object {
2343
+ "/README.md": "13a03eaf24ae98378acd36ea00f77f2f",
2344
+ }
2345
+ `);
2014
2346
  expect(customWorkerJS).toMatchInlineSnapshot(`
2015
- "
2016
- export default {
2017
- async fetch(request, env) {
2018
- const url = new URL(request.url);
2019
- return url.pathname.startsWith('/api/') ? new Response('Ok') : env.ASSETS.fetch(request);
2020
- };
2021
2347
  "
2022
- `);
2023
- });
2024
-
2025
- return {
2026
- url: "https://abcxyz.foo.pages.dev/",
2027
- };
2028
- }
2029
- );
2030
-
2031
- setMockResponse(
2032
- "/accounts/:accountId/pages/projects/foo",
2033
- "GET",
2034
- async ([_url, accountId]) => {
2035
- assertLater(() => {
2036
- expect(accountId).toEqual("some-account-id");
2037
- });
2038
- return { deployment_configs: { production: {}, preview: {} } };
2039
- }
2348
+ export default {
2349
+ async fetch(request, env) {
2350
+ const url = new URL(request.url);
2351
+ return url.pathname.startsWith('/api/') ? new Response('Ok') : env.ASSETS.fetch(request);
2352
+ };
2353
+ "
2354
+ `);
2355
+
2356
+ return res.once(
2357
+ ctx.status(200),
2358
+ ctx.json({
2359
+ success: true,
2360
+ errors: [],
2361
+ messages: [],
2362
+ result: {
2363
+ url: "https://abcxyz.foo.pages.dev/",
2364
+ },
2365
+ })
2366
+ );
2367
+ }
2368
+ ),
2369
+ rest.get(
2370
+ "*/accounts/:accountId/pages/projects/foo",
2371
+ async (req, res, ctx) => {
2372
+ expect(req.params.accountId).toEqual("some-account-id");
2373
+
2374
+ return res.once(
2375
+ ctx.status(200),
2376
+ ctx.json({
2377
+ success: true,
2378
+ errors: [],
2379
+ messages: [],
2380
+ result: {
2381
+ deployment_configs: { production: {}, preview: {} },
2382
+ },
2383
+ })
2384
+ );
2385
+ }
2386
+ )
2040
2387
  );
2041
2388
 
2042
2389
  await runWrangler("pages publish public --project-name=foo");
@@ -2065,48 +2412,62 @@ and that at least one include rule is provided.
2065
2412
  });
2066
2413
 
2067
2414
  afterEach(() => {
2068
- unsetAllMocks();
2069
2415
  process.env = ENV_COPY;
2070
2416
  });
2071
2417
 
2072
2418
  it("should upload a directory of files with a provided JWT", async () => {
2073
2419
  writeFileSync("logo.png", "foobar");
2074
2420
 
2075
- setMockResponse(
2076
- "/pages/assets/check-missing",
2077
- "POST",
2078
- async (_, init) => {
2079
- const body = JSON.parse(init.body as string) as { hashes: string[] };
2080
- assertLater(() => {
2081
- expect(init.headers).toMatchObject({
2082
- Authorization: "Bearer <<funfetti-auth-jwt>>",
2083
- });
2084
- expect(body).toMatchObject({
2085
- hashes: ["2082190357cfd3617ccfe04f340c6247"],
2086
- });
2087
- });
2088
- return body.hashes;
2089
- }
2090
- );
2421
+ msw.use(
2422
+ rest.post("*/pages/assets/check-missing", async (req, res, ctx) => {
2423
+ const body = (await req.json()) as {
2424
+ hashes: string[];
2425
+ };
2091
2426
 
2092
- setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
2093
- assertLater(() => {
2094
- expect(init.headers).toMatchObject({
2095
- Authorization: "Bearer <<funfetti-auth-jwt>>",
2427
+ expect(req.headers.get("Authorization")).toBe(
2428
+ "Bearer <<funfetti-auth-jwt>>"
2429
+ );
2430
+ expect(body).toMatchObject({
2431
+ hashes: ["2082190357cfd3617ccfe04f340c6247"],
2096
2432
  });
2097
- const body = JSON.parse(init.body as string) as UploadPayloadFile[];
2098
- expect(body).toMatchObject([
2433
+
2434
+ return res.once(
2435
+ ctx.status(200),
2436
+ ctx.json({
2437
+ success: true,
2438
+ errors: [],
2439
+ messages: [],
2440
+ result: body.hashes,
2441
+ })
2442
+ );
2443
+ }),
2444
+ rest.post("*/pages/assets/upload", async (req, res, ctx) => {
2445
+ expect(req.headers.get("Authorization")).toBe(
2446
+ "Bearer <<funfetti-auth-jwt>>"
2447
+ );
2448
+
2449
+ expect(await req.json()).toMatchObject([
2099
2450
  {
2451
+ base64: true,
2100
2452
  key: "2082190357cfd3617ccfe04f340c6247",
2101
- value: Buffer.from("foobar").toString("base64"),
2102
2453
  metadata: {
2103
2454
  contentType: "image/png",
2104
2455
  },
2105
- base64: true,
2456
+ value: "Zm9vYmFy",
2106
2457
  },
2107
2458
  ]);
2108
- });
2109
- });
2459
+
2460
+ return res(
2461
+ ctx.status(200),
2462
+ ctx.json({
2463
+ success: true,
2464
+ errors: [],
2465
+ messages: [],
2466
+ result: null,
2467
+ })
2468
+ );
2469
+ })
2470
+ );
2110
2471
 
2111
2472
  await runWrangler("pages project upload .");
2112
2473
 
@@ -2135,100 +2496,103 @@ and that at least one include rule is provided.
2135
2496
  mkdirSync("functions");
2136
2497
  writeFileSync("functions/foo.js", "func");
2137
2498
 
2138
- setMockResponse(
2139
- "/pages/assets/check-missing",
2140
- "POST",
2141
- async (_, init) => {
2142
- const body = JSON.parse(init.body as string) as { hashes: string[] };
2143
- assertLater(() => {
2144
- expect(init.headers).toMatchObject({
2145
- Authorization: "Bearer <<funfetti-auth-jwt>>",
2146
- });
2147
- expect(body).toMatchObject({
2148
- hashes: [
2149
- "2082190357cfd3617ccfe04f340c6247",
2150
- "95dedb64e6d4940fc2e0f11f711cc2f4",
2151
- "09a79777abda8ccc8bdd51dd3ff8e9e9",
2152
- ],
2153
- });
2499
+ // Accumulate multiple requests then assert afterwards
2500
+ const requests: RestRequest[] = [];
2501
+ msw.use(
2502
+ rest.post("*/pages/assets/check-missing", async (req, res, ctx) => {
2503
+ const body = (await req.json()) as {
2504
+ hashes: string[];
2505
+ };
2506
+
2507
+ expect(req.headers.get("Authorization")).toBe(
2508
+ "Bearer <<funfetti-auth-jwt>>"
2509
+ );
2510
+ expect(body).toMatchObject({
2511
+ hashes: [
2512
+ "2082190357cfd3617ccfe04f340c6247",
2513
+ "95dedb64e6d4940fc2e0f11f711cc2f4",
2514
+ "09a79777abda8ccc8bdd51dd3ff8e9e9",
2515
+ ],
2154
2516
  });
2155
- return body.hashes;
2156
- }
2517
+
2518
+ return res.once(
2519
+ ctx.status(200),
2520
+ ctx.json({
2521
+ success: true,
2522
+ errors: [],
2523
+ messages: [],
2524
+ result: body.hashes,
2525
+ })
2526
+ );
2527
+ }),
2528
+ rest.post("*/pages/assets/upload", (req, res, ctx) => {
2529
+ requests.push(req);
2530
+
2531
+ return res(
2532
+ ctx.status(200),
2533
+ ctx.json({
2534
+ success: true,
2535
+ errors: [],
2536
+ messages: [],
2537
+ result: null,
2538
+ })
2539
+ );
2540
+ })
2157
2541
  );
2158
2542
 
2159
- // Accumulate multiple requests then assert afterwards
2160
- const requests: RequestInit[] = [];
2161
- setMockRawResponse("/pages/assets/upload", "POST", async (_, init) => {
2162
- requests.push(init);
2543
+ await runWrangler("pages project upload .");
2163
2544
 
2164
- return createFetchResult(null, true);
2165
- });
2545
+ expect(requests.length).toBe(3);
2166
2546
 
2167
- assertLater(() => {
2168
- expect(requests.length).toBe(3);
2547
+ const resolvedRequests = await Promise.all(
2548
+ requests.map(async (req) => await req.json<UploadPayloadFile>())
2549
+ );
2169
2550
 
2170
- const sortedRequests = requests.sort((a, b) => {
2171
- return (JSON.parse(a.body as string)[0].key as string).localeCompare(
2172
- JSON.parse(b.body as string)[0].key as string
2173
- );
2174
- });
2551
+ const sortedRequests = resolvedRequests.sort((a, b) => {
2552
+ const aKey = a.key as string;
2553
+ const bKey = b.key as string;
2175
2554
 
2176
- expect(sortedRequests[0].headers).toMatchObject({
2177
- Authorization: "Bearer <<funfetti-auth-jwt>>",
2178
- });
2179
-
2180
- let body = JSON.parse(
2181
- sortedRequests[0].body as string
2182
- ) as UploadPayloadFile[];
2183
- expect(body).toMatchObject([
2184
- {
2185
- key: "09a79777abda8ccc8bdd51dd3ff8e9e9",
2186
- value: Buffer.from("func").toString("base64"),
2187
- metadata: {
2188
- contentType: "application/javascript",
2189
- },
2190
- base64: true,
2191
- },
2192
- ]);
2555
+ return aKey?.localeCompare(bKey);
2556
+ });
2193
2557
 
2194
- expect(sortedRequests[1].headers).toMatchObject({
2195
- Authorization: "Bearer <<funfetti-auth-jwt>>",
2196
- });
2558
+ for (const req of requests) {
2559
+ expect(req.headers.get("Authorization")).toBe(
2560
+ "Bearer <<funfetti-auth-jwt>>"
2561
+ );
2562
+ }
2197
2563
 
2198
- body = JSON.parse(
2199
- sortedRequests[1].body as string
2200
- ) as UploadPayloadFile[];
2201
- expect(body).toMatchObject([
2202
- {
2203
- key: "2082190357cfd3617ccfe04f340c6247",
2204
- value: Buffer.from("foobar").toString("base64"),
2205
- metadata: {
2206
- contentType: "image/png",
2207
- },
2208
- base64: true,
2564
+ expect(sortedRequests[0]).toMatchObject([
2565
+ {
2566
+ base64: true,
2567
+ key: "95dedb64e6d4940fc2e0f11f711cc2f4",
2568
+ metadata: {
2569
+ contentType: "application/octet-stream",
2209
2570
  },
2210
- ]);
2211
-
2212
- expect(sortedRequests[2].headers).toMatchObject({
2213
- Authorization: "Bearer <<funfetti-auth-jwt>>",
2214
- });
2571
+ value: "aGVhZGVyc2ZpbGU=",
2572
+ },
2573
+ ]);
2215
2574
 
2216
- body = JSON.parse(
2217
- sortedRequests[2].body as string
2218
- ) as UploadPayloadFile[];
2219
- expect(body).toMatchObject([
2220
- {
2221
- key: "95dedb64e6d4940fc2e0f11f711cc2f4",
2222
- value: Buffer.from("headersfile").toString("base64"),
2223
- metadata: {
2224
- contentType: "application/octet-stream",
2225
- },
2226
- base64: true,
2575
+ expect(sortedRequests[1]).toMatchObject([
2576
+ {
2577
+ base64: true,
2578
+ key: "2082190357cfd3617ccfe04f340c6247",
2579
+ metadata: {
2580
+ contentType: "image/png",
2227
2581
  },
2228
- ]);
2229
- });
2582
+ value: "Zm9vYmFy",
2583
+ },
2584
+ ]);
2230
2585
 
2231
- await runWrangler("pages project upload .");
2586
+ expect(sortedRequests[2]).toMatchObject([
2587
+ {
2588
+ base64: true,
2589
+ key: "09a79777abda8ccc8bdd51dd3ff8e9e9",
2590
+ metadata: {
2591
+ contentType: "application/javascript",
2592
+ },
2593
+ value: "ZnVuYw==",
2594
+ },
2595
+ ]);
2232
2596
 
2233
2597
  expect(std.out).toMatchInlineSnapshot(`
2234
2598
  "✨ Success! Uploaded 3 files (TIMINGS)
@@ -2240,62 +2604,81 @@ and that at least one include rule is provided.
2240
2604
  it("should retry uploads", async () => {
2241
2605
  writeFileSync("logo.txt", "foobar");
2242
2606
 
2243
- setMockResponse(
2244
- "/pages/assets/check-missing",
2245
- "POST",
2246
- async (_, init) => {
2247
- const body = JSON.parse(init.body as string) as { hashes: string[] };
2248
- assertLater(() => {
2249
- expect(init.headers).toMatchObject({
2250
- Authorization: "Bearer <<funfetti-auth-jwt>>",
2251
- });
2252
- expect(body).toMatchObject({
2253
- hashes: ["1a98fb08af91aca4a7df1764a2c4ddb0"],
2254
- });
2255
- });
2256
- return body.hashes;
2257
- }
2258
- );
2259
-
2260
2607
  // Accumulate multiple requests then assert afterwards
2261
- const requests: RequestInit[] = [];
2262
- setMockRawResponse("/pages/assets/upload", "POST", async (_, init) => {
2263
- requests.push(init);
2608
+ const requests: RestRequest[] = [];
2609
+ msw.use(
2610
+ rest.post("*/pages/assets/check-missing", async (req, res, ctx) => {
2611
+ const body = (await req.json()) as { hashes: string[] };
2264
2612
 
2265
- if (requests.length < 2) {
2266
- return createFetchResult(null, false, [
2267
- {
2268
- code: 800000,
2269
- message: "Something exploded, please retry",
2270
- },
2271
- ]);
2272
- } else {
2273
- return createFetchResult(null, true);
2274
- }
2275
- });
2613
+ expect(req.headers.get("Authorization")).toBe(
2614
+ "Bearer <<funfetti-auth-jwt>>"
2615
+ );
2616
+ expect(body).toMatchObject({
2617
+ hashes: ["1a98fb08af91aca4a7df1764a2c4ddb0"],
2618
+ });
2619
+
2620
+ return res.once(
2621
+ ctx.status(200),
2622
+ ctx.json({
2623
+ success: true,
2624
+ errors: [],
2625
+ messages: [],
2626
+ result: body.hashes,
2627
+ })
2628
+ );
2629
+ }),
2630
+ rest.post("*/pages/assets/upload", async (req, res, ctx) => {
2631
+ requests.push(req);
2632
+
2633
+ if (requests.length < 2) {
2634
+ return res(
2635
+ ctx.status(200),
2636
+ ctx.json({
2637
+ success: false,
2638
+ errors: [
2639
+ {
2640
+ code: 800000,
2641
+ message: "Something exploded, please retry",
2642
+ },
2643
+ ],
2644
+ messages: [],
2645
+ result: null,
2646
+ })
2647
+ );
2648
+ } else {
2649
+ return res(
2650
+ ctx.status(200),
2651
+ ctx.json({
2652
+ success: true,
2653
+ errors: [],
2654
+ messages: [],
2655
+ result: null,
2656
+ })
2657
+ );
2658
+ }
2659
+ })
2660
+ );
2276
2661
 
2277
2662
  await runWrangler("pages project upload .");
2278
2663
 
2279
2664
  // Assert two identical requests
2280
2665
  expect(requests.length).toBe(2);
2281
2666
  for (const init of requests) {
2282
- assertLater(() => {
2283
- expect(init.headers).toMatchObject({
2284
- Authorization: "Bearer <<funfetti-auth-jwt>>",
2285
- });
2667
+ expect(init.headers.get("Authorization")).toBe(
2668
+ "Bearer <<funfetti-auth-jwt>>"
2669
+ );
2286
2670
 
2287
- const body = JSON.parse(init.body as string) as UploadPayloadFile[];
2288
- expect(body).toMatchObject([
2289
- {
2290
- key: "1a98fb08af91aca4a7df1764a2c4ddb0",
2291
- value: Buffer.from("foobar").toString("base64"),
2292
- metadata: {
2293
- contentType: "text/plain",
2294
- },
2295
- base64: true,
2671
+ const body = (await init.json()) as UploadPayloadFile[];
2672
+ expect(body).toMatchObject([
2673
+ {
2674
+ key: "1a98fb08af91aca4a7df1764a2c4ddb0",
2675
+ value: Buffer.from("foobar").toString("base64"),
2676
+ metadata: {
2677
+ contentType: "text/plain",
2296
2678
  },
2297
- ]);
2298
- });
2679
+ base64: true,
2680
+ },
2681
+ ]);
2299
2682
  }
2300
2683
 
2301
2684
  expect(std.out).toMatchInlineSnapshot(`
@@ -2313,33 +2696,52 @@ and that at least one include rule is provided.
2313
2696
 
2314
2697
  mockGetToken("<<funfetti-auth-jwt>>");
2315
2698
 
2316
- setMockResponse(
2317
- "/pages/assets/check-missing",
2318
- "POST",
2319
- async (_, init) => {
2320
- const body = JSON.parse(init.body as string) as { hashes: string[] };
2321
- assertLater(() => {
2322
- expect(init.headers).toMatchObject({
2323
- Authorization: "Bearer <<funfetti-auth-jwt>>",
2324
- });
2325
- expect(body).toMatchObject({
2326
- hashes: expect.arrayContaining([
2327
- "d96fef225537c9f5e44a3cb27fd0b492",
2328
- "2082190357cfd3617ccfe04f340c6247",
2329
- "6be321bef99e758250dac034474ddbb8",
2330
- "1a98fb08af91aca4a7df1764a2c4ddb0",
2331
- ]),
2332
- });
2699
+ // Accumulate multiple requests then assert afterwards
2700
+ const requests: RestRequest[] = [];
2701
+ msw.use(
2702
+ rest.post("*/pages/assets/check-missing", async (req, res, ctx) => {
2703
+ const body = (await req.json()) as { hashes: string[] };
2704
+
2705
+ expect(req.headers.get("Authorization")).toBe(
2706
+ "Bearer <<funfetti-auth-jwt>>"
2707
+ );
2708
+ expect(body).toMatchObject({
2709
+ hashes: expect.arrayContaining([
2710
+ "d96fef225537c9f5e44a3cb27fd0b492",
2711
+ "2082190357cfd3617ccfe04f340c6247",
2712
+ "6be321bef99e758250dac034474ddbb8",
2713
+ "1a98fb08af91aca4a7df1764a2c4ddb0",
2714
+ ]),
2333
2715
  });
2334
- return body.hashes;
2335
- }
2336
- );
2337
2716
 
2338
- // Accumulate multiple requests then assert afterwards
2339
- const requests: RequestInit[] = [];
2340
- setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
2341
- requests.push(init);
2342
- });
2717
+ return res.once(
2718
+ ctx.status(200),
2719
+ ctx.json({
2720
+ success: true,
2721
+ errors: [],
2722
+ messages: [],
2723
+ result: body.hashes,
2724
+ })
2725
+ );
2726
+ }),
2727
+ rest.post("*/pages/assets/upload", async (req, res, ctx) => {
2728
+ requests.push(req);
2729
+
2730
+ expect(req.headers.get("Authorization")).toBe(
2731
+ "Bearer <<funfetti-auth-jwt>>"
2732
+ );
2733
+
2734
+ return res(
2735
+ ctx.status(200),
2736
+ ctx.json({
2737
+ success: true,
2738
+ errors: [],
2739
+ messages: [],
2740
+ result: null,
2741
+ })
2742
+ );
2743
+ })
2744
+ );
2343
2745
 
2344
2746
  await runWrangler("pages project upload .");
2345
2747
 
@@ -2347,10 +2749,7 @@ and that at least one include rule is provided.
2347
2749
  expect(requests.length).toBe(3);
2348
2750
  const bodies: UploadPayloadFile[][] = [];
2349
2751
  for (const init of requests) {
2350
- expect(init.headers).toMatchObject({
2351
- Authorization: "Bearer <<funfetti-auth-jwt>>",
2352
- });
2353
- bodies.push(JSON.parse(init.body as string) as UploadPayloadFile[]);
2752
+ bodies.push((await init.json()) as UploadPayloadFile[]);
2354
2753
  }
2355
2754
  // One bucket should end up with 2 files
2356
2755
  expect(bodies.map((b) => b.length).sort()).toEqual([1, 1, 2]);
@@ -2399,29 +2798,36 @@ and that at least one include rule is provided.
2399
2798
 
2400
2799
  mockGetToken("<<funfetti-auth-jwt>>");
2401
2800
 
2402
- setMockResponse(
2403
- "/pages/assets/check-missing",
2404
- "POST",
2405
- async (_, init) => {
2406
- const body = JSON.parse(init.body as string) as { hashes: string[] };
2407
- assertLater(() => {
2408
- expect(init.headers).toMatchObject({
2409
- Authorization: "Bearer <<funfetti-auth-jwt>>",
2410
- });
2801
+ msw.use(
2802
+ rest.post(
2803
+ "*/pages/assets/check-missing",
2804
+
2805
+ async (req, res, ctx) => {
2806
+ const body = (await req.json()) as { hashes: string[] };
2807
+
2808
+ expect(req.headers.get("Authorization")).toBe(
2809
+ "Bearer <<funfetti-auth-jwt>>"
2810
+ );
2411
2811
  expect(body).toMatchObject({
2412
2812
  hashes: ["7b764dacfd211bebd8077828a7ddefd7"],
2413
2813
  });
2414
- });
2415
- return body.hashes;
2416
- }
2417
- );
2418
2814
 
2419
- setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
2420
- assertLater(() => {
2421
- expect(init.headers).toMatchObject({
2422
- Authorization: "Bearer <<funfetti-auth-jwt>>",
2423
- });
2424
- const body = JSON.parse(init.body as string) as UploadPayloadFile[];
2815
+ return res.once(
2816
+ ctx.status(200),
2817
+ ctx.json({
2818
+ success: true,
2819
+ errors: [],
2820
+ messages: [],
2821
+ result: body.hashes,
2822
+ })
2823
+ );
2824
+ }
2825
+ ),
2826
+ rest.post("*/pages/assets/upload", async (req, res, ctx) => {
2827
+ expect(req.headers.get("Authorization")).toBe(
2828
+ "Bearer <<funfetti-auth-jwt>>"
2829
+ );
2830
+ const body = (await req.json()) as UploadPayloadFile[];
2425
2831
  expect(body).toMatchObject([
2426
2832
  {
2427
2833
  key: "7b764dacfd211bebd8077828a7ddefd7",
@@ -2432,8 +2838,18 @@ and that at least one include rule is provided.
2432
2838
  base64: true,
2433
2839
  },
2434
2840
  ]);
2435
- });
2436
- });
2841
+
2842
+ return res.once(
2843
+ ctx.status(200),
2844
+ ctx.json({
2845
+ success: true,
2846
+ errors: [],
2847
+ messages: [],
2848
+ result: null,
2849
+ })
2850
+ );
2851
+ })
2852
+ );
2437
2853
 
2438
2854
  await runWrangler("pages project upload .");
2439
2855
 
@@ -2441,3 +2857,43 @@ and that at least one include rule is provided.
2441
2857
  });
2442
2858
  });
2443
2859
  });
2860
+
2861
+ function mockFormDataToString(this: FormData) {
2862
+ const entries = [];
2863
+ for (const [key, value] of this.entries()) {
2864
+ if (value instanceof Blob) {
2865
+ const reader = new FileReaderSync();
2866
+ reader.readAsText(value);
2867
+ const result = reader.result;
2868
+ entries.push([key, result]);
2869
+ } else {
2870
+ entries.push([key, value]);
2871
+ }
2872
+ }
2873
+ return JSON.stringify({
2874
+ __formdata: entries,
2875
+ });
2876
+ }
2877
+
2878
+ async function mockFormDataFromString(this: MockedRequest): Promise<FormData> {
2879
+ const { __formdata } = await this.json();
2880
+ expect(__formdata).toBeInstanceOf(Array);
2881
+
2882
+ const form = new FormData();
2883
+ for (const [key, value] of __formdata) {
2884
+ form.set(key, value);
2885
+ }
2886
+ return form;
2887
+ }
2888
+
2889
+ // The following two functions workaround the fact that MSW does not yet support FormData in requests.
2890
+ // We use the fact that MSW relies upon `node-fetch` internally, which will call `toString()` on the FormData object,
2891
+ // rather than passing it through or serializing it as a proper FormData object.
2892
+ // The hack is to serialize FormData to a JSON string by overriding `FormData.toString()`.
2893
+ // And then to deserialize back to a FormData object by monkey-patching a `formData()` helper onto `MockedRequest`.
2894
+ FormData.prototype.toString = mockFormDataToString;
2895
+ export interface RestRequestWithFormData extends MockedRequest, RestRequest {
2896
+ formData(): Promise<FormData>;
2897
+ }
2898
+ (MockedRequest.prototype as RestRequestWithFormData).formData =
2899
+ mockFormDataFromString;