wrangler 2.6.1 → 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 (130) 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 -42
  21. package/src/__tests__/init.test.ts +782 -522
  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 +1618 -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 +16 -18
  42. package/src/cli.ts +2 -2
  43. package/src/config/index.ts +2 -1
  44. package/src/config/validation.ts +1 -2
  45. package/src/create-worker-upload-form.ts +2 -2
  46. package/src/d1/{delete.tsx → delete.ts} +0 -0
  47. package/src/d1/execute.tsx +8 -37
  48. package/src/d1/migrations/apply.tsx +32 -19
  49. package/src/d1/migrations/{index.tsx → index.ts} +0 -0
  50. package/src/d1/splitter.ts +161 -0
  51. package/src/d1/{types.tsx → types.ts} +0 -0
  52. package/src/delete.ts +3 -8
  53. package/src/deployments.ts +6 -0
  54. package/src/deprecated/index.ts +2 -295
  55. package/src/dev/dev.tsx +2 -2
  56. package/src/dev/{get-local-persistence-path.tsx → get-local-persistence-path.ts} +0 -0
  57. package/src/dev/local.tsx +16 -4
  58. package/src/dev/remote.tsx +28 -1
  59. package/src/dev/start-server.ts +19 -11
  60. package/src/dev/use-esbuild.ts +1 -1
  61. package/src/{dev-registry.tsx → dev-registry.ts} +0 -0
  62. package/src/dev.tsx +35 -11
  63. package/src/dialogs.ts +136 -0
  64. package/src/dispatch-namespace.ts +1 -1
  65. package/src/docs/index.ts +97 -0
  66. package/src/environment-variables/factory.ts +88 -0
  67. package/src/environment-variables/misc-variables.ts +30 -0
  68. package/src/generate/index.ts +300 -0
  69. package/src/{index.tsx → index.ts} +16 -10
  70. package/src/init.ts +106 -60
  71. package/src/jest.d.ts +4 -0
  72. package/src/logger.ts +15 -3
  73. package/src/metrics/metrics-config.ts +1 -1
  74. package/src/metrics/send-event.ts +2 -1
  75. package/src/miniflare-cli/assets.ts +4 -0
  76. package/src/miniflare-cli/index.ts +1 -5
  77. package/src/miniflare-cli/tsconfig.json +9 -0
  78. package/src/miniflare-cli/tsconfig.tsbuildinfo +1 -0
  79. package/src/miniflare-cli/types.ts +11 -0
  80. package/src/pages/{build.tsx → build.ts} +0 -0
  81. package/src/pages/{deployment-tails.tsx → deployment-tails.ts} +0 -0
  82. package/src/pages/{dev.tsx → dev.ts} +53 -55
  83. package/src/pages/functions/buildWorker.ts +1 -1
  84. package/src/pages/functions/tsconfig.json +8 -0
  85. package/src/pages/functions/tsconfig.tsbuildinfo +1 -0
  86. package/src/pages/{functions.tsx → functions.ts} +0 -0
  87. package/src/pages/{hash.tsx → hash.ts} +0 -0
  88. package/src/pages/{index.tsx → index.ts} +0 -0
  89. package/src/pages/projects.tsx +3 -5
  90. package/src/pages/publish.tsx +16 -5
  91. package/src/pages/upload.tsx +27 -6
  92. package/src/publish/publish.ts +9 -7
  93. package/src/pubsub/{pubsub-commands.tsx → pubsub-commands.ts} +1 -1
  94. package/src/secret/index.ts +1 -1
  95. package/src/{sites.tsx → sites.ts} +0 -0
  96. package/src/tail/index.ts +2 -3
  97. package/src/tsconfig-sanity.ts +16 -0
  98. package/src/user/access.ts +0 -1
  99. package/src/user/auth-variables.ts +113 -0
  100. package/src/user/choose-account.tsx +1 -31
  101. package/src/user/index.ts +0 -1
  102. package/src/user/{user.tsx → user.ts} +107 -73
  103. package/src/{whoami.tsx → whoami.ts} +37 -71
  104. package/templates/__tests__/tsconfig-sanity.ts +12 -0
  105. package/templates/__tests__/tsconfig.json +8 -0
  106. package/templates/__tests__/tsconfig.tsbuildinfo +1 -0
  107. package/templates/d1-beta-facade.js +36 -0
  108. package/templates/facade.d.ts +14 -0
  109. package/templates/first-party-worker-module-facade.ts +4 -3
  110. package/templates/format-dev-errors.ts +7 -6
  111. package/templates/init-tests/test-jest-new-worker.js +3 -5
  112. package/templates/init-tests/test-vitest-new-worker.js +3 -5
  113. package/templates/init-tests/test-vitest-new-worker.ts +25 -0
  114. package/templates/middleware/loader-modules.ts +0 -2
  115. package/templates/middleware/loader-sw.ts +6 -0
  116. package/templates/pages-dev-pipeline.ts +4 -1
  117. package/templates/pages-shim.ts +4 -1
  118. package/templates/pages-template-plugin.ts +12 -7
  119. package/templates/serve-static-assets.ts +16 -14
  120. package/templates/tsconfig-sanity.ts +11 -0
  121. package/templates/tsconfig.init.json +106 -0
  122. package/templates/tsconfig.json +5 -103
  123. package/templates/tsconfig.tsbuildinfo +1 -0
  124. package/wrangler-dist/cli.d.ts +58 -60
  125. package/wrangler-dist/cli.js +34498 -55459
  126. package/wrangler-dist/wasm-sync.wasm +0 -0
  127. package/src/__tests__/dialogs.test.tsx +0 -40
  128. package/src/dialogs.tsx +0 -168
  129. package/src/environment-variables.ts +0 -50
  130. 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
 
