wrangler 2.0.6 → 2.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/bin/wrangler.js +16 -4
- package/package.json +6 -4
- package/pages/functions/buildPlugin.ts +13 -0
- package/pages/functions/buildWorker.ts +13 -0
- package/src/__tests__/configuration.test.ts +132 -60
- package/src/__tests__/dev.test.tsx +168 -67
- package/src/__tests__/helpers/mock-dialogs.ts +41 -1
- package/src/__tests__/index.test.ts +25 -10
- package/src/__tests__/init.test.ts +252 -131
- package/src/__tests__/kv.test.ts +16 -16
- package/src/__tests__/package-manager.test.ts +154 -7
- package/src/__tests__/pages.test.ts +442 -38
- package/src/__tests__/parse.test.ts +5 -1
- package/src/__tests__/publish.test.ts +377 -84
- package/src/__tests__/secret.test.ts +4 -4
- package/src/__tests__/whoami.test.tsx +34 -0
- package/src/abort.d.ts +3 -0
- package/src/cfetch/index.ts +21 -4
- package/src/cfetch/internal.ts +20 -18
- package/src/config/config.ts +1 -1
- package/src/config/index.ts +162 -0
- package/src/config/validation.ts +77 -29
- package/src/create-worker-preview.ts +32 -22
- package/src/dev/dev.tsx +6 -16
- package/src/dev/remote.tsx +40 -16
- package/src/dialogs.tsx +48 -0
- package/src/durable.ts +102 -0
- package/src/index.tsx +291 -207
- package/src/inspect.ts +39 -0
- package/src/kv.ts +74 -25
- package/src/open-in-browser.ts +5 -12
- package/src/package-manager.ts +50 -3
- package/src/pages.tsx +218 -61
- package/src/parse.ts +21 -4
- package/src/proxy.ts +38 -22
- package/src/publish.ts +166 -108
- package/src/sites.tsx +8 -8
- package/src/user.tsx +12 -1
- package/src/whoami.tsx +3 -2
- package/src/worker.ts +2 -1
- package/src/zones.ts +73 -0
- package/templates/new-worker-scheduled.js +17 -0
- package/templates/new-worker-scheduled.ts +32 -0
- package/templates/new-worker.ts +16 -1
- package/wrangler-dist/cli.js +33066 -20052
|
@@ -1,11 +1,35 @@
|
|
|
1
1
|
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { mockAccountId, mockApiToken } from "./helpers/mock-account-id";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
createFetchResult,
|
|
5
|
+
setMockRawResponse,
|
|
6
|
+
setMockResponse,
|
|
7
|
+
unsetAllMocks,
|
|
8
|
+
} from "./helpers/mock-cfetch";
|
|
4
9
|
import { mockConsoleMethods } from "./helpers/mock-console";
|
|
5
10
|
import { runInTempDir } from "./helpers/run-in-tmp";
|
|
6
11
|
import { runWrangler } from "./helpers/run-wrangler";
|
|
7
|
-
import type { Project,
|
|
8
|
-
import type {
|
|
12
|
+
import type { Deployment, Project, UploadPayloadFile } from "../pages";
|
|
13
|
+
import type { FormData, RequestInit } from "undici";
|
|
14
|
+
|
|
15
|
+
// Asserting within mock responses get swallowed, so run them out-of-band
|
|
16
|
+
const outOfBandTests: (() => void)[] = [];
|
|
17
|
+
function assertLater(fn: () => void) {
|
|
18
|
+
outOfBandTests.push(fn);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function mockGetToken(jwt: string) {
|
|
22
|
+
return setMockResponse(
|
|
23
|
+
"/accounts/:accountId/pages/projects/foo/upload-token",
|
|
24
|
+
async ([_url, accountId]) => {
|
|
25
|
+
assertLater(() => {
|
|
26
|
+
expect(accountId).toEqual("some-account-id");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
return { jwt };
|
|
30
|
+
}
|
|
31
|
+
);
|
|
32
|
+
}
|
|
9
33
|
|
|
10
34
|
describe("pages", () => {
|
|
11
35
|
runInTempDir();
|
|
@@ -13,6 +37,12 @@ describe("pages", () => {
|
|
|
13
37
|
function endEventLoop() {
|
|
14
38
|
return new Promise((resolve) => setImmediate(resolve));
|
|
15
39
|
}
|
|
40
|
+
beforeEach(() => {
|
|
41
|
+
outOfBandTests.length = 0;
|
|
42
|
+
});
|
|
43
|
+
afterEach(() => {
|
|
44
|
+
outOfBandTests.forEach((fn) => fn());
|
|
45
|
+
});
|
|
16
46
|
|
|
17
47
|
it("should should display a list of available subcommands, for pages with no subcommand", async () => {
|
|
18
48
|
await runWrangler("pages");
|
|
@@ -49,7 +79,7 @@ describe("pages", () => {
|
|
|
49
79
|
expect(std.out).toMatchInlineSnapshot(`
|
|
50
80
|
"🚧 'wrangler pages <command>' is a beta command. Please report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose
|
|
51
81
|
|
|
52
|
-
[32mIf you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new
|
|
82
|
+
[32mIf you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose[0m"
|
|
53
83
|
`);
|
|
54
84
|
});
|
|
55
85
|
|
|
@@ -59,7 +89,7 @@ describe("pages", () => {
|
|
|
59
89
|
expect(std.out).toMatchInlineSnapshot(`
|
|
60
90
|
"🚧 'wrangler pages <command>' is a beta command. Please report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose
|
|
61
91
|
|
|
62
|
-
[32mIf you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new
|
|
92
|
+
[32mIf you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose[0m"
|
|
63
93
|
`);
|
|
64
94
|
});
|
|
65
95
|
});
|
|
@@ -78,12 +108,16 @@ describe("pages", () => {
|
|
|
78
108
|
"/accounts/:accountId/pages/projects",
|
|
79
109
|
([_url, accountId], init, query) => {
|
|
80
110
|
requests.count++;
|
|
81
|
-
expect(accountId).toEqual("some-account-id");
|
|
82
|
-
expect(query.get("per_page")).toEqual("10");
|
|
83
|
-
expect(query.get("page")).toEqual(`${requests.count}`);
|
|
84
|
-
expect(init).toEqual({});
|
|
85
111
|
const pageSize = Number(query.get("per_page"));
|
|
86
112
|
const page = Number(query.get("page"));
|
|
113
|
+
const expectedPageSize = 10;
|
|
114
|
+
const expectedPage = requests.count;
|
|
115
|
+
assertLater(() => {
|
|
116
|
+
expect(accountId).toEqual("some-account-id");
|
|
117
|
+
expect(pageSize).toEqual(expectedPageSize);
|
|
118
|
+
expect(page).toEqual(expectedPage);
|
|
119
|
+
expect(init).toEqual({});
|
|
120
|
+
});
|
|
87
121
|
return projects.slice((page - 1) * pageSize, page * pageSize);
|
|
88
122
|
}
|
|
89
123
|
);
|
|
@@ -158,12 +192,14 @@ describe("pages", () => {
|
|
|
158
192
|
setMockResponse(
|
|
159
193
|
"/accounts/:accountId/pages/projects",
|
|
160
194
|
([_url, accountId], init) => {
|
|
161
|
-
expect(accountId).toEqual("some-account-id");
|
|
162
|
-
expect(init.method).toEqual("POST");
|
|
163
195
|
const body = JSON.parse(init.body as string);
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
196
|
+
assertLater(() => {
|
|
197
|
+
expect(accountId).toEqual("some-account-id");
|
|
198
|
+
expect(init.method).toEqual("POST");
|
|
199
|
+
expect(body).toEqual({
|
|
200
|
+
name: "a-new-project",
|
|
201
|
+
production_branch: "main",
|
|
202
|
+
});
|
|
167
203
|
});
|
|
168
204
|
return {
|
|
169
205
|
name: "a-new-project",
|
|
@@ -195,8 +231,10 @@ describe("pages", () => {
|
|
|
195
231
|
"/accounts/:accountId/pages/projects/:project/deployments",
|
|
196
232
|
([_url, accountId, project]) => {
|
|
197
233
|
requests.count++;
|
|
198
|
-
|
|
199
|
-
|
|
234
|
+
assertLater(() => {
|
|
235
|
+
expect(project).toEqual("images");
|
|
236
|
+
expect(accountId).toEqual("some-account-id");
|
|
237
|
+
});
|
|
200
238
|
return deployments;
|
|
201
239
|
}
|
|
202
240
|
);
|
|
@@ -279,33 +317,68 @@ describe("pages", () => {
|
|
|
279
317
|
writeFileSync("logo.png", "foobar");
|
|
280
318
|
|
|
281
319
|
setMockResponse(
|
|
282
|
-
"/accounts/:accountId/pages/projects/foo/
|
|
283
|
-
async ([_url, accountId]
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
const logoPNGFile = body.get("file") as File;
|
|
288
|
-
expect(await logoPNGFile.text()).toEqual("foobar");
|
|
289
|
-
expect(logoPNGFile.name).toEqual("logo.png");
|
|
320
|
+
"/accounts/:accountId/pages/projects/foo/upload-token",
|
|
321
|
+
async ([_url, accountId]) => {
|
|
322
|
+
assertLater(() => {
|
|
323
|
+
expect(accountId).toEqual("some-account-id");
|
|
324
|
+
});
|
|
290
325
|
|
|
291
326
|
return {
|
|
292
|
-
|
|
327
|
+
jwt: "<<funfetti-auth-jwt>>",
|
|
293
328
|
};
|
|
294
329
|
}
|
|
295
330
|
);
|
|
296
331
|
|
|
332
|
+
setMockResponse(
|
|
333
|
+
"/pages/assets/check-missing",
|
|
334
|
+
"POST",
|
|
335
|
+
async (_, init) => {
|
|
336
|
+
const body = JSON.parse(init.body as string) as { hashes: string[] };
|
|
337
|
+
assertLater(() => {
|
|
338
|
+
expect(init.headers).toMatchObject({
|
|
339
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
340
|
+
});
|
|
341
|
+
expect(body).toMatchObject({
|
|
342
|
+
hashes: ["2082190357cfd3617ccfe04f340c6247"],
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
return body.hashes;
|
|
346
|
+
}
|
|
347
|
+
);
|
|
348
|
+
|
|
349
|
+
setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
|
|
350
|
+
assertLater(() => {
|
|
351
|
+
expect(init.headers).toMatchObject({
|
|
352
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
353
|
+
});
|
|
354
|
+
const body = JSON.parse(init.body as string) as UploadPayloadFile[];
|
|
355
|
+
expect(body).toMatchObject([
|
|
356
|
+
{
|
|
357
|
+
key: "2082190357cfd3617ccfe04f340c6247",
|
|
358
|
+
value: Buffer.from("foobar").toString("base64"),
|
|
359
|
+
metadata: {
|
|
360
|
+
contentType: "image/png",
|
|
361
|
+
},
|
|
362
|
+
base64: true,
|
|
363
|
+
},
|
|
364
|
+
]);
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
|
|
297
368
|
setMockResponse(
|
|
298
369
|
"/accounts/:accountId/pages/projects/foo/deployments",
|
|
299
370
|
async ([_url, accountId], init) => {
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
371
|
+
assertLater(() => {
|
|
372
|
+
expect(accountId).toEqual("some-account-id");
|
|
373
|
+
expect(init.method).toEqual("POST");
|
|
374
|
+
const body = init.body as FormData;
|
|
375
|
+
const manifest = JSON.parse(body.get("manifest") as string);
|
|
376
|
+
expect(manifest).toMatchInlineSnapshot(`
|
|
377
|
+
Object {
|
|
378
|
+
"/logo.png": "2082190357cfd3617ccfe04f340c6247",
|
|
379
|
+
}
|
|
380
|
+
`);
|
|
381
|
+
});
|
|
309
382
|
|
|
310
383
|
return {
|
|
311
384
|
url: "https://abcxyz.foo.pages.dev/",
|
|
@@ -324,17 +397,348 @@ describe("pages", () => {
|
|
|
324
397
|
// `);
|
|
325
398
|
});
|
|
326
399
|
|
|
400
|
+
it("should retry uploads", async () => {
|
|
401
|
+
writeFileSync("logo.txt", "foobar");
|
|
402
|
+
|
|
403
|
+
mockGetToken("<<funfetti-auth-jwt>>");
|
|
404
|
+
|
|
405
|
+
setMockResponse(
|
|
406
|
+
"/pages/assets/check-missing",
|
|
407
|
+
"POST",
|
|
408
|
+
async (_, init) => {
|
|
409
|
+
const body = JSON.parse(init.body as string) as { hashes: string[] };
|
|
410
|
+
assertLater(() => {
|
|
411
|
+
expect(init.headers).toMatchObject({
|
|
412
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
413
|
+
});
|
|
414
|
+
expect(body).toMatchObject({
|
|
415
|
+
hashes: ["1a98fb08af91aca4a7df1764a2c4ddb0"],
|
|
416
|
+
});
|
|
417
|
+
});
|
|
418
|
+
return body.hashes;
|
|
419
|
+
}
|
|
420
|
+
);
|
|
421
|
+
|
|
422
|
+
// Accumulate multiple requests then assert afterwards
|
|
423
|
+
const requests: RequestInit[] = [];
|
|
424
|
+
setMockRawResponse("/pages/assets/upload", "POST", async (_, init) => {
|
|
425
|
+
requests.push(init);
|
|
426
|
+
|
|
427
|
+
if (requests.length < 2) {
|
|
428
|
+
return createFetchResult(null, false, [
|
|
429
|
+
{
|
|
430
|
+
code: 800000,
|
|
431
|
+
message: "Something exploded, please retry",
|
|
432
|
+
},
|
|
433
|
+
]);
|
|
434
|
+
} else {
|
|
435
|
+
return createFetchResult(null, true);
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
setMockResponse(
|
|
440
|
+
"/accounts/:accountId/pages/projects/foo/deployments",
|
|
441
|
+
async ([_url, accountId], init) => {
|
|
442
|
+
assertLater(() => {
|
|
443
|
+
expect(accountId).toEqual("some-account-id");
|
|
444
|
+
expect(init.method).toEqual("POST");
|
|
445
|
+
const body = init.body as FormData;
|
|
446
|
+
const manifest = JSON.parse(body.get("manifest") as string);
|
|
447
|
+
expect(manifest).toMatchInlineSnapshot(`
|
|
448
|
+
Object {
|
|
449
|
+
"/logo.txt": "1a98fb08af91aca4a7df1764a2c4ddb0",
|
|
450
|
+
}
|
|
451
|
+
`);
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
return {
|
|
455
|
+
url: "https://abcxyz.foo.pages.dev/",
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
);
|
|
459
|
+
|
|
460
|
+
await runWrangler("pages publish . --project-name=foo");
|
|
461
|
+
|
|
462
|
+
// Assert two identical requests
|
|
463
|
+
expect(requests.length).toBe(2);
|
|
464
|
+
for (const init of requests) {
|
|
465
|
+
assertLater(() => {
|
|
466
|
+
expect(init.headers).toMatchObject({
|
|
467
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
const body = JSON.parse(init.body as string) as UploadPayloadFile[];
|
|
471
|
+
expect(body).toMatchObject([
|
|
472
|
+
{
|
|
473
|
+
key: "1a98fb08af91aca4a7df1764a2c4ddb0",
|
|
474
|
+
value: Buffer.from("foobar").toString("base64"),
|
|
475
|
+
metadata: {
|
|
476
|
+
contentType: "text/plain",
|
|
477
|
+
},
|
|
478
|
+
base64: true,
|
|
479
|
+
},
|
|
480
|
+
]);
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
expect(std.out).toMatchInlineSnapshot(`
|
|
485
|
+
"✨ Success! Uploaded 1 files (TIMINGS)
|
|
486
|
+
|
|
487
|
+
✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/"
|
|
488
|
+
`);
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
it("should refetch a JWT if it expires while uploading", async () => {
|
|
492
|
+
writeFileSync("logo.txt", "foobar");
|
|
493
|
+
|
|
494
|
+
const cancelMockGetToken = mockGetToken("<<funfetti-auth-jwt>>");
|
|
495
|
+
|
|
496
|
+
setMockResponse(
|
|
497
|
+
"/pages/assets/check-missing",
|
|
498
|
+
"POST",
|
|
499
|
+
async (_, init) => {
|
|
500
|
+
const body = JSON.parse(init.body as string) as { hashes: string[] };
|
|
501
|
+
assertLater(() => {
|
|
502
|
+
expect(init.headers).toMatchObject({
|
|
503
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
504
|
+
});
|
|
505
|
+
expect(body).toMatchObject({
|
|
506
|
+
hashes: ["1a98fb08af91aca4a7df1764a2c4ddb0"],
|
|
507
|
+
});
|
|
508
|
+
});
|
|
509
|
+
return body.hashes;
|
|
510
|
+
}
|
|
511
|
+
);
|
|
512
|
+
|
|
513
|
+
// Accumulate multiple requests then assert afterwards
|
|
514
|
+
const requests: RequestInit[] = [];
|
|
515
|
+
setMockRawResponse("/pages/assets/upload", "POST", async (_, init) => {
|
|
516
|
+
requests.push(init);
|
|
517
|
+
|
|
518
|
+
// Fail just the first request
|
|
519
|
+
if (requests.length < 2) {
|
|
520
|
+
cancelMockGetToken();
|
|
521
|
+
mockGetToken("<<funfetti-auth-jwt2>>");
|
|
522
|
+
return createFetchResult(null, false, [
|
|
523
|
+
{
|
|
524
|
+
code: 8000013,
|
|
525
|
+
message: "Authorization failed",
|
|
526
|
+
},
|
|
527
|
+
]);
|
|
528
|
+
} else {
|
|
529
|
+
return createFetchResult(null, true);
|
|
530
|
+
}
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
setMockResponse(
|
|
534
|
+
"/accounts/:accountId/pages/projects/foo/deployments",
|
|
535
|
+
async ([_url, accountId], init) => {
|
|
536
|
+
assertLater(() => {
|
|
537
|
+
expect(accountId).toEqual("some-account-id");
|
|
538
|
+
expect(init.method).toEqual("POST");
|
|
539
|
+
const body = init.body as FormData;
|
|
540
|
+
const manifest = JSON.parse(body.get("manifest") as string);
|
|
541
|
+
expect(manifest).toMatchInlineSnapshot(`
|
|
542
|
+
Object {
|
|
543
|
+
"/logo.txt": "1a98fb08af91aca4a7df1764a2c4ddb0",
|
|
544
|
+
}
|
|
545
|
+
`);
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
return {
|
|
549
|
+
url: "https://abcxyz.foo.pages.dev/",
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
);
|
|
553
|
+
|
|
554
|
+
await runWrangler("pages publish . --project-name=foo");
|
|
555
|
+
|
|
556
|
+
// Assert two requests
|
|
557
|
+
expect(requests.length).toBe(2);
|
|
558
|
+
|
|
559
|
+
expect(requests[0].headers).toMatchObject({
|
|
560
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
expect(requests[1].headers).toMatchObject({
|
|
564
|
+
Authorization: "Bearer <<funfetti-auth-jwt2>>",
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
for (const init of requests) {
|
|
568
|
+
const body = JSON.parse(init.body as string) as UploadPayloadFile[];
|
|
569
|
+
expect(body).toMatchObject([
|
|
570
|
+
{
|
|
571
|
+
key: "1a98fb08af91aca4a7df1764a2c4ddb0",
|
|
572
|
+
value: Buffer.from("foobar").toString("base64"),
|
|
573
|
+
metadata: {
|
|
574
|
+
contentType: "text/plain",
|
|
575
|
+
},
|
|
576
|
+
base64: true,
|
|
577
|
+
},
|
|
578
|
+
]);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
expect(std.out).toMatchInlineSnapshot(`
|
|
582
|
+
"✨ Success! Uploaded 1 files (TIMINGS)
|
|
583
|
+
|
|
584
|
+
✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/"
|
|
585
|
+
`);
|
|
586
|
+
});
|
|
587
|
+
|
|
588
|
+
it("should try to use multiple buckets (up to the max concurrency)", async () => {
|
|
589
|
+
writeFileSync("logo.txt", "foobar");
|
|
590
|
+
writeFileSync("logo.png", "foobar");
|
|
591
|
+
writeFileSync("logo.html", "foobar");
|
|
592
|
+
writeFileSync("logo.js", "foobar");
|
|
593
|
+
|
|
594
|
+
mockGetToken("<<funfetti-auth-jwt>>");
|
|
595
|
+
|
|
596
|
+
setMockResponse(
|
|
597
|
+
"/pages/assets/check-missing",
|
|
598
|
+
"POST",
|
|
599
|
+
async (_, init) => {
|
|
600
|
+
const body = JSON.parse(init.body as string) as { hashes: string[] };
|
|
601
|
+
assertLater(() => {
|
|
602
|
+
expect(init.headers).toMatchObject({
|
|
603
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
604
|
+
});
|
|
605
|
+
expect(body).toMatchObject({
|
|
606
|
+
hashes: expect.arrayContaining([
|
|
607
|
+
"d96fef225537c9f5e44a3cb27fd0b492",
|
|
608
|
+
"2082190357cfd3617ccfe04f340c6247",
|
|
609
|
+
"6be321bef99e758250dac034474ddbb8",
|
|
610
|
+
"1a98fb08af91aca4a7df1764a2c4ddb0",
|
|
611
|
+
]),
|
|
612
|
+
});
|
|
613
|
+
});
|
|
614
|
+
return body.hashes;
|
|
615
|
+
}
|
|
616
|
+
);
|
|
617
|
+
|
|
618
|
+
// Accumulate multiple requests then assert afterwards
|
|
619
|
+
const requests: RequestInit[] = [];
|
|
620
|
+
setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
|
|
621
|
+
requests.push(init);
|
|
622
|
+
});
|
|
623
|
+
|
|
624
|
+
setMockResponse(
|
|
625
|
+
"/accounts/:accountId/pages/projects/foo/deployments",
|
|
626
|
+
async ([_url, accountId], init) => {
|
|
627
|
+
assertLater(() => {
|
|
628
|
+
expect(accountId).toEqual("some-account-id");
|
|
629
|
+
expect(init.method).toEqual("POST");
|
|
630
|
+
const body = init.body as FormData;
|
|
631
|
+
const manifest = JSON.parse(body.get("manifest") as string);
|
|
632
|
+
expect(manifest).toMatchInlineSnapshot(`
|
|
633
|
+
Object {
|
|
634
|
+
"/logo.html": "d96fef225537c9f5e44a3cb27fd0b492",
|
|
635
|
+
"/logo.js": "6be321bef99e758250dac034474ddbb8",
|
|
636
|
+
"/logo.png": "2082190357cfd3617ccfe04f340c6247",
|
|
637
|
+
"/logo.txt": "1a98fb08af91aca4a7df1764a2c4ddb0",
|
|
638
|
+
}
|
|
639
|
+
`);
|
|
640
|
+
});
|
|
641
|
+
|
|
642
|
+
return {
|
|
643
|
+
url: "https://abcxyz.foo.pages.dev/",
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
);
|
|
647
|
+
|
|
648
|
+
await runWrangler("pages publish . --project-name=foo");
|
|
649
|
+
|
|
650
|
+
// We have 3 buckets, so expect 3 uploads
|
|
651
|
+
expect(requests.length).toBe(3);
|
|
652
|
+
const bodies: UploadPayloadFile[][] = [];
|
|
653
|
+
for (const init of requests) {
|
|
654
|
+
expect(init.headers).toMatchObject({
|
|
655
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
656
|
+
});
|
|
657
|
+
bodies.push(JSON.parse(init.body as string) as UploadPayloadFile[]);
|
|
658
|
+
}
|
|
659
|
+
// First bucket should end up with 2 files
|
|
660
|
+
expect(bodies.map((b) => b.length)).toEqual([2, 1, 1]);
|
|
661
|
+
// But we don't know the order, so flatten and test without ordering
|
|
662
|
+
expect(bodies.flatMap((b) => b)).toEqual(
|
|
663
|
+
expect.arrayContaining([
|
|
664
|
+
{
|
|
665
|
+
base64: true,
|
|
666
|
+
key: "d96fef225537c9f5e44a3cb27fd0b492",
|
|
667
|
+
metadata: { contentType: "text/html" },
|
|
668
|
+
value: "Zm9vYmFy",
|
|
669
|
+
},
|
|
670
|
+
{
|
|
671
|
+
base64: true,
|
|
672
|
+
key: "1a98fb08af91aca4a7df1764a2c4ddb0",
|
|
673
|
+
metadata: { contentType: "text/plain" },
|
|
674
|
+
value: "Zm9vYmFy",
|
|
675
|
+
},
|
|
676
|
+
{
|
|
677
|
+
base64: true,
|
|
678
|
+
key: "6be321bef99e758250dac034474ddbb8",
|
|
679
|
+
metadata: { contentType: "application/javascript" },
|
|
680
|
+
value: "Zm9vYmFy",
|
|
681
|
+
},
|
|
682
|
+
{
|
|
683
|
+
base64: true,
|
|
684
|
+
key: "2082190357cfd3617ccfe04f340c6247",
|
|
685
|
+
metadata: { contentType: "image/png" },
|
|
686
|
+
value: "Zm9vYmFy",
|
|
687
|
+
},
|
|
688
|
+
])
|
|
689
|
+
);
|
|
690
|
+
|
|
691
|
+
expect(std.out).toMatchInlineSnapshot(`
|
|
692
|
+
"✨ Success! Uploaded 4 files (TIMINGS)
|
|
693
|
+
|
|
694
|
+
✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/"
|
|
695
|
+
`);
|
|
696
|
+
});
|
|
697
|
+
|
|
327
698
|
it("should not error when directory names contain periods and houses a extensionless file", async () => {
|
|
328
699
|
mkdirSync(".well-known");
|
|
700
|
+
// Note: same content as previous test, but since it's a different extension,
|
|
701
|
+
// it hashes to a different value
|
|
329
702
|
writeFileSync(".well-known/foobar", "foobar");
|
|
330
703
|
|
|
704
|
+
mockGetToken("<<funfetti-auth-jwt>>");
|
|
705
|
+
|
|
331
706
|
setMockResponse(
|
|
332
|
-
"/
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
707
|
+
"/pages/assets/check-missing",
|
|
708
|
+
"POST",
|
|
709
|
+
async (_, init) => {
|
|
710
|
+
const body = JSON.parse(init.body as string) as { hashes: string[] };
|
|
711
|
+
assertLater(() => {
|
|
712
|
+
expect(init.headers).toMatchObject({
|
|
713
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
714
|
+
});
|
|
715
|
+
expect(body).toMatchObject({
|
|
716
|
+
hashes: ["7b764dacfd211bebd8077828a7ddefd7"],
|
|
717
|
+
});
|
|
718
|
+
});
|
|
719
|
+
return body.hashes;
|
|
720
|
+
}
|
|
336
721
|
);
|
|
337
722
|
|
|
723
|
+
setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
|
|
724
|
+
assertLater(() => {
|
|
725
|
+
expect(init.headers).toMatchObject({
|
|
726
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
727
|
+
});
|
|
728
|
+
const body = JSON.parse(init.body as string) as UploadPayloadFile[];
|
|
729
|
+
expect(body).toMatchObject([
|
|
730
|
+
{
|
|
731
|
+
key: "7b764dacfd211bebd8077828a7ddefd7",
|
|
732
|
+
value: Buffer.from("foobar").toString("base64"),
|
|
733
|
+
metadata: {
|
|
734
|
+
contentType: "application/octet-stream",
|
|
735
|
+
},
|
|
736
|
+
base64: true,
|
|
737
|
+
},
|
|
738
|
+
]);
|
|
739
|
+
});
|
|
740
|
+
});
|
|
741
|
+
|
|
338
742
|
setMockResponse(
|
|
339
743
|
"/accounts/:accountId/pages/projects/foo/deployments",
|
|
340
744
|
async () => ({
|
|
@@ -167,7 +167,11 @@ describe("parseTOML", () => {
|
|
|
167
167
|
});
|
|
168
168
|
|
|
169
169
|
it("should cope with Windows line-endings", () => {
|
|
170
|
-
expect(
|
|
170
|
+
expect(
|
|
171
|
+
parseTOML(
|
|
172
|
+
"# A comment with a Windows line-ending\r\n# Another comment with a Windows line-ending\r\n"
|
|
173
|
+
)
|
|
174
|
+
).toEqual({});
|
|
171
175
|
});
|
|
172
176
|
});
|
|
173
177
|
|