@@ -335,6 +350,7 @@ describe("pages", () => {
335
350
  --commit-hash The SHA to attach to this deployment [string]
336
351
  --commit-message The commit message to attach to this deployment [string]
337
352
  --commit-dirty Whether or not the workspace should be considered dirty for this deployment [boolean]
353
+ --skip-caching Skip asset caching which speeds up builds [boolean]
338
354
 
339
355
  🚧 'wrangler pages <command>' is a beta command. Please report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose"
340
356
  `);
@@ -342,33 +358,34 @@ describe("pages", () => {
342
358
 
343
359
  it("should upload a directory of files", async () => {
344
360
  writeFileSync("logo.png", "foobar");
345
-
346
361
  mockGetToken("<<funfetti-auth-jwt>>");
347
362
 
348
- setMockResponse(
349
- "/pages/assets/check-missing",
350
- "POST",
351
- async (_, init) => {
352
- const body = JSON.parse(init.body as string) as { hashes: string[] };
353
- assertLater(() => {
354
- expect(init.headers).toMatchObject({
355
- Authorization: "Bearer <<funfetti-auth-jwt>>",
356
- });
357
- expect(body).toMatchObject({
358
- hashes: ["2082190357cfd3617ccfe04f340c6247"],
359
- });
360
- });
361
- return body.hashes;
362
- }
363
- );
363
+ msw.use(
364
+ rest.post("*/pages/assets/check-missing", async (req, res, ctx) => {
365
+ const body = await req.json();
364
366
 
365
- setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
366
- assertLater(() => {
367
- expect(init.headers).toMatchObject({
368
- 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"],
369
372
  });
370
- const body = JSON.parse(init.body as string) as UploadPayloadFile[];
371
- 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([
372
389
  {
373
390
  key: "2082190357cfd3617ccfe04f340c6247",
374
391
  value: Buffer.from("foobar").toString("base64"),
@@ -378,39 +395,55 @@ describe("pages", () => {
378
395
  base64: true,
379
396
  },
380
397
  ]);
381
- });
382
- });
383
-
384
- setMockResponse(
385
- "/accounts/:accountId/pages/projects/foo/deployments",
386
- async ([_url, accountId], init) => {
387
- assertLater(() => {
388
- expect(accountId).toEqual("some-account-id");
389
- expect(init.method).toEqual("POST");
390
- const body = init.body as FormData;
391
- const manifest = JSON.parse(body.get("manifest") as string);
392
- expect(manifest).toMatchInlineSnapshot(`
393
- Object {
394
- "/logo.png": "2082190357cfd3617ccfe04f340c6247",
395
- }
396
- `);
397
- });
398
-
399
- return {
400
- url: "https://abcxyz.foo.pages.dev/",
401
- };
402
- }
403
- );
404
-
405
- setMockResponse(
406
- "/accounts/:accountId/pages/projects/foo",
407
- "GET",
408
- async ([_url, accountId]) => {
409
- assertLater(() => {
410
- expect(accountId).toEqual("some-account-id");
411
- });
412
- 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
+ ],
413
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
+ )
414
447
  );
415
448
 
416
449
  await runWrangler("pages publish . --project-name=foo");
@@ -427,84 +460,35 @@ describe("pages", () => {
427
460
 
428
461
  mockGetToken("<<funfetti-auth-jwt>>");
429
462
 
430
- setMockResponse(
431
- "/pages/assets/check-missing",
432
- "POST",
433
- async (_, init) => {
434
- const body = JSON.parse(init.body as string) as { hashes: string[] };
435
- assertLater(() => {
436
- expect(init.headers).toMatchObject({
437
- Authorization: "Bearer <<funfetti-auth-jwt>>",
438
- });
439
- expect(body).toMatchObject({
440
- hashes: ["1a98fb08af91aca4a7df1764a2c4ddb0"],
441
- });
442
- });
443
- return body.hashes;
444
- }
445
- );
446
-
447
463
  // Accumulate multiple requests then assert afterwards
448
- const requests: RequestInit[] = [];
449
- setMockRawResponse("/pages/assets/upload", "POST", async (_, init) => {
450
- requests.push(init);
451
-
452
- if (requests.length < 2) {
453
- return createFetchResult(null, false, [
454
- {
455
- code: 800000,
456
- message: "Something exploded, please retry",
457
- },
458
- ]);
459
- } else {
460
- return createFetchResult(null, true);
461
- }
462
- });
463
-
464
- setMockResponse(
465
- "/accounts/:accountId/pages/projects/foo/deployments",
466
- async ([_url, accountId], init) => {
467
- assertLater(() => {
468
- expect(accountId).toEqual("some-account-id");
469
- expect(init.method).toEqual("POST");
470
- const body = init.body as FormData;
471
- const manifest = JSON.parse(body.get("manifest") as string);
472
- expect(manifest).toMatchInlineSnapshot(`
473
- Object {
474
- "/logo.txt": "1a98fb08af91aca4a7df1764a2c4ddb0",
475
- }
476
- `);
477
- });
478
-
479
- return {
480
- url: "https://abcxyz.foo.pages.dev/",
481
- };
482
- }
483
- );
484
-
485
- setMockResponse(
486
- "/accounts/:accountId/pages/projects/foo",
487
- "GET",
488
- async ([_url, accountId]) => {
489
- assertLater(() => {
490
- expect(accountId).toEqual("some-account-id");
491
- });
492
- return { deployment_configs: { production: {}, preview: {} } };
493
- }
494
- );
495
-
496
- 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();
497
468
 
498
- // Assert two identical requests
499
- expect(requests.length).toBe(2);
500
- for (const init of requests) {
501
- assertLater(() => {
502
- expect(init.headers).toMatchObject({
503
- 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"],
504
474
  });
505
475
 
506
- const body = JSON.parse(init.body as string) as UploadPayloadFile[];
507
- 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([
508
492
  {
509
493
  key: "1a98fb08af91aca4a7df1764a2c4ddb0",
510
494
  value: Buffer.from("foobar").toString("base64"),
@@ -514,8 +498,80 @@ describe("pages", () => {
514
498
  base64: true,
515
499
  },
516
500
  ]);
517
- });
518
- }
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");
519
575
 
520
576
  expect(std.out).toMatchInlineSnapshot(`
521
577
  "✨ Success! Uploaded 1 files (TIMINGS)
@@ -526,104 +582,125 @@ describe("pages", () => {
526
582
 
527
583
  it("should refetch a JWT if it expires while uploading", async () => {
528
584
  writeFileSync("logo.txt", "foobar");
585
+ mockGetToken("<<funfetti-auth-jwt>>");
529
586
 
530
- 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[] };
531
591
 
532
- setMockResponse(
533
- "/pages/assets/check-missing",
534
- "POST",
535
- async (_, init) => {
536
- const body = JSON.parse(init.body as string) as { hashes: string[] };
537
- assertLater(() => {
538
- expect(init.headers).toMatchObject({
539
- Authorization: "Bearer <<funfetti-auth-jwt>>",
540
- });
541
- expect(body).toMatchObject({
542
- hashes: ["1a98fb08af91aca4a7df1764a2c4ddb0"],
543
- });
592
+ expect(req.headers.get("Authorization")).toBe(
593
+ "Bearer <<funfetti-auth-jwt>>"
594
+ );
595
+ expect(body).toMatchObject({
596
+ hashes: ["1a98fb08af91aca4a7df1764a2c4ddb0"],
544
597
  });
545
- return body.hashes;
546
- }
547
- );
548
598
 
549
- // Accumulate multiple requests then assert afterwards
550
- const requests: RequestInit[] = [];
551
- setMockRawResponse("/pages/assets/upload", "POST", async (_, init) => {
552
- requests.push(init);
553
-
554
- // Fail just the first request
555
- if (requests.length < 2) {
556
- cancelMockGetToken();
557
- mockGetToken("<<funfetti-auth-jwt2>>");
558
- 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([
559
612
  {
560
- code: 8000013,
561
- message: "Authorization failed",
613
+ key: "1a98fb08af91aca4a7df1764a2c4ddb0",
614
+ value: Buffer.from("foobar").toString("base64"),
615
+ metadata: {
616
+ contentType: "text/plain",
617
+ },
618
+ base64: true,
562
619
  },
563
620
  ]);
564
- } else {
565
- return createFetchResult(null, true);
566
- }
567
- });
568
-
569
- setMockResponse(
570
- "/accounts/:accountId/pages/projects/foo/deployments",
571
- async ([_url, accountId], init) => {
572
- assertLater(() => {
573
- expect(accountId).toEqual("some-account-id");
574
- expect(init.method).toEqual("POST");
575
- const body = init.body as FormData;
576
- const manifest = JSON.parse(body.get("manifest") as string);
577
- expect(manifest).toMatchInlineSnapshot(`
578
- Object {
579
- "/logo.txt": "1a98fb08af91aca4a7df1764a2c4ddb0",
580
- }
581
- `);
582
- });
583
-
584
- return {
585
- url: "https://abcxyz.foo.pages.dev/",
586
- };
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
+ ],
587
663
  }
588
- );
664
+ `);
589
665
 
590
- setMockResponse(
591
- "/accounts/:accountId/pages/projects/foo",
592
- "GET",
593
- async ([_url, accountId]) => {
594
- assertLater(() => {
595
- expect(accountId).toEqual("some-account-id");
596
- });
597
- return { deployment_configs: { production: {}, preview: {} } };
598
- }
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
+ )
599
693
  );
600
694
 
601
695
  await runWrangler("pages publish . --project-name=foo");
602
696
 
603
- // Assert two requests
604
- expect(requests.length).toBe(2);
605
-
606
- expect(requests[0].headers).toMatchObject({
607
- Authorization: "Bearer <<funfetti-auth-jwt>>",
608
- });
609
-
610
- expect(requests[1].headers).toMatchObject({
611
- Authorization: "Bearer <<funfetti-auth-jwt2>>",
612
- });
697
+ expect(requests[0].headers.get("Authorization")).toBe(
698
+ "Bearer <<funfetti-auth-jwt>>"
699
+ );
613
700
 
614
- for (const init of requests) {
615
- const body = JSON.parse(init.body as string) as UploadPayloadFile[];
616
- expect(body).toMatchObject([
617
- {
618
- key: "1a98fb08af91aca4a7df1764a2c4ddb0",
619
- value: Buffer.from("foobar").toString("base64"),
620
- metadata: {
621
- contentType: "text/plain",
622
- },
623
- base64: true,
624
- },
625
- ]);
626
- }
701
+ expect(requests[1].headers.get("Authorization")).toBe(
702
+ "Bearer <<funfetti-auth-jwt2>>"
703
+ );
627
704
 
628
705
  expect(std.out).toMatchInlineSnapshot(`
629
706
  "✨ Success! Uploaded 1 files (TIMINGS)
@@ -640,80 +717,110 @@ describe("pages", () => {
640
717
 
641
718
  mockGetToken("<<funfetti-auth-jwt>>");
642
719
 
643
- setMockResponse(
644
- "/pages/assets/check-missing",
645
- "POST",
646
- async (_, init) => {
647
- const body = JSON.parse(init.body as string) as { hashes: string[] };
648
- assertLater(() => {
649
- expect(init.headers).toMatchObject({
650
- Authorization: "Bearer <<funfetti-auth-jwt>>",
651
- });
652
- expect(body).toMatchObject({
653
- hashes: expect.arrayContaining([
654
- "d96fef225537c9f5e44a3cb27fd0b492",
655
- "2082190357cfd3617ccfe04f340c6247",
656
- "6be321bef99e758250dac034474ddbb8",
657
- "1a98fb08af91aca4a7df1764a2c4ddb0",
658
- ]),
659
- });
660
- });
661
- return body.hashes;
662
- }
663
- );
664
-
665
720
  // Accumulate multiple requests then assert afterwards
666
- const requests: RequestInit[] = [];
667
- setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
668
- requests.push(init);
669
- });
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
+ };
670
728
 
671
- setMockResponse(
672
- "/accounts/:accountId/pages/projects/foo/deployments",
673
- async ([_url, accountId], init) => {
674
- assertLater(() => {
675
- expect(accountId).toEqual("some-account-id");
676
- expect(init.method).toEqual("POST");
677
- const body = init.body as FormData;
678
- const manifest = JSON.parse(body.get("manifest") as string);
679
- expect(manifest).toMatchInlineSnapshot(`
680
- Object {
681
- "/logo.html": "d96fef225537c9f5e44a3cb27fd0b492",
682
- "/logo.js": "6be321bef99e758250dac034474ddbb8",
683
- "/logo.png": "2082190357cfd3617ccfe04f340c6247",
684
- "/logo.txt": "1a98fb08af91aca4a7df1764a2c4ddb0",
685
- }
686
- `);
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
+ ]),
687
739
  });
688
740
 
689
- return {
690
- url: "https://abcxyz.foo.pages.dev/",
691
- };
692
- }
693
- );
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);
694
753
 
695
- setMockResponse(
696
- "/accounts/:accountId/pages/projects/foo",
697
- "GET",
698
- async ([_url, accountId]) => {
699
- assertLater(() => {
700
- expect(accountId).toEqual("some-account-id");
701
- });
702
- return { deployment_configs: { production: {}, preview: {} } };
703
- }
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
+ )
704
817
  );
705
818
 
706
819
  await runWrangler("pages publish . --project-name=foo");
707
820
 
708
821
  // We have 3 buckets, so expect 3 uploads
709
822
  expect(requests.length).toBe(3);
710
- const bodies: UploadPayloadFile[][] = [];
711
- for (const init of requests) {
712
- expect(init.headers).toMatchObject({
713
- Authorization: "Bearer <<funfetti-auth-jwt>>",
714
- });
715
- bodies.push(JSON.parse(init.body as string) as UploadPayloadFile[]);
716
- }
823
+
717
824
  // One bucket should end up with 2 files
718
825
  expect(bodies.map((b) => b.length).sort()).toEqual([1, 1, 2]);
719
826
  // But we don't know the order, so flatten and test without ordering
@@ -763,82 +870,105 @@ describe("pages", () => {
763
870
 
764
871
  mockGetToken("<<funfetti-auth-jwt>>");
765
872
 
766
- setMockResponse(
767
- "/pages/assets/check-missing",
768
- "POST",
769
- async (_, init) => {
770
- 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 {
771
879
  hashes: string[];
772
880
  };
773
- assertLater(() => {
774
- expect(init.headers).toMatchObject({
775
- Authorization: "Bearer <<funfetti-auth-jwt>>",
776
- });
777
- expect(body).toMatchObject({
778
- hashes: expect.arrayContaining([
779
- "d96fef225537c9f5e44a3cb27fd0b492",
780
- "2082190357cfd3617ccfe04f340c6247",
781
- "6be321bef99e758250dac034474ddbb8",
782
- "1a98fb08af91aca4a7df1764a2c4ddb0",
783
- ]),
784
- });
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
+ ]),
785
892
  });
786
- return body.hashes;
787
- }
788
- );
789
893
 
790
- // Accumulate multiple requests then assert afterwards
791
- const requests: RequestInit[] = [];
792
- setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
793
- requests.push(init);
794
- });
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);
795
906
 
796
- setMockResponse(
797
- "/accounts/:accountId/pages/projects/foo/deployments",
798
- async ([_url, accountId], init) => {
799
- assertLater(() => {
800
- expect(accountId).toEqual("some-account-id");
801
- expect(init.method).toEqual("POST");
802
- 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();
803
927
  const manifest = JSON.parse(body.get("manifest") as string);
804
928
  expect(manifest).toMatchInlineSnapshot(`
805
- Object {
806
- "/imgs/logo.png": "2082190357cfd3617ccfe04f340c6247",
807
- "/logo.html": "d96fef225537c9f5e44a3cb27fd0b492",
808
- "/logo.js": "6be321bef99e758250dac034474ddbb8",
809
- "/logo.txt": "1a98fb08af91aca4a7df1764a2c4ddb0",
810
- }
811
- `);
812
- });
813
-
814
- return {
815
- url: "https://abcxyz.foo.pages.dev/",
816
- };
817
- }
818
- );
819
-
820
- setMockResponse(
821
- "/accounts/:accountId/pages/projects/foo",
822
- "GET",
823
- async ([_url, accountId]) => {
824
- assertLater(() => {
825
- expect(accountId).toEqual("some-account-id");
826
- });
827
- return { deployment_configs: { production: {}, preview: {} } };
828
- }
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
+ )
829
966
  );
830
967
 
831
968
  await runWrangler(`pages publish public --project-name=foo`);
832
969
 
833
970
  // We have 3 buckets, so expect 3 uploads
834
971
  expect(requests.length).toBe(3);
835
- const bodies: UploadPayloadFile[][] = [];
836
- for (const init of requests) {
837
- expect(init.headers).toMatchObject({
838
- Authorization: "Bearer <<funfetti-auth-jwt>>",
839
- });
840
- bodies.push(JSON.parse(init.body as string) as UploadPayloadFile[]);
841
- }
842
972
  // One bucket should end up with 2 files
843
973
  expect(bodies.map((b) => b.length).sort()).toEqual([1, 1, 2]);
844
974
  // But we don't know the order, so flatten and test without ordering
@@ -888,83 +1018,106 @@ describe("pages", () => {
888
1018
 
889
1019
  mockGetToken("<<funfetti-auth-jwt>>");
890
1020
 
891
- setMockResponse(
892
- "/pages/assets/check-missing",
893
- "POST",
894
- async (_, init) => {
895
- 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 {
896
1027
  hashes: string[];
897
1028
  };
898
- assertLater(() => {
899
- expect(init.headers).toMatchObject({
900
- Authorization: "Bearer <<funfetti-auth-jwt>>",
901
- });
902
- expect(body).toMatchObject({
903
- hashes: expect.arrayContaining([
904
- "d96fef225537c9f5e44a3cb27fd0b492",
905
- "2082190357cfd3617ccfe04f340c6247",
906
- "6be321bef99e758250dac034474ddbb8",
907
- "1a98fb08af91aca4a7df1764a2c4ddb0",
908
- ]),
909
- });
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
+ ]),
910
1040
  });
911
- return body.hashes;
912
- }
913
- );
914
1041
 
915
- // Accumulate multiple requests then assert afterwards
916
- const requests: RequestInit[] = [];
917
- setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
918
- requests.push(init);
919
- });
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");
920
1074
 
921
- setMockResponse(
922
- "/accounts/:accountId/pages/projects/foo/deployments",
923
- async ([_url, accountId], init) => {
924
- assertLater(() => {
925
- expect(accountId).toEqual("some-account-id");
926
- expect(init.method).toEqual("POST");
927
- const body = init.body as FormData;
1075
+ const body = await (req as RestRequestWithFormData).formData();
928
1076
  const manifest = JSON.parse(body.get("manifest") as string);
929
1077
  expect(manifest).toMatchInlineSnapshot(`
930
- Object {
931
- "/imgs/logo.png": "2082190357cfd3617ccfe04f340c6247",
932
- "/logo.html": "d96fef225537c9f5e44a3cb27fd0b492",
933
- "/logo.js": "6be321bef99e758250dac034474ddbb8",
934
- "/logo.txt": "1a98fb08af91aca4a7df1764a2c4ddb0",
935
- }
936
- `);
937
- });
938
-
939
- return {
940
- url: "https://abcxyz.foo.pages.dev/",
941
- };
942
- }
943
- );
944
-
945
- setMockResponse(
946
- "/accounts/:accountId/pages/projects/foo",
947
- "GET",
948
- async ([_url, accountId]) => {
949
- assertLater(() => {
950
- expect(accountId).toEqual("some-account-id");
951
- });
952
- return { deployment_configs: { production: {}, preview: {} } };
953
- }
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
+ )
954
1115
  );
955
1116
 
956
1117
  chdir("public");
957
1118
  await runWrangler(`pages publish . --project-name=foo`);
958
-
959
1119
  // We have 3 buckets, so expect 3 uploads
960
1120
  expect(requests.length).toBe(3);
961
- const bodies: UploadPayloadFile[][] = [];
962
- for (const init of requests) {
963
- expect(init.headers).toMatchObject({
964
- Authorization: "Bearer <<funfetti-auth-jwt>>",
965
- });
966
- bodies.push(JSON.parse(init.body as string) as UploadPayloadFile[]);
967
- }
968
1121
  // One bucket should end up with 2 files
969
1122
  expect(bodies.map((b) => b.length).sort()).toEqual([1, 1, 2]);
970
1123
  // But we don't know the order, so flatten and test without ordering
@@ -1012,29 +1165,35 @@ describe("pages", () => {
1012
1165
 
1013
1166
  mockGetToken("<<funfetti-auth-jwt>>");
1014
1167
 
1015
- setMockResponse(
1016
- "/pages/assets/check-missing",
1017
- "POST",
1018
- async (_, init) => {
1019
- const body = JSON.parse(init.body as string) as { hashes: string[] };
1020
- assertLater(() => {
1021
- expect(init.headers).toMatchObject({
1022
- Authorization: "Bearer <<funfetti-auth-jwt>>",
1023
- });
1024
- expect(body).toMatchObject({
1025
- hashes: ["7b764dacfd211bebd8077828a7ddefd7"],
1026
- });
1027
- });
1028
- return body.hashes;
1029
- }
1030
- );
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
+ };
1031
1173
 
1032
- setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
1033
- assertLater(() => {
1034
- expect(init.headers).toMatchObject({
1035
- 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"],
1036
1179
  });
1037
- 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[];
1038
1197
  expect(body).toMatchObject([
1039
1198
  {
1040
1199
  key: "7b764dacfd211bebd8077828a7ddefd7",
@@ -1045,25 +1204,50 @@ describe("pages", () => {
1045
1204
  base64: true,
1046
1205
  },
1047
1206
  ]);
1048
- });
1049
- });
1050
-
1051
- setMockResponse(
1052
- "/accounts/:accountId/pages/projects/foo/deployments",
1053
- async () => ({
1054
- url: "https://abcxyz.foo.pages.dev/",
1055
- })
1056
- );
1057
-
1058
- setMockResponse(
1059
- "/accounts/:accountId/pages/projects/foo",
1060
- "GET",
1061
- async ([_url, accountId]) => {
1062
- assertLater(() => {
1063
- expect(accountId).toEqual("some-account-id");
1064
- });
1065
- return { deployment_configs: { production: {}, preview: {} } };
1066
- }
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
+ )
1067
1251
  );
1068
1252
 
1069
1253
  await runWrangler("pages publish . --project-name=foo");
@@ -1102,30 +1286,35 @@ describe("pages", () => {
1102
1286
 
1103
1287
  mockGetToken("<<funfetti-auth-jwt>>");
1104
1288
 
1105
- setMockResponse(
1106
- "/pages/assets/check-missing",
1107
- "POST",
1108
- async (_, init) => {
1109
- const body = JSON.parse(init.body as string) as { hashes: string[] };
1110
- assertLater(() => {
1111
- expect(init.headers).toMatchObject({
1112
- Authorization: "Bearer <<funfetti-auth-jwt>>",
1113
- });
1114
- expect(body).toMatchObject({
1115
- hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1116
- });
1117
- });
1118
- return body.hashes;
1119
- }
1120
- );
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
+ };
1121
1294
 
1122
- setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
1123
- assertLater(() => {
1124
- expect(init.headers).toMatchObject({
1125
- 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"],
1126
1300
  });
1127
- const body = JSON.parse(init.body as string) as UploadPayloadFile[];
1128
- 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([
1129
1318
  {
1130
1319
  key: "13a03eaf24ae98378acd36ea00f77f2f",
1131
1320
  value: Buffer.from("This is a readme").toString("base64"),
@@ -1135,46 +1324,51 @@ describe("pages", () => {
1135
1324
  base64: true,
1136
1325
  },
1137
1326
  ]);
1138
- });
1139
- });
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
+ );
1140
1341
 
1141
- setMockResponse(
1142
- `/pages/assets/upsert-hashes`,
1143
- "POST",
1144
- async (_, init) => {
1145
- assertLater(() => {
1146
- expect(init.headers).toMatchObject({
1147
- Authorization: "Bearer <<funfetti-auth-jwt>>",
1148
- });
1149
- const body = JSON.parse(init.body as string) as UploadPayloadFile[];
1150
- expect(body).toMatchObject({
1151
- hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1152
- });
1342
+ expect(await req.json()).toMatchObject({
1343
+ hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1153
1344
  });
1154
1345
 
1155
- return Promise.resolve(true);
1156
- }
1157
- );
1346
+ return res.once(
1347
+ ctx.status(200),
1348
+ ctx.json({
1349
+ success: true,
1350
+ errors: [],
1351
+ messages: [],
1352
+ result: true,
1353
+ })
1354
+ );
1355
+ }),
1158
1356
 
1159
- setMockResponse(
1160
- "/accounts/:accountId/pages/projects/foo/deployments",
1161
- async ([_url, accountId], init) => {
1162
- assertLater(async () => {
1163
- expect(accountId).toEqual("some-account-id");
1164
- expect(init.method).toEqual("POST");
1165
- 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();
1166
1362
  const manifest = JSON.parse(body.get("manifest") as string);
1167
1363
 
1168
1364
  // for Functions projects, we auto-generate a `_worker.js`,
1169
1365
  // `functions-filepath-routing-config.json`, and `_routes.json`
1170
1366
  // file, based on the contents of `/functions`
1171
- const generatedWorkerJS = body.get("_worker.js") as Blob;
1172
- const generatedRoutesJSON = await (
1173
- body.get("_routes.json") as Blob
1174
- ).text();
1175
- const generatedFilepathRoutingConfig = await (
1176
- body.get("functions-filepath-routing-config.json") as Blob
1177
- ).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;
1178
1372
 
1179
1373
  // make sure this is all we uploaded
1180
1374
  expect([...body.keys()]).toEqual([
@@ -1185,10 +1379,10 @@ describe("pages", () => {
1185
1379
  ]);
1186
1380
 
1187
1381
  expect(manifest).toMatchInlineSnapshot(`
1188
- Object {
1189
- "/README.md": "13a03eaf24ae98378acd36ea00f77f2f",
1190
- }
1191
- `);
1382
+ Object {
1383
+ "/README.md": "13a03eaf24ae98378acd36ea00f77f2f",
1384
+ }
1385
+ `);
1192
1386
 
1193
1387
  // the contents of the generated `_worker.js` file is pretty massive, so I don't
1194
1388
  // think snapshot testing makes much sense here. Plus, calling
@@ -1197,7 +1391,7 @@ describe("pages", () => {
1197
1391
  // file contents is too big). So for now, let's test that _worker.js was indeed
1198
1392
  // generated and that the file size is greater than zero
1199
1393
  expect(generatedWorkerJS).not.toBeNull();
1200
- expect(generatedWorkerJS.size).toBeGreaterThan(0);
1394
+ expect(generatedWorkerJS.length).toBeGreaterThan(0);
1201
1395
 
1202
1396
  const maybeRoutesJSONSpec = JSON.parse(generatedRoutesJSON);
1203
1397
  expect(isRoutesJSONSpec(maybeRoutesJSONSpec)).toBe(true);
@@ -1226,23 +1420,38 @@ describe("pages", () => {
1226
1420
  ],
1227
1421
  baseURL: "/",
1228
1422
  });
1229
- });
1230
-
1231
- return {
1232
- url: "https://abcxyz.foo.pages.dev/",
1233
- };
1234
- }
1235
- );
1236
1423
 
1237
- setMockResponse(
1238
- "/accounts/:accountId/pages/projects/foo",
1239
- "GET",
1240
- async ([_url, accountId]) => {
1241
- assertLater(() => {
1242
- expect(accountId).toEqual("some-account-id");
1243
- });
1244
- return { deployment_configs: { production: {}, preview: {} } };
1245
- }
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
+ )
1246
1455
  );
1247
1456
 
1248
1457
  await runWrangler("pages publish public --project-name=foo");
@@ -1277,30 +1486,35 @@ describe("pages", () => {
1277
1486
 
1278
1487
  mockGetToken("<<funfetti-auth-jwt>>");
1279
1488
 
1280
- setMockResponse(
1281
- "/pages/assets/check-missing",
1282
- "POST",
1283
- async (_, init) => {
1284
- const body = JSON.parse(init.body as string) as { hashes: string[] };
1285
- assertLater(() => {
1286
- expect(init.headers).toMatchObject({
1287
- Authorization: "Bearer <<funfetti-auth-jwt>>",
1288
- });
1289
- expect(body).toMatchObject({
1290
- hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1291
- });
1292
- });
1293
- return body.hashes;
1294
- }
1295
- );
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
+ };
1296
1494
 
1297
- setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
1298
- assertLater(() => {
1299
- expect(init.headers).toMatchObject({
1300
- 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"],
1301
1500
  });
1302
- const body = JSON.parse(init.body as string) as UploadPayloadFile[];
1303
- 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([
1304
1518
  {
1305
1519
  key: "13a03eaf24ae98378acd36ea00f77f2f",
1306
1520
  value: Buffer.from("This is a readme").toString("base64"),
@@ -1310,56 +1524,75 @@ describe("pages", () => {
1310
1524
  base64: true,
1311
1525
  },
1312
1526
  ]);
1313
- });
1314
- });
1315
-
1316
- setMockResponse(
1317
- "/accounts/:accountId/pages/projects/foo/deployments",
1318
- async ([_url, accountId], init) => {
1319
- assertLater(async () => {
1320
- expect(accountId).toEqual("some-account-id");
1321
- expect(init.method).toEqual("POST");
1322
- 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();
1323
1542
  const manifest = JSON.parse(body.get("manifest") as string);
1324
- const customWorkerJS = await (
1325
- body.get("_worker.js") as Blob
1326
- ).text();
1543
+ const customWorkerJS = body.get("_worker.js");
1327
1544
 
1328
1545
  // make sure this is all we uploaded
1329
- expect([...body.keys()]).toEqual(["manifest", "_worker.js"]);
1546
+ expect([...body.keys()].sort()).toEqual(
1547
+ ["manifest", "_worker.js"].sort()
1548
+ );
1330
1549
 
1331
1550
  expect(manifest).toMatchInlineSnapshot(`
1332
- Object {
1333
- "/README.md": "13a03eaf24ae98378acd36ea00f77f2f",
1334
- }
1335
- `);
1551
+ Object {
1552
+ "/README.md": "13a03eaf24ae98378acd36ea00f77f2f",
1553
+ }
1554
+ `);
1336
1555
 
1337
1556
  expect(customWorkerJS).toMatchInlineSnapshot(`
1338
- "
1339
- export default {
1340
- async fetch(request, env) {
1341
- const url = new URL(request.url);
1342
- return url.pathname.startsWith('/api/') ? new Response('Ok') : env.ASSETS.fetch(request);
1343
- };
1344
1557
  "
1345
- `);
1346
- });
1347
-
1348
- return {
1349
- url: "https://abcxyz.foo.pages.dev/",
1350
- };
1351
- }
1352
- );
1353
-
1354
- setMockResponse(
1355
- "/accounts/:accountId/pages/projects/foo",
1356
- "GET",
1357
- async ([_url, accountId]) => {
1358
- assertLater(() => {
1359
- expect(accountId).toEqual("some-account-id");
1360
- });
1361
- return { deployment_configs: { production: {}, preview: {} } };
1362
- }
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
+ )
1363
1596
  );
1364
1597
 
1365
1598
  await runWrangler("pages publish public --project-name=foo");
@@ -1413,31 +1646,35 @@ describe("pages", () => {
1413
1646
  );
1414
1647
 
1415
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
+ };
1416
1654
 
1417
- setMockResponse(
1418
- "/pages/assets/check-missing",
1419
- "POST",
1420
- async (_, init) => {
1421
- const body = JSON.parse(init.body as string) as { hashes: string[] };
1422
- assertLater(() => {
1423
- expect(init.headers).toMatchObject({
1424
- Authorization: "Bearer <<funfetti-auth-jwt>>",
1425
- });
1426
- expect(body).toMatchObject({
1427
- hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1428
- });
1655
+ expect(req.headers.get("Authorization")).toBe(
1656
+ "Bearer <<funfetti-auth-jwt>>"
1657
+ );
1658
+ expect(body).toMatchObject({
1659
+ hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1429
1660
  });
1430
- return body.hashes;
1431
- }
1432
- );
1433
1661
 
1434
- setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
1435
- assertLater(() => {
1436
- expect(init.headers).toMatchObject({
1437
- Authorization: "Bearer <<funfetti-auth-jwt>>",
1438
- });
1439
- const body = JSON.parse(init.body as string) as UploadPayloadFile[];
1440
- 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([
1441
1678
  {
1442
1679
  key: "13a03eaf24ae98378acd36ea00f77f2f",
1443
1680
  value: Buffer.from("This is a readme").toString("base64"),
@@ -1447,60 +1684,67 @@ describe("pages", () => {
1447
1684
  base64: true,
1448
1685
  },
1449
1686
  ]);
1450
- });
1451
- });
1452
1687
 
1453
- setMockResponse(
1454
- `/pages/assets/upsert-hashes`,
1455
- "POST",
1456
- async (_, init) => {
1457
- assertLater(() => {
1458
- expect(init.headers).toMatchObject({
1459
- Authorization: "Bearer <<funfetti-auth-jwt>>",
1460
- });
1461
- const body = JSON.parse(init.body as string) as UploadPayloadFile[];
1462
- expect(body).toMatchObject({
1463
- hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1464
- });
1465
- });
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
+ );
1466
1702
 
1467
- return Promise.resolve(true);
1468
- }
1469
- );
1703
+ expect(await req.json()).toMatchObject({
1704
+ hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1705
+ });
1470
1706
 
1471
- setMockResponse(
1472
- "/accounts/:accountId/pages/projects/foo/deployments",
1473
- async ([_url, accountId], init) => {
1474
- assertLater(async () => {
1475
- expect(accountId).toEqual("some-account-id");
1476
- expect(init.method).toEqual("POST");
1477
- 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();
1478
1722
  const manifest = JSON.parse(body.get("manifest") as string);
1479
- const generatedWorkerJS = body.get("_worker.js") as Blob;
1480
- const customRoutesJSON = await (
1481
- body.get("_routes.json") as Blob
1482
- ).text();
1483
- const generatedFilepathRoutingConfig = await (
1484
- body.get("functions-filepath-routing-config.json") as Blob
1485
- ).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;
1486
1728
 
1487
1729
  // make sure this is all we uploaded
1488
- expect([...body.keys()]).toEqual([
1489
- "manifest",
1490
- "functions-filepath-routing-config.json",
1491
- "_worker.js",
1492
- "_routes.json",
1493
- ]);
1730
+ expect([...body.keys()].sort()).toEqual(
1731
+ [
1732
+ "manifest",
1733
+ "functions-filepath-routing-config.json",
1734
+ "_worker.js",
1735
+ "_routes.json",
1736
+ ].sort()
1737
+ );
1494
1738
 
1495
1739
  expect(manifest).toMatchInlineSnapshot(`
1496
- Object {
1497
- "/README.md": "13a03eaf24ae98378acd36ea00f77f2f",
1498
- }
1499
- `);
1740
+ Object {
1741
+ "/README.md": "13a03eaf24ae98378acd36ea00f77f2f",
1742
+ }
1743
+ `);
1500
1744
 
1501
1745
  // file content of generated `_worker.js` is too massive to snapshot test
1502
1746
  expect(generatedWorkerJS).not.toBeNull();
1503
- expect(generatedWorkerJS.size).toBeGreaterThan(0);
1747
+ expect(generatedWorkerJS.length).toBeGreaterThan(0);
1504
1748
 
1505
1749
  const customRoutes = JSON.parse(customRoutesJSON);
1506
1750
  expect(customRoutes).toMatchObject({
@@ -1517,7 +1761,6 @@ describe("pages", () => {
1517
1761
  // The actual shape doesn't matter that much since this
1518
1762
  // is only used for display in Dash, but it's still useful for
1519
1763
  // tracking unexpected changes to this config.
1520
- console.log(generatedFilepathRoutingConfig);
1521
1764
  expect(parsedFilepathRoutingConfig).toStrictEqual({
1522
1765
  routes: [
1523
1766
  {
@@ -1535,23 +1778,38 @@ describe("pages", () => {
1535
1778
  ],
1536
1779
  baseURL: "/",
1537
1780
  });
1538
- });
1539
-
1540
- return {
1541
- url: "https://abcxyz.foo.pages.dev/",
1542
- };
1543
- }
1544
- );
1545
1781
 
1546
- setMockResponse(
1547
- "/accounts/:accountId/pages/projects/foo",
1548
- "GET",
1549
- async ([_url, accountId]) => {
1550
- assertLater(() => {
1551
- expect(accountId).toEqual("some-account-id");
1552
- });
1553
- return { deployment_configs: { production: {}, preview: {} } };
1554
- }
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
+ )
1555
1813
  );
1556
1814
 
1557
1815
  await runWrangler("pages publish public --project-name=foo");
@@ -1603,31 +1861,35 @@ describe("pages", () => {
1603
1861
  );
1604
1862
 
1605
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
+ };
1606
1869
 
1607
- setMockResponse(
1608
- "/pages/assets/check-missing",
1609
- "POST",
1610
- async (_, init) => {
1611
- const body = JSON.parse(init.body as string) as { hashes: string[] };
1612
- assertLater(() => {
1613
- expect(init.headers).toMatchObject({
1614
- Authorization: "Bearer <<funfetti-auth-jwt>>",
1615
- });
1616
- expect(body).toMatchObject({
1617
- hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1618
- });
1870
+ expect(req.headers.get("Authorization")).toBe(
1871
+ "Bearer <<funfetti-auth-jwt>>"
1872
+ );
1873
+ expect(body).toMatchObject({
1874
+ hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1619
1875
  });
1620
- return body.hashes;
1621
- }
1622
- );
1623
1876
 
1624
- setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
1625
- assertLater(() => {
1626
- expect(init.headers).toMatchObject({
1627
- Authorization: "Bearer <<funfetti-auth-jwt>>",
1628
- });
1629
- const body = JSON.parse(init.body as string) as UploadPayloadFile[];
1630
- 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([
1631
1893
  {
1632
1894
  key: "13a03eaf24ae98378acd36ea00f77f2f",
1633
1895
  value: Buffer.from("This is a readme").toString("base64"),
@@ -1637,18 +1899,35 @@ describe("pages", () => {
1637
1899
  base64: true,
1638
1900
  },
1639
1901
  ]);
1640
- });
1641
- });
1642
1902
 
1643
- setMockResponse(
1644
- "/accounts/:accountId/pages/projects/foo",
1645
- "GET",
1646
- async ([_url, accountId]) => {
1647
- assertLater(() => {
1648
- expect(accountId).toEqual("some-account-id");
1649
- });
1650
- return { deployment_configs: { production: {}, preview: {} } };
1651
- }
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
+ )
1652
1931
  );
1653
1932
 
1654
1933
  await expect(runWrangler("pages publish public --project-name=foo"))
@@ -1696,30 +1975,35 @@ and that at least one include rule is provided.
1696
1975
 
1697
1976
  mockGetToken("<<funfetti-auth-jwt>>");
1698
1977
 
1699
- setMockResponse(
1700
- "/pages/assets/check-missing",
1701
- "POST",
1702
- async (_, init) => {
1703
- const body = JSON.parse(init.body as string) as { hashes: string[] };
1704
- assertLater(() => {
1705
- expect(init.headers).toMatchObject({
1706
- Authorization: "Bearer <<funfetti-auth-jwt>>",
1707
- });
1708
- expect(body).toMatchObject({
1709
- hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1710
- });
1711
- });
1712
- return body.hashes;
1713
- }
1714
- );
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
+ };
1715
1983
 
1716
- setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
1717
- assertLater(() => {
1718
- expect(init.headers).toMatchObject({
1719
- 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"],
1720
1989
  });
1721
- const body = JSON.parse(init.body as string) as UploadPayloadFile[];
1722
- 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([
1723
2007
  {
1724
2008
  key: "13a03eaf24ae98378acd36ea00f77f2f",
1725
2009
  value: Buffer.from("This is a readme").toString("base64"),
@@ -1729,41 +2013,44 @@ and that at least one include rule is provided.
1729
2013
  base64: true,
1730
2014
  },
1731
2015
  ]);
1732
- });
1733
- });
1734
2016
 
1735
- setMockResponse(
1736
- `/pages/assets/upsert-hashes`,
1737
- "POST",
1738
- async (_, init) => {
1739
- assertLater(() => {
1740
- expect(init.headers).toMatchObject({
1741
- Authorization: "Bearer <<funfetti-auth-jwt>>",
1742
- });
1743
- const body = JSON.parse(init.body as string) as UploadPayloadFile[];
1744
- expect(body).toMatchObject({
1745
- hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1746
- });
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"],
1747
2034
  });
1748
2035
 
1749
- return Promise.resolve(true);
1750
- }
1751
- );
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();
1752
2050
 
1753
- setMockResponse(
1754
- "/accounts/:accountId/pages/projects/foo/deployments",
1755
- async ([_url, accountId], init) => {
1756
- assertLater(async () => {
1757
- expect(accountId).toEqual("some-account-id");
1758
- expect(init.method).toEqual("POST");
1759
- const body = init.body as FormData;
1760
2051
  const manifest = JSON.parse(body.get("manifest") as string);
1761
- const customWorkerJS = await (
1762
- body.get("_worker.js") as Blob
1763
- ).text();
1764
- const customRoutesJSON = await (
1765
- body.get("_routes.json") as Blob
1766
- ).text();
2052
+ const customWorkerJS = body.get("_worker.js") as string;
2053
+ const customRoutesJSON = body.get("_routes.json") as string;
1767
2054
 
1768
2055
  // make sure this is all we uploaded
1769
2056
  expect([...body.keys()]).toEqual([
@@ -1771,47 +2058,61 @@ and that at least one include rule is provided.
1771
2058
  "_worker.js",
1772
2059
  "_routes.json",
1773
2060
  ]);
1774
-
2061
+ expect(req.params.accountId).toEqual("some-account-id");
1775
2062
  expect(manifest).toMatchInlineSnapshot(`
1776
- Object {
1777
- "/README.md": "13a03eaf24ae98378acd36ea00f77f2f",
1778
- }
1779
- `);
2063
+ Object {
2064
+ "/README.md": "13a03eaf24ae98378acd36ea00f77f2f",
2065
+ }
2066
+ `);
1780
2067
 
1781
2068
  expect(customWorkerJS).toMatchInlineSnapshot(`
1782
- "
1783
- export default {
1784
- async fetch(request, env) {
1785
- const url = new URL(request.url);
1786
- return url.pathname.startsWith('/api/') ? new Response('Ok') : env.ASSETS.fetch(request);
1787
- };
1788
2069
  "
1789
- `);
1790
-
1791
- const customRoutes = JSON.parse(customRoutesJSON);
1792
- 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({
1793
2079
  version: ROUTES_SPEC_VERSION,
1794
2080
  description: "Custom _routes.json file",
1795
2081
  include: ["/api/*"],
1796
2082
  exclude: [],
1797
2083
  });
1798
- });
1799
-
1800
- return {
1801
- url: "https://abcxyz.foo.pages.dev/",
1802
- };
1803
- }
1804
- );
1805
2084
 
1806
- setMockResponse(
1807
- "/accounts/:accountId/pages/projects/foo",
1808
- "GET",
1809
- async ([_url, accountId]) => {
1810
- assertLater(() => {
1811
- expect(accountId).toEqual("some-account-id");
1812
- });
1813
- return { deployment_configs: { production: {}, preview: {} } };
1814
- }
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
+ )
1815
2116
  );
1816
2117
 
1817
2118
  await runWrangler("pages publish public --project-name=foo");
@@ -1863,30 +2164,35 @@ and that at least one include rule is provided.
1863
2164
 
1864
2165
  mockGetToken("<<funfetti-auth-jwt>>");
1865
2166
 
1866
- setMockResponse(
1867
- "/pages/assets/check-missing",
1868
- "POST",
1869
- async (_, init) => {
1870
- const body = JSON.parse(init.body as string) as { hashes: string[] };
1871
- assertLater(() => {
1872
- expect(init.headers).toMatchObject({
1873
- Authorization: "Bearer <<funfetti-auth-jwt>>",
1874
- });
1875
- expect(body).toMatchObject({
1876
- hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1877
- });
1878
- });
1879
- return body.hashes;
1880
- }
1881
- );
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
+ };
1882
2172
 
1883
- setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
1884
- assertLater(() => {
1885
- expect(init.headers).toMatchObject({
1886
- 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"],
1887
2178
  });
1888
- const body = JSON.parse(init.body as string) as UploadPayloadFile[];
1889
- 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([
1890
2196
  {
1891
2197
  key: "13a03eaf24ae98378acd36ea00f77f2f",
1892
2198
  value: Buffer.from("This is a readme").toString("base64"),
@@ -1896,18 +2202,35 @@ and that at least one include rule is provided.
1896
2202
  base64: true,
1897
2203
  },
1898
2204
  ]);
1899
- });
1900
- });
1901
2205
 
1902
- setMockResponse(
1903
- "/accounts/:accountId/pages/projects/foo",
1904
- "GET",
1905
- async ([_url, accountId]) => {
1906
- assertLater(() => {
1907
- expect(accountId).toEqual("some-account-id");
1908
- });
1909
- return { deployment_configs: { production: {}, preview: {} } };
1910
- }
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
+ )
1911
2234
  );
1912
2235
 
1913
2236
  await expect(runWrangler("pages publish public --project-name=foo"))
@@ -1953,30 +2276,35 @@ and that at least one include rule is provided.
1953
2276
 
1954
2277
  mockGetToken("<<funfetti-auth-jwt>>");
1955
2278
 
1956
- setMockResponse(
1957
- "/pages/assets/check-missing",
1958
- "POST",
1959
- async (_, init) => {
1960
- const body = JSON.parse(init.body as string) as { hashes: string[] };
1961
- assertLater(() => {
1962
- expect(init.headers).toMatchObject({
1963
- Authorization: "Bearer <<funfetti-auth-jwt>>",
1964
- });
1965
- expect(body).toMatchObject({
1966
- hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
1967
- });
1968
- });
1969
- return body.hashes;
1970
- }
1971
- );
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
+ };
1972
2284
 
1973
- setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
1974
- assertLater(() => {
1975
- expect(init.headers).toMatchObject({
1976
- 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"],
1977
2290
  });
1978
- const body = JSON.parse(init.body as string) as UploadPayloadFile[];
1979
- 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([
1980
2308
  {
1981
2309
  key: "13a03eaf24ae98378acd36ea00f77f2f",
1982
2310
  value: Buffer.from("This is a readme").toString("base64"),
@@ -1986,56 +2314,76 @@ and that at least one include rule is provided.
1986
2314
  base64: true,
1987
2315
  },
1988
2316
  ]);
1989
- });
1990
- });
1991
2317
 
1992
- setMockResponse(
1993
- "/accounts/:accountId/pages/projects/foo/deployments",
1994
- async ([_url, accountId], init) => {
1995
- assertLater(async () => {
1996
- expect(accountId).toEqual("some-account-id");
1997
- expect(init.method).toEqual("POST");
1998
- 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();
1999
2333
  const manifest = JSON.parse(body.get("manifest") as string);
2000
- const customWorkerJS = await (
2001
- body.get("_worker.js") as Blob
2002
- ).text();
2334
+ const customWorkerJS = body.get("_worker.js");
2003
2335
 
2336
+ expect(req.params.accountId).toEqual("some-account-id");
2004
2337
  // make sure this is all we uploaded
2005
- expect([...body.keys()]).toEqual(["manifest", "_worker.js"]);
2006
-
2338
+ expect([...body.keys()].sort()).toEqual(
2339
+ ["manifest", "_worker.js"].sort()
2340
+ );
2007
2341
  expect(manifest).toMatchInlineSnapshot(`
2008
- Object {
2009
- "/README.md": "13a03eaf24ae98378acd36ea00f77f2f",
2010
- }
2011
- `);
2012
-
2342
+ Object {
2343
+ "/README.md": "13a03eaf24ae98378acd36ea00f77f2f",
2344
+ }
2345
+ `);
2013
2346
  expect(customWorkerJS).toMatchInlineSnapshot(`
2014
- "
2015
- export default {
2016
- async fetch(request, env) {
2017
- const url = new URL(request.url);
2018
- return url.pathname.startsWith('/api/') ? new Response('Ok') : env.ASSETS.fetch(request);
2019
- };
2020
2347
  "
2021
- `);
2022
- });
2023
-
2024
- return {
2025
- url: "https://abcxyz.foo.pages.dev/",
2026
- };
2027
- }
2028
- );
2029
-
2030
- setMockResponse(
2031
- "/accounts/:accountId/pages/projects/foo",
2032
- "GET",
2033
- async ([_url, accountId]) => {
2034
- assertLater(() => {
2035
- expect(accountId).toEqual("some-account-id");
2036
- });
2037
- return { deployment_configs: { production: {}, preview: {} } };
2038
- }
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
+ )
2039
2387
  );
2040
2388
 
2041
2389
  await runWrangler("pages publish public --project-name=foo");
@@ -2064,48 +2412,62 @@ and that at least one include rule is provided.
2064
2412
  });
2065
2413
 
2066
2414
  afterEach(() => {
2067
- unsetAllMocks();
2068
2415
  process.env = ENV_COPY;
2069
2416
  });
2070
2417
 
2071
2418
  it("should upload a directory of files with a provided JWT", async () => {
2072
2419
  writeFileSync("logo.png", "foobar");
2073
2420
 
2074
- setMockResponse(
2075
- "/pages/assets/check-missing",
2076
- "POST",
2077
- async (_, init) => {
2078
- const body = JSON.parse(init.body as string) as { hashes: string[] };
2079
- assertLater(() => {
2080
- expect(init.headers).toMatchObject({
2081
- Authorization: "Bearer <<funfetti-auth-jwt>>",
2082
- });
2083
- expect(body).toMatchObject({
2084
- hashes: ["2082190357cfd3617ccfe04f340c6247"],
2085
- });
2086
- });
2087
- return body.hashes;
2088
- }
2089
- );
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
+ };
2090
2426
 
2091
- setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
2092
- assertLater(() => {
2093
- expect(init.headers).toMatchObject({
2094
- 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"],
2095
2432
  });
2096
- const body = JSON.parse(init.body as string) as UploadPayloadFile[];
2097
- 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([
2098
2450
  {
2451
+ base64: true,
2099
2452
  key: "2082190357cfd3617ccfe04f340c6247",
2100
- value: Buffer.from("foobar").toString("base64"),
2101
2453
  metadata: {
2102
2454
  contentType: "image/png",
2103
2455
  },
2104
- base64: true,
2456
+ value: "Zm9vYmFy",
2105
2457
  },
2106
2458
  ]);
2107
- });
2108
- });
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
+ );
2109
2471
 
2110
2472
  await runWrangler("pages project upload .");
2111
2473
 
@@ -2134,100 +2496,103 @@ and that at least one include rule is provided.
2134
2496
  mkdirSync("functions");
2135
2497
  writeFileSync("functions/foo.js", "func");
2136
2498
 
2137
- setMockResponse(
2138
- "/pages/assets/check-missing",
2139
- "POST",
2140
- async (_, init) => {
2141
- const body = JSON.parse(init.body as string) as { hashes: string[] };
2142
- assertLater(() => {
2143
- expect(init.headers).toMatchObject({
2144
- Authorization: "Bearer <<funfetti-auth-jwt>>",
2145
- });
2146
- expect(body).toMatchObject({
2147
- hashes: [
2148
- "2082190357cfd3617ccfe04f340c6247",
2149
- "95dedb64e6d4940fc2e0f11f711cc2f4",
2150
- "09a79777abda8ccc8bdd51dd3ff8e9e9",
2151
- ],
2152
- });
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
+ ],
2153
2516
  });
2154
- return body.hashes;
2155
- }
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
+ })
2156
2541
  );
2157
2542
 
2158
- // Accumulate multiple requests then assert afterwards
2159
- const requests: RequestInit[] = [];
2160
- setMockRawResponse("/pages/assets/upload", "POST", async (_, init) => {
2161
- requests.push(init);
2543
+ await runWrangler("pages project upload .");
2162
2544
 
2163
- return createFetchResult(null, true);
2164
- });
2545
+ expect(requests.length).toBe(3);
2165
2546
 
2166
- assertLater(() => {
2167
- expect(requests.length).toBe(3);
2547
+ const resolvedRequests = await Promise.all(
2548
+ requests.map(async (req) => await req.json<UploadPayloadFile>())
2549
+ );
2168
2550
 
2169
- const sortedRequests = requests.sort((a, b) => {
2170
- return (JSON.parse(a.body as string)[0].key as string).localeCompare(
2171
- JSON.parse(b.body as string)[0].key as string
2172
- );
2173
- });
2551
+ const sortedRequests = resolvedRequests.sort((a, b) => {
2552
+ const aKey = a.key as string;
2553
+ const bKey = b.key as string;
2174
2554
 
2175
- expect(sortedRequests[0].headers).toMatchObject({
2176
- Authorization: "Bearer <<funfetti-auth-jwt>>",
2177
- });
2178
-
2179
- let body = JSON.parse(
2180
- sortedRequests[0].body as string
2181
- ) as UploadPayloadFile[];
2182
- expect(body).toMatchObject([
2183
- {
2184
- key: "09a79777abda8ccc8bdd51dd3ff8e9e9",
2185
- value: Buffer.from("func").toString("base64"),
2186
- metadata: {
2187
- contentType: "application/javascript",
2188
- },
2189
- base64: true,
2190
- },
2191
- ]);
2555
+ return aKey?.localeCompare(bKey);
2556
+ });
2192
2557
 
2193
- expect(sortedRequests[1].headers).toMatchObject({
2194
- Authorization: "Bearer <<funfetti-auth-jwt>>",
2195
- });
2558
+ for (const req of requests) {
2559
+ expect(req.headers.get("Authorization")).toBe(
2560
+ "Bearer <<funfetti-auth-jwt>>"
2561
+ );
2562
+ }
2196
2563
 
2197
- body = JSON.parse(
2198
- sortedRequests[1].body as string
2199
- ) as UploadPayloadFile[];
2200
- expect(body).toMatchObject([
2201
- {
2202
- key: "2082190357cfd3617ccfe04f340c6247",
2203
- value: Buffer.from("foobar").toString("base64"),
2204
- metadata: {
2205
- contentType: "image/png",
2206
- },
2207
- base64: true,
2564
+ expect(sortedRequests[0]).toMatchObject([
2565
+ {
2566
+ base64: true,
2567
+ key: "95dedb64e6d4940fc2e0f11f711cc2f4",
2568
+ metadata: {
2569
+ contentType: "application/octet-stream",
2208
2570
  },
2209
- ]);
2210
-
2211
- expect(sortedRequests[2].headers).toMatchObject({
2212
- Authorization: "Bearer <<funfetti-auth-jwt>>",
2213
- });
2571
+ value: "aGVhZGVyc2ZpbGU=",
2572
+ },
2573
+ ]);
2214
2574
 
2215
- body = JSON.parse(
2216
- sortedRequests[2].body as string
2217
- ) as UploadPayloadFile[];
2218
- expect(body).toMatchObject([
2219
- {
2220
- key: "95dedb64e6d4940fc2e0f11f711cc2f4",
2221
- value: Buffer.from("headersfile").toString("base64"),
2222
- metadata: {
2223
- contentType: "application/octet-stream",
2224
- },
2225
- base64: true,
2575
+ expect(sortedRequests[1]).toMatchObject([
2576
+ {
2577
+ base64: true,
2578
+ key: "2082190357cfd3617ccfe04f340c6247",
2579
+ metadata: {
2580
+ contentType: "image/png",
2226
2581
  },
2227
- ]);
2228
- });
2582
+ value: "Zm9vYmFy",
2583
+ },
2584
+ ]);
2229
2585
 
2230
- 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
+ ]);
2231
2596
 
2232
2597
  expect(std.out).toMatchInlineSnapshot(`
2233
2598
  "✨ Success! Uploaded 3 files (TIMINGS)
@@ -2239,62 +2604,81 @@ and that at least one include rule is provided.
2239
2604
  it("should retry uploads", async () => {
2240
2605
  writeFileSync("logo.txt", "foobar");
2241
2606
 
2242
- setMockResponse(
2243
- "/pages/assets/check-missing",
2244
- "POST",
2245
- async (_, init) => {
2246
- const body = JSON.parse(init.body as string) as { hashes: string[] };
2247
- assertLater(() => {
2248
- expect(init.headers).toMatchObject({
2249
- Authorization: "Bearer <<funfetti-auth-jwt>>",
2250
- });
2251
- expect(body).toMatchObject({
2252
- hashes: ["1a98fb08af91aca4a7df1764a2c4ddb0"],
2253
- });
2254
- });
2255
- return body.hashes;
2256
- }
2257
- );
2258
-
2259
2607
  // Accumulate multiple requests then assert afterwards
2260
- const requests: RequestInit[] = [];
2261
- setMockRawResponse("/pages/assets/upload", "POST", async (_, init) => {
2262
- 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[] };
2263
2612
 
2264
- if (requests.length < 2) {
2265
- return createFetchResult(null, false, [
2266
- {
2267
- code: 800000,
2268
- message: "Something exploded, please retry",
2269
- },
2270
- ]);
2271
- } else {
2272
- return createFetchResult(null, true);
2273
- }
2274
- });
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
+ );
2275
2661
 
2276
2662
  await runWrangler("pages project upload .");
2277
2663
 
2278
2664
  // Assert two identical requests
2279
2665
  expect(requests.length).toBe(2);
2280
2666
  for (const init of requests) {
2281
- assertLater(() => {
2282
- expect(init.headers).toMatchObject({
2283
- Authorization: "Bearer <<funfetti-auth-jwt>>",
2284
- });
2667
+ expect(init.headers.get("Authorization")).toBe(
2668
+ "Bearer <<funfetti-auth-jwt>>"
2669
+ );
2285
2670
 
2286
- const body = JSON.parse(init.body as string) as UploadPayloadFile[];
2287
- expect(body).toMatchObject([
2288
- {
2289
- key: "1a98fb08af91aca4a7df1764a2c4ddb0",
2290
- value: Buffer.from("foobar").toString("base64"),
2291
- metadata: {
2292
- contentType: "text/plain",
2293
- },
2294
- 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",
2295
2678
  },
2296
- ]);
2297
- });
2679
+ base64: true,
2680
+ },
2681
+ ]);
2298
2682
  }
2299
2683
 
2300
2684
  expect(std.out).toMatchInlineSnapshot(`
@@ -2312,33 +2696,52 @@ and that at least one include rule is provided.
2312
2696
 
2313
2697
  mockGetToken("<<funfetti-auth-jwt>>");
2314
2698
 
2315
- setMockResponse(
2316
- "/pages/assets/check-missing",
2317
- "POST",
2318
- async (_, init) => {
2319
- const body = JSON.parse(init.body as string) as { hashes: string[] };
2320
- assertLater(() => {
2321
- expect(init.headers).toMatchObject({
2322
- Authorization: "Bearer <<funfetti-auth-jwt>>",
2323
- });
2324
- expect(body).toMatchObject({
2325
- hashes: expect.arrayContaining([
2326
- "d96fef225537c9f5e44a3cb27fd0b492",
2327
- "2082190357cfd3617ccfe04f340c6247",
2328
- "6be321bef99e758250dac034474ddbb8",
2329
- "1a98fb08af91aca4a7df1764a2c4ddb0",
2330
- ]),
2331
- });
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
+ ]),
2332
2715
  });
2333
- return body.hashes;
2334
- }
2335
- );
2336
2716
 
2337
- // Accumulate multiple requests then assert afterwards
2338
- const requests: RequestInit[] = [];
2339
- setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
2340
- requests.push(init);
2341
- });
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
+ );
2342
2745
 
2343
2746
  await runWrangler("pages project upload .");
2344
2747
 
@@ -2346,10 +2749,7 @@ and that at least one include rule is provided.
2346
2749
  expect(requests.length).toBe(3);
2347
2750
  const bodies: UploadPayloadFile[][] = [];
2348
2751
  for (const init of requests) {
2349
- expect(init.headers).toMatchObject({
2350
- Authorization: "Bearer <<funfetti-auth-jwt>>",
2351
- });
2352
- bodies.push(JSON.parse(init.body as string) as UploadPayloadFile[]);
2752
+ bodies.push((await init.json()) as UploadPayloadFile[]);
2353
2753
  }
2354
2754
  // One bucket should end up with 2 files
2355
2755
  expect(bodies.map((b) => b.length).sort()).toEqual([1, 1, 2]);
@@ -2398,29 +2798,36 @@ and that at least one include rule is provided.
2398
2798
 
2399
2799
  mockGetToken("<<funfetti-auth-jwt>>");
2400
2800
 
2401
- setMockResponse(
2402
- "/pages/assets/check-missing",
2403
- "POST",
2404
- async (_, init) => {
2405
- const body = JSON.parse(init.body as string) as { hashes: string[] };
2406
- assertLater(() => {
2407
- expect(init.headers).toMatchObject({
2408
- Authorization: "Bearer <<funfetti-auth-jwt>>",
2409
- });
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
+ );
2410
2811
  expect(body).toMatchObject({
2411
2812
  hashes: ["7b764dacfd211bebd8077828a7ddefd7"],
2412
2813
  });
2413
- });
2414
- return body.hashes;
2415
- }
2416
- );
2417
2814
 
2418
- setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
2419
- assertLater(() => {
2420
- expect(init.headers).toMatchObject({
2421
- Authorization: "Bearer <<funfetti-auth-jwt>>",
2422
- });
2423
- 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[];
2424
2831
  expect(body).toMatchObject([
2425
2832
  {
2426
2833
  key: "7b764dacfd211bebd8077828a7ddefd7",
@@ -2431,8 +2838,18 @@ and that at least one include rule is provided.
2431
2838
  base64: true,
2432
2839
  },
2433
2840
  ]);
2434
- });
2435
- });
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
+ );
2436
2853
 
2437
2854
  await runWrangler("pages project upload .");
2438
2855
 
@@ -2440,3 +2857,43 @@ and that at least one include rule is provided.
2440
2857
  });
2441
2858
  });
2442
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;