wrangler 2.0.28 → 2.0.29
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/miniflare-dist/index.mjs +54 -46
- package/package.json +1 -1
- package/src/__tests__/api-dev.test.ts +19 -0
- package/src/__tests__/helpers/hello-world-worker.js +5 -0
- package/src/__tests__/jest.setup.ts +13 -0
- package/src/__tests__/pages.test.ts +829 -103
- package/src/__tests__/paths.test.ts +17 -0
- package/src/api/dev.ts +74 -28
- package/src/bundle.ts +13 -10
- package/src/cli.ts +1 -1
- package/src/dev/local.tsx +317 -169
- package/src/dev/start-server.ts +412 -0
- package/src/dev.tsx +325 -169
- package/src/entry.ts +2 -1
- package/src/init.ts +5 -5
- package/src/metrics/send-event.ts +1 -0
- package/src/miniflare-cli/assets.ts +4 -65
- package/src/miniflare-cli/index.ts +36 -32
- package/src/pages/constants.ts +3 -0
- package/src/pages/dev.tsx +3 -2
- package/src/pages/functions/buildPlugin.ts +2 -1
- package/src/pages/functions/buildWorker.ts +2 -1
- package/src/pages/functions/routes-transformation.test.ts +12 -1
- package/src/pages/functions/routes-transformation.ts +7 -1
- package/src/pages/publish.tsx +82 -38
- package/src/paths.ts +20 -1
- package/src/worker.ts +7 -7
- package/wrangler-dist/cli.d.ts +15 -5
- package/wrangler-dist/cli.js +2009 -1389
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { chdir } from "node:process";
|
|
3
|
+
import { ROUTES_SPEC_VERSION } from "../pages/constants";
|
|
3
4
|
import { mockAccountId, mockApiToken } from "./helpers/mock-account-id";
|
|
4
5
|
import {
|
|
5
6
|
createFetchResult,
|
|
@@ -57,23 +58,23 @@ describe("pages", () => {
|
|
|
57
58
|
await endEventLoop();
|
|
58
59
|
|
|
59
60
|
expect(std.out).toMatchInlineSnapshot(`
|
|
60
|
-
|
|
61
|
+
"wrangler pages
|
|
61
62
|
|
|
62
|
-
|
|
63
|
+
⚡️ Configure Cloudflare Pages
|
|
63
64
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
Commands:
|
|
66
|
+
wrangler pages dev [directory] [-- command..] 🧑💻 Develop your full-stack Pages application locally
|
|
67
|
+
wrangler pages project ⚡️ Interact with your Pages projects
|
|
68
|
+
wrangler pages deployment 🚀 Interact with the deployments of a project
|
|
69
|
+
wrangler pages publish [directory] 🆙 Publish a directory of static assets as a Pages deployment
|
|
69
70
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
Flags:
|
|
72
|
+
-c, --config Path to .toml configuration file [string]
|
|
73
|
+
-h, --help Show help [boolean]
|
|
74
|
+
-v, --version Show version number [boolean]
|
|
74
75
|
|
|
75
|
-
|
|
76
|
-
|
|
76
|
+
🚧 'wrangler pages <command>' is a beta command. Please report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose"
|
|
77
|
+
`);
|
|
77
78
|
});
|
|
78
79
|
|
|
79
80
|
describe("beta message for subcommands", () => {
|
|
@@ -85,20 +86,20 @@ describe("pages", () => {
|
|
|
85
86
|
);
|
|
86
87
|
|
|
87
88
|
expect(std.out).toMatchInlineSnapshot(`
|
|
88
|
-
|
|
89
|
+
"🚧 'wrangler pages <command>' is a beta command. Please report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose
|
|
89
90
|
|
|
90
|
-
|
|
91
|
-
|
|
91
|
+
[32mIf you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose[0m"
|
|
92
|
+
`);
|
|
92
93
|
});
|
|
93
94
|
|
|
94
95
|
it("should display for pages:functions:build", async () => {
|
|
95
96
|
await expect(runWrangler("pages functions build")).rejects.toThrowError();
|
|
96
97
|
|
|
97
98
|
expect(std.out).toMatchInlineSnapshot(`
|
|
98
|
-
|
|
99
|
+
"🚧 'wrangler pages <command>' is a beta command. Please report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose
|
|
99
100
|
|
|
100
|
-
|
|
101
|
-
|
|
101
|
+
[32mIf you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose[0m"
|
|
102
|
+
`);
|
|
102
103
|
});
|
|
103
104
|
|
|
104
105
|
it("should display for pages:functions:optimize-routes", async () => {
|
|
@@ -109,10 +110,10 @@ describe("pages", () => {
|
|
|
109
110
|
).rejects.toThrowError();
|
|
110
111
|
|
|
111
112
|
expect(std.out).toMatchInlineSnapshot(`
|
|
112
|
-
|
|
113
|
+
"🚧 'wrangler pages <command>' is a beta command. Please report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose
|
|
113
114
|
|
|
114
|
-
|
|
115
|
-
|
|
115
|
+
[32mIf you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose[0m"
|
|
116
|
+
`);
|
|
116
117
|
});
|
|
117
118
|
});
|
|
118
119
|
|
|
@@ -234,9 +235,9 @@ describe("pages", () => {
|
|
|
234
235
|
"pages project create a-new-project --production-branch=main"
|
|
235
236
|
);
|
|
236
237
|
expect(std.out).toMatchInlineSnapshot(`
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
238
|
+
"✨ Successfully created the 'a-new-project' project. It will be available at https://a-new-project.pages.dev/ once you create your first deployment.
|
|
239
|
+
To deploy a folder of assets, run 'wrangler pages publish [directory]'."
|
|
240
|
+
`);
|
|
240
241
|
});
|
|
241
242
|
});
|
|
242
243
|
|
|
@@ -312,26 +313,26 @@ describe("pages", () => {
|
|
|
312
313
|
await endEventLoop();
|
|
313
314
|
|
|
314
315
|
expect(std.out).toMatchInlineSnapshot(`
|
|
315
|
-
|
|
316
|
+
"wrangler pages publish [directory]
|
|
316
317
|
|
|
317
|
-
|
|
318
|
+
🆙 Publish a directory of static assets as a Pages deployment
|
|
318
319
|
|
|
319
|
-
|
|
320
|
-
|
|
320
|
+
Positionals:
|
|
321
|
+
directory The directory of static files to upload [string]
|
|
321
322
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
323
|
+
Flags:
|
|
324
|
+
-h, --help Show help [boolean]
|
|
325
|
+
-v, --version Show version number [boolean]
|
|
325
326
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
327
|
+
Options:
|
|
328
|
+
--project-name The name of the project you want to deploy to [string]
|
|
329
|
+
--branch The name of the branch you want to deploy to [string]
|
|
330
|
+
--commit-hash The SHA to attach to this deployment [string]
|
|
331
|
+
--commit-message The commit message to attach to this deployment [string]
|
|
332
|
+
--commit-dirty Whether or not the workspace should be considered dirty for this deployment [boolean]
|
|
332
333
|
|
|
333
|
-
|
|
334
|
-
|
|
334
|
+
🚧 'wrangler pages <command>' is a beta command. Please report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose"
|
|
335
|
+
`);
|
|
335
336
|
});
|
|
336
337
|
|
|
337
338
|
it("should upload a directory of files", async () => {
|
|
@@ -384,10 +385,10 @@ describe("pages", () => {
|
|
|
384
385
|
const body = init.body as FormData;
|
|
385
386
|
const manifest = JSON.parse(body.get("manifest") as string);
|
|
386
387
|
expect(manifest).toMatchInlineSnapshot(`
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
388
|
+
Object {
|
|
389
|
+
"/logo.png": "2082190357cfd3617ccfe04f340c6247",
|
|
390
|
+
}
|
|
391
|
+
`);
|
|
391
392
|
});
|
|
392
393
|
|
|
393
394
|
return {
|
|
@@ -398,13 +399,11 @@ describe("pages", () => {
|
|
|
398
399
|
|
|
399
400
|
await runWrangler("pages publish . --project-name=foo");
|
|
400
401
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
// expect(std.out).toMatchInlineSnapshot(`
|
|
404
|
-
// "✨ Success! Uploaded 1 files (TIMINGS)
|
|
402
|
+
expect(std.out).toMatchInlineSnapshot(`
|
|
403
|
+
"✨ Success! Uploaded 1 files (TIMINGS)
|
|
405
404
|
|
|
406
|
-
|
|
407
|
-
|
|
405
|
+
✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/"
|
|
406
|
+
`);
|
|
408
407
|
});
|
|
409
408
|
|
|
410
409
|
it("should retry uploads", async () => {
|
|
@@ -455,10 +454,10 @@ describe("pages", () => {
|
|
|
455
454
|
const body = init.body as FormData;
|
|
456
455
|
const manifest = JSON.parse(body.get("manifest") as string);
|
|
457
456
|
expect(manifest).toMatchInlineSnapshot(`
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
457
|
+
Object {
|
|
458
|
+
"/logo.txt": "1a98fb08af91aca4a7df1764a2c4ddb0",
|
|
459
|
+
}
|
|
460
|
+
`);
|
|
462
461
|
});
|
|
463
462
|
|
|
464
463
|
return {
|
|
@@ -492,10 +491,10 @@ describe("pages", () => {
|
|
|
492
491
|
}
|
|
493
492
|
|
|
494
493
|
expect(std.out).toMatchInlineSnapshot(`
|
|
495
|
-
|
|
494
|
+
"✨ Success! Uploaded 1 files (TIMINGS)
|
|
496
495
|
|
|
497
|
-
|
|
498
|
-
|
|
496
|
+
✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/"
|
|
497
|
+
`);
|
|
499
498
|
});
|
|
500
499
|
|
|
501
500
|
it("should refetch a JWT if it expires while uploading", async () => {
|
|
@@ -549,10 +548,10 @@ describe("pages", () => {
|
|
|
549
548
|
const body = init.body as FormData;
|
|
550
549
|
const manifest = JSON.parse(body.get("manifest") as string);
|
|
551
550
|
expect(manifest).toMatchInlineSnapshot(`
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
551
|
+
Object {
|
|
552
|
+
"/logo.txt": "1a98fb08af91aca4a7df1764a2c4ddb0",
|
|
553
|
+
}
|
|
554
|
+
`);
|
|
556
555
|
});
|
|
557
556
|
|
|
558
557
|
return {
|
|
@@ -589,10 +588,10 @@ describe("pages", () => {
|
|
|
589
588
|
}
|
|
590
589
|
|
|
591
590
|
expect(std.out).toMatchInlineSnapshot(`
|
|
592
|
-
|
|
591
|
+
"✨ Success! Uploaded 1 files (TIMINGS)
|
|
593
592
|
|
|
594
|
-
|
|
595
|
-
|
|
593
|
+
✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/"
|
|
594
|
+
`);
|
|
596
595
|
});
|
|
597
596
|
|
|
598
597
|
it("should try to use multiple buckets (up to the max concurrency)", async () => {
|
|
@@ -640,13 +639,13 @@ describe("pages", () => {
|
|
|
640
639
|
const body = init.body as FormData;
|
|
641
640
|
const manifest = JSON.parse(body.get("manifest") as string);
|
|
642
641
|
expect(manifest).toMatchInlineSnapshot(`
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
642
|
+
Object {
|
|
643
|
+
"/logo.html": "d96fef225537c9f5e44a3cb27fd0b492",
|
|
644
|
+
"/logo.js": "6be321bef99e758250dac034474ddbb8",
|
|
645
|
+
"/logo.png": "2082190357cfd3617ccfe04f340c6247",
|
|
646
|
+
"/logo.txt": "1a98fb08af91aca4a7df1764a2c4ddb0",
|
|
647
|
+
}
|
|
648
|
+
`);
|
|
650
649
|
});
|
|
651
650
|
|
|
652
651
|
return {
|
|
@@ -699,10 +698,10 @@ describe("pages", () => {
|
|
|
699
698
|
);
|
|
700
699
|
|
|
701
700
|
expect(std.out).toMatchInlineSnapshot(`
|
|
702
|
-
|
|
701
|
+
"✨ Success! Uploaded 4 files (TIMINGS)
|
|
703
702
|
|
|
704
|
-
|
|
705
|
-
|
|
703
|
+
✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/"
|
|
704
|
+
`);
|
|
706
705
|
});
|
|
707
706
|
|
|
708
707
|
it("should resolve child directories correctly", async () => {
|
|
@@ -754,13 +753,13 @@ describe("pages", () => {
|
|
|
754
753
|
const body = init.body as FormData;
|
|
755
754
|
const manifest = JSON.parse(body.get("manifest") as string);
|
|
756
755
|
expect(manifest).toMatchInlineSnapshot(`
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
756
|
+
Object {
|
|
757
|
+
"/imgs/logo.png": "2082190357cfd3617ccfe04f340c6247",
|
|
758
|
+
"/logo.html": "d96fef225537c9f5e44a3cb27fd0b492",
|
|
759
|
+
"/logo.js": "6be321bef99e758250dac034474ddbb8",
|
|
760
|
+
"/logo.txt": "1a98fb08af91aca4a7df1764a2c4ddb0",
|
|
761
|
+
}
|
|
762
|
+
`);
|
|
764
763
|
});
|
|
765
764
|
|
|
766
765
|
return {
|
|
@@ -813,10 +812,10 @@ describe("pages", () => {
|
|
|
813
812
|
);
|
|
814
813
|
|
|
815
814
|
expect(std.out).toMatchInlineSnapshot(`
|
|
816
|
-
|
|
815
|
+
"✨ Success! Uploaded 4 files (TIMINGS)
|
|
817
816
|
|
|
818
|
-
|
|
819
|
-
|
|
817
|
+
✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/"
|
|
818
|
+
`);
|
|
820
819
|
});
|
|
821
820
|
|
|
822
821
|
it("should resolve the current directory correctly", async () => {
|
|
@@ -868,13 +867,13 @@ describe("pages", () => {
|
|
|
868
867
|
const body = init.body as FormData;
|
|
869
868
|
const manifest = JSON.parse(body.get("manifest") as string);
|
|
870
869
|
expect(manifest).toMatchInlineSnapshot(`
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
870
|
+
Object {
|
|
871
|
+
"/imgs/logo.png": "2082190357cfd3617ccfe04f340c6247",
|
|
872
|
+
"/logo.html": "d96fef225537c9f5e44a3cb27fd0b492",
|
|
873
|
+
"/logo.js": "6be321bef99e758250dac034474ddbb8",
|
|
874
|
+
"/logo.txt": "1a98fb08af91aca4a7df1764a2c4ddb0",
|
|
875
|
+
}
|
|
876
|
+
`);
|
|
878
877
|
});
|
|
879
878
|
|
|
880
879
|
return {
|
|
@@ -928,10 +927,10 @@ describe("pages", () => {
|
|
|
928
927
|
);
|
|
929
928
|
|
|
930
929
|
expect(std.out).toMatchInlineSnapshot(`
|
|
931
|
-
|
|
930
|
+
"✨ Success! Uploaded 4 files (TIMINGS)
|
|
932
931
|
|
|
933
|
-
|
|
934
|
-
|
|
932
|
+
✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/"
|
|
933
|
+
`);
|
|
935
934
|
});
|
|
936
935
|
|
|
937
936
|
it("should not error when directory names contain periods and houses a extensionless file", async () => {
|
|
@@ -1002,6 +1001,733 @@ describe("pages", () => {
|
|
|
1002
1001
|
`"Pages does not support wrangler.toml"`
|
|
1003
1002
|
);
|
|
1004
1003
|
});
|
|
1004
|
+
|
|
1005
|
+
it("should upload a Functions project", async () => {
|
|
1006
|
+
// set up the directory of static files to upload.
|
|
1007
|
+
mkdirSync("public");
|
|
1008
|
+
writeFileSync("public/README.md", "This is a readme");
|
|
1009
|
+
|
|
1010
|
+
// set up /functions
|
|
1011
|
+
mkdirSync("functions");
|
|
1012
|
+
writeFileSync(
|
|
1013
|
+
"functions/hello.js",
|
|
1014
|
+
`
|
|
1015
|
+
export async function onRequest() {
|
|
1016
|
+
return new Response("Hello, world!");
|
|
1017
|
+
}
|
|
1018
|
+
`
|
|
1019
|
+
);
|
|
1020
|
+
|
|
1021
|
+
mockGetToken("<<funfetti-auth-jwt>>");
|
|
1022
|
+
|
|
1023
|
+
setMockResponse(
|
|
1024
|
+
"/pages/assets/check-missing",
|
|
1025
|
+
"POST",
|
|
1026
|
+
async (_, init) => {
|
|
1027
|
+
const body = JSON.parse(init.body as string) as { hashes: string[] };
|
|
1028
|
+
assertLater(() => {
|
|
1029
|
+
expect(init.headers).toMatchObject({
|
|
1030
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
1031
|
+
});
|
|
1032
|
+
expect(body).toMatchObject({
|
|
1033
|
+
hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
|
|
1034
|
+
});
|
|
1035
|
+
});
|
|
1036
|
+
return body.hashes;
|
|
1037
|
+
}
|
|
1038
|
+
);
|
|
1039
|
+
|
|
1040
|
+
setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
|
|
1041
|
+
assertLater(() => {
|
|
1042
|
+
expect(init.headers).toMatchObject({
|
|
1043
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
1044
|
+
});
|
|
1045
|
+
const body = JSON.parse(init.body as string) as UploadPayloadFile[];
|
|
1046
|
+
expect(body).toMatchObject([
|
|
1047
|
+
{
|
|
1048
|
+
key: "13a03eaf24ae98378acd36ea00f77f2f",
|
|
1049
|
+
value: Buffer.from("This is a readme").toString("base64"),
|
|
1050
|
+
metadata: {
|
|
1051
|
+
contentType: "text/markdown",
|
|
1052
|
+
},
|
|
1053
|
+
base64: true,
|
|
1054
|
+
},
|
|
1055
|
+
]);
|
|
1056
|
+
});
|
|
1057
|
+
});
|
|
1058
|
+
|
|
1059
|
+
setMockResponse(
|
|
1060
|
+
`/pages/assets/upsert-hashes`,
|
|
1061
|
+
"POST",
|
|
1062
|
+
async (_, init) => {
|
|
1063
|
+
assertLater(() => {
|
|
1064
|
+
expect(init.headers).toMatchObject({
|
|
1065
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
1066
|
+
});
|
|
1067
|
+
const body = JSON.parse(init.body as string) as UploadPayloadFile[];
|
|
1068
|
+
expect(body).toMatchObject({
|
|
1069
|
+
hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
|
|
1070
|
+
});
|
|
1071
|
+
});
|
|
1072
|
+
|
|
1073
|
+
return Promise.resolve(true);
|
|
1074
|
+
}
|
|
1075
|
+
);
|
|
1076
|
+
|
|
1077
|
+
setMockResponse(
|
|
1078
|
+
"/accounts/:accountId/pages/projects/foo/deployments",
|
|
1079
|
+
async ([_url, accountId], init) => {
|
|
1080
|
+
assertLater(async () => {
|
|
1081
|
+
expect(accountId).toEqual("some-account-id");
|
|
1082
|
+
expect(init.method).toEqual("POST");
|
|
1083
|
+
const body = init.body as FormData;
|
|
1084
|
+
const manifest = JSON.parse(body.get("manifest") as string);
|
|
1085
|
+
|
|
1086
|
+
// for Functions projects, we auto-generate a `_worker.js` and `_routes.json`
|
|
1087
|
+
// file, based on the contents of `/functions`
|
|
1088
|
+
const generatedWorkerJS = body.get("_worker.js") as Blob;
|
|
1089
|
+
const generatedRoutesJSON = await (
|
|
1090
|
+
body.get("_routes.json") as Blob
|
|
1091
|
+
).text();
|
|
1092
|
+
|
|
1093
|
+
// make sure this is all we uploaded
|
|
1094
|
+
expect([...body.keys()]).toEqual([
|
|
1095
|
+
"manifest",
|
|
1096
|
+
"_worker.js",
|
|
1097
|
+
"_routes.json",
|
|
1098
|
+
]);
|
|
1099
|
+
|
|
1100
|
+
expect(manifest).toMatchInlineSnapshot(`
|
|
1101
|
+
Object {
|
|
1102
|
+
"/README.md": "13a03eaf24ae98378acd36ea00f77f2f",
|
|
1103
|
+
}
|
|
1104
|
+
`);
|
|
1105
|
+
|
|
1106
|
+
// the contents of the generated `_worker.js` file is pretty massive, so I don't
|
|
1107
|
+
// think snapshot testing makes much sense here. Plus, calling
|
|
1108
|
+
// `.toMatchInlineSnapshot()` without any arguments, in order to generate that
|
|
1109
|
+
// snapshot value, doesn't generate anything in this case (probably because the
|
|
1110
|
+
// file contents is too big). So for now, let's test that _worker.js was indeed
|
|
1111
|
+
// generated and that the file size is greater than zero
|
|
1112
|
+
expect(generatedWorkerJS).not.toBeNull();
|
|
1113
|
+
expect(generatedWorkerJS.size).toBeGreaterThan(0);
|
|
1114
|
+
|
|
1115
|
+
expect(generatedRoutesJSON).toMatchInlineSnapshot(`
|
|
1116
|
+
"{
|
|
1117
|
+
\\"version\\": 1,
|
|
1118
|
+
\\"description\\": \\"Generated by wrangler@2.0.28\\",
|
|
1119
|
+
\\"include\\": [
|
|
1120
|
+
\\"/hello\\"
|
|
1121
|
+
],
|
|
1122
|
+
\\"exclude\\": []
|
|
1123
|
+
}"
|
|
1124
|
+
`);
|
|
1125
|
+
});
|
|
1126
|
+
|
|
1127
|
+
return {
|
|
1128
|
+
url: "https://abcxyz.foo.pages.dev/",
|
|
1129
|
+
};
|
|
1130
|
+
}
|
|
1131
|
+
);
|
|
1132
|
+
|
|
1133
|
+
await runWrangler("pages publish public --project-name=foo");
|
|
1134
|
+
|
|
1135
|
+
expect(std.out).toMatchInlineSnapshot(`
|
|
1136
|
+
"Compiled Worker successfully.
|
|
1137
|
+
✨ Success! Uploaded 1 files (TIMINGS)
|
|
1138
|
+
|
|
1139
|
+
✨ Uploading Functions
|
|
1140
|
+
✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/"
|
|
1141
|
+
`);
|
|
1142
|
+
|
|
1143
|
+
expect(std.err).toMatchInlineSnapshot('""');
|
|
1144
|
+
});
|
|
1145
|
+
|
|
1146
|
+
it("should upload an Advanced Mode project", async () => {
|
|
1147
|
+
// set up the directory of static files to upload.
|
|
1148
|
+
mkdirSync("public");
|
|
1149
|
+
writeFileSync("public/README.md", "This is a readme");
|
|
1150
|
+
|
|
1151
|
+
// set up _worker.js
|
|
1152
|
+
writeFileSync(
|
|
1153
|
+
"public/_worker.js",
|
|
1154
|
+
`
|
|
1155
|
+
export default {
|
|
1156
|
+
async fetch(request, env) {
|
|
1157
|
+
const url = new URL(request.url);
|
|
1158
|
+
return url.pathname.startsWith('/api/') ? new Response('Ok') : env.ASSETS.fetch(request);
|
|
1159
|
+
};
|
|
1160
|
+
`
|
|
1161
|
+
);
|
|
1162
|
+
|
|
1163
|
+
mockGetToken("<<funfetti-auth-jwt>>");
|
|
1164
|
+
|
|
1165
|
+
setMockResponse(
|
|
1166
|
+
"/pages/assets/check-missing",
|
|
1167
|
+
"POST",
|
|
1168
|
+
async (_, init) => {
|
|
1169
|
+
const body = JSON.parse(init.body as string) as { hashes: string[] };
|
|
1170
|
+
assertLater(() => {
|
|
1171
|
+
expect(init.headers).toMatchObject({
|
|
1172
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
1173
|
+
});
|
|
1174
|
+
expect(body).toMatchObject({
|
|
1175
|
+
hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
|
|
1176
|
+
});
|
|
1177
|
+
});
|
|
1178
|
+
return body.hashes;
|
|
1179
|
+
}
|
|
1180
|
+
);
|
|
1181
|
+
|
|
1182
|
+
setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
|
|
1183
|
+
assertLater(() => {
|
|
1184
|
+
expect(init.headers).toMatchObject({
|
|
1185
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
1186
|
+
});
|
|
1187
|
+
const body = JSON.parse(init.body as string) as UploadPayloadFile[];
|
|
1188
|
+
expect(body).toMatchObject([
|
|
1189
|
+
{
|
|
1190
|
+
key: "13a03eaf24ae98378acd36ea00f77f2f",
|
|
1191
|
+
value: Buffer.from("This is a readme").toString("base64"),
|
|
1192
|
+
metadata: {
|
|
1193
|
+
contentType: "text/markdown",
|
|
1194
|
+
},
|
|
1195
|
+
base64: true,
|
|
1196
|
+
},
|
|
1197
|
+
]);
|
|
1198
|
+
});
|
|
1199
|
+
});
|
|
1200
|
+
|
|
1201
|
+
setMockResponse(
|
|
1202
|
+
"/accounts/:accountId/pages/projects/foo/deployments",
|
|
1203
|
+
async ([_url, accountId], init) => {
|
|
1204
|
+
assertLater(async () => {
|
|
1205
|
+
expect(accountId).toEqual("some-account-id");
|
|
1206
|
+
expect(init.method).toEqual("POST");
|
|
1207
|
+
const body = init.body as FormData;
|
|
1208
|
+
const manifest = JSON.parse(body.get("manifest") as string);
|
|
1209
|
+
const customWorkerJS = await (
|
|
1210
|
+
body.get("_worker.js") as Blob
|
|
1211
|
+
).text();
|
|
1212
|
+
|
|
1213
|
+
// make sure this is all we uploaded
|
|
1214
|
+
expect([...body.keys()]).toEqual(["manifest", "_worker.js"]);
|
|
1215
|
+
|
|
1216
|
+
expect(manifest).toMatchInlineSnapshot(`
|
|
1217
|
+
Object {
|
|
1218
|
+
"/README.md": "13a03eaf24ae98378acd36ea00f77f2f",
|
|
1219
|
+
}
|
|
1220
|
+
`);
|
|
1221
|
+
|
|
1222
|
+
expect(customWorkerJS).toMatchInlineSnapshot(`
|
|
1223
|
+
"
|
|
1224
|
+
export default {
|
|
1225
|
+
async fetch(request, env) {
|
|
1226
|
+
const url = new URL(request.url);
|
|
1227
|
+
return url.pathname.startsWith('/api/') ? new Response('Ok') : env.ASSETS.fetch(request);
|
|
1228
|
+
};
|
|
1229
|
+
"
|
|
1230
|
+
`);
|
|
1231
|
+
});
|
|
1232
|
+
|
|
1233
|
+
return {
|
|
1234
|
+
url: "https://abcxyz.foo.pages.dev/",
|
|
1235
|
+
};
|
|
1236
|
+
}
|
|
1237
|
+
);
|
|
1238
|
+
|
|
1239
|
+
await runWrangler("pages publish public --project-name=foo");
|
|
1240
|
+
|
|
1241
|
+
expect(std.out).toMatchInlineSnapshot(`
|
|
1242
|
+
"✨ Success! Uploaded 1 files (TIMINGS)
|
|
1243
|
+
|
|
1244
|
+
✨ Uploading _worker.js
|
|
1245
|
+
✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/"
|
|
1246
|
+
`);
|
|
1247
|
+
|
|
1248
|
+
expect(std.err).toMatchInlineSnapshot('""');
|
|
1249
|
+
});
|
|
1250
|
+
|
|
1251
|
+
it("should upload _routes.json for Functions projects, if provided", async () => {
|
|
1252
|
+
// set up the directory of static files to upload.
|
|
1253
|
+
mkdirSync("public");
|
|
1254
|
+
writeFileSync("public/README.md", "This is a readme");
|
|
1255
|
+
|
|
1256
|
+
// set up /functions
|
|
1257
|
+
mkdirSync("functions");
|
|
1258
|
+
writeFileSync(
|
|
1259
|
+
"functions/hello.js",
|
|
1260
|
+
`
|
|
1261
|
+
export async function onRequest() {
|
|
1262
|
+
return new Response("Hello, world!");
|
|
1263
|
+
}
|
|
1264
|
+
`
|
|
1265
|
+
);
|
|
1266
|
+
|
|
1267
|
+
writeFileSync(
|
|
1268
|
+
"functions/goodbye.ts",
|
|
1269
|
+
`
|
|
1270
|
+
export async function onRequest() {
|
|
1271
|
+
return new Response("Bye bye!");
|
|
1272
|
+
}
|
|
1273
|
+
`
|
|
1274
|
+
);
|
|
1275
|
+
|
|
1276
|
+
// set up _routes.json
|
|
1277
|
+
writeFileSync(
|
|
1278
|
+
"public/_routes.json",
|
|
1279
|
+
`
|
|
1280
|
+
{
|
|
1281
|
+
"version": ${ROUTES_SPEC_VERSION},
|
|
1282
|
+
"description": "Custom _routes.json file",
|
|
1283
|
+
"include": ["/hello"],
|
|
1284
|
+
"exclude": []
|
|
1285
|
+
}
|
|
1286
|
+
`
|
|
1287
|
+
);
|
|
1288
|
+
|
|
1289
|
+
mockGetToken("<<funfetti-auth-jwt>>");
|
|
1290
|
+
|
|
1291
|
+
setMockResponse(
|
|
1292
|
+
"/pages/assets/check-missing",
|
|
1293
|
+
"POST",
|
|
1294
|
+
async (_, init) => {
|
|
1295
|
+
const body = JSON.parse(init.body as string) as { hashes: string[] };
|
|
1296
|
+
assertLater(() => {
|
|
1297
|
+
expect(init.headers).toMatchObject({
|
|
1298
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
1299
|
+
});
|
|
1300
|
+
expect(body).toMatchObject({
|
|
1301
|
+
hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
|
|
1302
|
+
});
|
|
1303
|
+
});
|
|
1304
|
+
return body.hashes;
|
|
1305
|
+
}
|
|
1306
|
+
);
|
|
1307
|
+
|
|
1308
|
+
setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
|
|
1309
|
+
assertLater(() => {
|
|
1310
|
+
expect(init.headers).toMatchObject({
|
|
1311
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
1312
|
+
});
|
|
1313
|
+
const body = JSON.parse(init.body as string) as UploadPayloadFile[];
|
|
1314
|
+
expect(body).toMatchObject([
|
|
1315
|
+
{
|
|
1316
|
+
key: "13a03eaf24ae98378acd36ea00f77f2f",
|
|
1317
|
+
value: Buffer.from("This is a readme").toString("base64"),
|
|
1318
|
+
metadata: {
|
|
1319
|
+
contentType: "text/markdown",
|
|
1320
|
+
},
|
|
1321
|
+
base64: true,
|
|
1322
|
+
},
|
|
1323
|
+
]);
|
|
1324
|
+
});
|
|
1325
|
+
});
|
|
1326
|
+
|
|
1327
|
+
setMockResponse(
|
|
1328
|
+
`/pages/assets/upsert-hashes`,
|
|
1329
|
+
"POST",
|
|
1330
|
+
async (_, init) => {
|
|
1331
|
+
assertLater(() => {
|
|
1332
|
+
expect(init.headers).toMatchObject({
|
|
1333
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
1334
|
+
});
|
|
1335
|
+
const body = JSON.parse(init.body as string) as UploadPayloadFile[];
|
|
1336
|
+
expect(body).toMatchObject({
|
|
1337
|
+
hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
|
|
1338
|
+
});
|
|
1339
|
+
});
|
|
1340
|
+
|
|
1341
|
+
return Promise.resolve(true);
|
|
1342
|
+
}
|
|
1343
|
+
);
|
|
1344
|
+
|
|
1345
|
+
setMockResponse(
|
|
1346
|
+
"/accounts/:accountId/pages/projects/foo/deployments",
|
|
1347
|
+
async ([_url, accountId], init) => {
|
|
1348
|
+
assertLater(async () => {
|
|
1349
|
+
expect(accountId).toEqual("some-account-id");
|
|
1350
|
+
expect(init.method).toEqual("POST");
|
|
1351
|
+
const body = init.body as FormData;
|
|
1352
|
+
const manifest = JSON.parse(body.get("manifest") as string);
|
|
1353
|
+
const generatedWorkerJS = body.get("_worker.js") as Blob;
|
|
1354
|
+
const customRoutesJSON = await (
|
|
1355
|
+
body.get("_routes.json") as Blob
|
|
1356
|
+
).text();
|
|
1357
|
+
|
|
1358
|
+
// make sure this is all we uploaded
|
|
1359
|
+
expect([...body.keys()]).toEqual([
|
|
1360
|
+
"manifest",
|
|
1361
|
+
"_worker.js",
|
|
1362
|
+
"_routes.json",
|
|
1363
|
+
]);
|
|
1364
|
+
|
|
1365
|
+
expect(manifest).toMatchInlineSnapshot(`
|
|
1366
|
+
Object {
|
|
1367
|
+
"/README.md": "13a03eaf24ae98378acd36ea00f77f2f",
|
|
1368
|
+
}
|
|
1369
|
+
`);
|
|
1370
|
+
|
|
1371
|
+
// file content of generated `_worker.js` is too massive to snapshot test
|
|
1372
|
+
expect(generatedWorkerJS).not.toBeNull();
|
|
1373
|
+
expect(generatedWorkerJS.size).toBeGreaterThan(0);
|
|
1374
|
+
|
|
1375
|
+
expect(customRoutesJSON).toMatchInlineSnapshot(`
|
|
1376
|
+
"
|
|
1377
|
+
{
|
|
1378
|
+
\\"version\\": 1,
|
|
1379
|
+
\\"description\\": \\"Custom _routes.json file\\",
|
|
1380
|
+
\\"include\\": [\\"/hello\\"],
|
|
1381
|
+
\\"exclude\\": []
|
|
1382
|
+
}
|
|
1383
|
+
"
|
|
1384
|
+
`);
|
|
1385
|
+
});
|
|
1386
|
+
|
|
1387
|
+
return {
|
|
1388
|
+
url: "https://abcxyz.foo.pages.dev/",
|
|
1389
|
+
};
|
|
1390
|
+
}
|
|
1391
|
+
);
|
|
1392
|
+
|
|
1393
|
+
await runWrangler("pages publish public --project-name=foo");
|
|
1394
|
+
|
|
1395
|
+
expect(std.out).toMatchInlineSnapshot(`
|
|
1396
|
+
"Compiled Worker successfully.
|
|
1397
|
+
✨ Success! Uploaded 1 files (TIMINGS)
|
|
1398
|
+
|
|
1399
|
+
✨ Uploading Functions
|
|
1400
|
+
✨ Uploading _routes.json
|
|
1401
|
+
✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/"
|
|
1402
|
+
`);
|
|
1403
|
+
|
|
1404
|
+
expect(std.warn).toMatchInlineSnapshot(`
|
|
1405
|
+
"[33m▲ [43;33m[[43;30mWARNING[43;33m][0m [1m_routes.json is an experimental feature and is subject to change. Please use with care.[0m
|
|
1406
|
+
|
|
1407
|
+
"
|
|
1408
|
+
`);
|
|
1409
|
+
|
|
1410
|
+
expect(std.err).toMatchInlineSnapshot('""');
|
|
1411
|
+
});
|
|
1412
|
+
|
|
1413
|
+
it("should not deploy Functions projects that provide an invalid custom _routes.json file", async () => {
|
|
1414
|
+
// set up the directory of static files to upload.
|
|
1415
|
+
mkdirSync("public");
|
|
1416
|
+
writeFileSync("public/README.md", "This is a readme");
|
|
1417
|
+
|
|
1418
|
+
// set up _routes.json
|
|
1419
|
+
writeFileSync(
|
|
1420
|
+
"public/_routes.json",
|
|
1421
|
+
`
|
|
1422
|
+
{
|
|
1423
|
+
"description": "Custom _routes.json file",
|
|
1424
|
+
"include": [],
|
|
1425
|
+
"exclude": []
|
|
1426
|
+
}
|
|
1427
|
+
`
|
|
1428
|
+
);
|
|
1429
|
+
|
|
1430
|
+
// set up /functions
|
|
1431
|
+
mkdirSync("functions");
|
|
1432
|
+
writeFileSync(
|
|
1433
|
+
"functions/hello.js",
|
|
1434
|
+
`
|
|
1435
|
+
export async function onRequest() {
|
|
1436
|
+
return new Response("Hello, world!");
|
|
1437
|
+
}
|
|
1438
|
+
`
|
|
1439
|
+
);
|
|
1440
|
+
|
|
1441
|
+
mockGetToken("<<funfetti-auth-jwt>>");
|
|
1442
|
+
|
|
1443
|
+
setMockResponse(
|
|
1444
|
+
"/pages/assets/check-missing",
|
|
1445
|
+
"POST",
|
|
1446
|
+
async (_, init) => {
|
|
1447
|
+
const body = JSON.parse(init.body as string) as { hashes: string[] };
|
|
1448
|
+
assertLater(() => {
|
|
1449
|
+
expect(init.headers).toMatchObject({
|
|
1450
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
1451
|
+
});
|
|
1452
|
+
expect(body).toMatchObject({
|
|
1453
|
+
hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
|
|
1454
|
+
});
|
|
1455
|
+
});
|
|
1456
|
+
return body.hashes;
|
|
1457
|
+
}
|
|
1458
|
+
);
|
|
1459
|
+
|
|
1460
|
+
setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
|
|
1461
|
+
assertLater(() => {
|
|
1462
|
+
expect(init.headers).toMatchObject({
|
|
1463
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
1464
|
+
});
|
|
1465
|
+
const body = JSON.parse(init.body as string) as UploadPayloadFile[];
|
|
1466
|
+
expect(body).toMatchObject([
|
|
1467
|
+
{
|
|
1468
|
+
key: "13a03eaf24ae98378acd36ea00f77f2f",
|
|
1469
|
+
value: Buffer.from("This is a readme").toString("base64"),
|
|
1470
|
+
metadata: {
|
|
1471
|
+
contentType: "text/markdown",
|
|
1472
|
+
},
|
|
1473
|
+
base64: true,
|
|
1474
|
+
},
|
|
1475
|
+
]);
|
|
1476
|
+
});
|
|
1477
|
+
});
|
|
1478
|
+
|
|
1479
|
+
await expect(runWrangler("pages publish public --project-name=foo"))
|
|
1480
|
+
.rejects.toThrowErrorMatchingInlineSnapshot(`
|
|
1481
|
+
"Invalid _routes.json file found at: public/_routes.json. Please make sure the JSON object has the following format:
|
|
1482
|
+
{
|
|
1483
|
+
version: ${ROUTES_SPEC_VERSION};
|
|
1484
|
+
include: string[];
|
|
1485
|
+
exclude: string[];
|
|
1486
|
+
}
|
|
1487
|
+
and that at least one include rule is provided.
|
|
1488
|
+
"
|
|
1489
|
+
`);
|
|
1490
|
+
});
|
|
1491
|
+
|
|
1492
|
+
it("should upload _routes.json for Advanced Mode projects, if provided", async () => {
|
|
1493
|
+
// set up the directory of static files to upload.
|
|
1494
|
+
mkdirSync("public");
|
|
1495
|
+
writeFileSync("public/README.md", "This is a readme");
|
|
1496
|
+
|
|
1497
|
+
// set up _routes.json
|
|
1498
|
+
writeFileSync(
|
|
1499
|
+
"public/_routes.json",
|
|
1500
|
+
`
|
|
1501
|
+
{
|
|
1502
|
+
"version": ${ROUTES_SPEC_VERSION},
|
|
1503
|
+
"description": "Custom _routes.json file",
|
|
1504
|
+
"include": ["/api/*"],
|
|
1505
|
+
"exclude": []
|
|
1506
|
+
}
|
|
1507
|
+
`
|
|
1508
|
+
);
|
|
1509
|
+
|
|
1510
|
+
// set up _worker.js
|
|
1511
|
+
writeFileSync(
|
|
1512
|
+
"public/_worker.js",
|
|
1513
|
+
`
|
|
1514
|
+
export default {
|
|
1515
|
+
async fetch(request, env) {
|
|
1516
|
+
const url = new URL(request.url);
|
|
1517
|
+
return url.pathname.startsWith('/api/') ? new Response('Ok') : env.ASSETS.fetch(request);
|
|
1518
|
+
};
|
|
1519
|
+
`
|
|
1520
|
+
);
|
|
1521
|
+
|
|
1522
|
+
mockGetToken("<<funfetti-auth-jwt>>");
|
|
1523
|
+
|
|
1524
|
+
setMockResponse(
|
|
1525
|
+
"/pages/assets/check-missing",
|
|
1526
|
+
"POST",
|
|
1527
|
+
async (_, init) => {
|
|
1528
|
+
const body = JSON.parse(init.body as string) as { hashes: string[] };
|
|
1529
|
+
assertLater(() => {
|
|
1530
|
+
expect(init.headers).toMatchObject({
|
|
1531
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
1532
|
+
});
|
|
1533
|
+
expect(body).toMatchObject({
|
|
1534
|
+
hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
|
|
1535
|
+
});
|
|
1536
|
+
});
|
|
1537
|
+
return body.hashes;
|
|
1538
|
+
}
|
|
1539
|
+
);
|
|
1540
|
+
|
|
1541
|
+
setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
|
|
1542
|
+
assertLater(() => {
|
|
1543
|
+
expect(init.headers).toMatchObject({
|
|
1544
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
1545
|
+
});
|
|
1546
|
+
const body = JSON.parse(init.body as string) as UploadPayloadFile[];
|
|
1547
|
+
expect(body).toMatchObject([
|
|
1548
|
+
{
|
|
1549
|
+
key: "13a03eaf24ae98378acd36ea00f77f2f",
|
|
1550
|
+
value: Buffer.from("This is a readme").toString("base64"),
|
|
1551
|
+
metadata: {
|
|
1552
|
+
contentType: "text/markdown",
|
|
1553
|
+
},
|
|
1554
|
+
base64: true,
|
|
1555
|
+
},
|
|
1556
|
+
]);
|
|
1557
|
+
});
|
|
1558
|
+
});
|
|
1559
|
+
|
|
1560
|
+
setMockResponse(
|
|
1561
|
+
`/pages/assets/upsert-hashes`,
|
|
1562
|
+
"POST",
|
|
1563
|
+
async (_, init) => {
|
|
1564
|
+
assertLater(() => {
|
|
1565
|
+
expect(init.headers).toMatchObject({
|
|
1566
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
1567
|
+
});
|
|
1568
|
+
const body = JSON.parse(init.body as string) as UploadPayloadFile[];
|
|
1569
|
+
expect(body).toMatchObject({
|
|
1570
|
+
hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
|
|
1571
|
+
});
|
|
1572
|
+
});
|
|
1573
|
+
|
|
1574
|
+
return Promise.resolve(true);
|
|
1575
|
+
}
|
|
1576
|
+
);
|
|
1577
|
+
|
|
1578
|
+
setMockResponse(
|
|
1579
|
+
"/accounts/:accountId/pages/projects/foo/deployments",
|
|
1580
|
+
async ([_url, accountId], init) => {
|
|
1581
|
+
assertLater(async () => {
|
|
1582
|
+
expect(accountId).toEqual("some-account-id");
|
|
1583
|
+
expect(init.method).toEqual("POST");
|
|
1584
|
+
const body = init.body as FormData;
|
|
1585
|
+
const manifest = JSON.parse(body.get("manifest") as string);
|
|
1586
|
+
const customWorkerJS = await (
|
|
1587
|
+
body.get("_worker.js") as Blob
|
|
1588
|
+
).text();
|
|
1589
|
+
const customRoutesJSON = await (
|
|
1590
|
+
body.get("_routes.json") as Blob
|
|
1591
|
+
).text();
|
|
1592
|
+
|
|
1593
|
+
// make sure this is all we uploaded
|
|
1594
|
+
expect([...body.keys()]).toEqual([
|
|
1595
|
+
"manifest",
|
|
1596
|
+
"_worker.js",
|
|
1597
|
+
"_routes.json",
|
|
1598
|
+
]);
|
|
1599
|
+
|
|
1600
|
+
expect(manifest).toMatchInlineSnapshot(`
|
|
1601
|
+
Object {
|
|
1602
|
+
"/README.md": "13a03eaf24ae98378acd36ea00f77f2f",
|
|
1603
|
+
}
|
|
1604
|
+
`);
|
|
1605
|
+
|
|
1606
|
+
expect(customWorkerJS).toMatchInlineSnapshot(`
|
|
1607
|
+
"
|
|
1608
|
+
export default {
|
|
1609
|
+
async fetch(request, env) {
|
|
1610
|
+
const url = new URL(request.url);
|
|
1611
|
+
return url.pathname.startsWith('/api/') ? new Response('Ok') : env.ASSETS.fetch(request);
|
|
1612
|
+
};
|
|
1613
|
+
"
|
|
1614
|
+
`);
|
|
1615
|
+
|
|
1616
|
+
expect(customRoutesJSON).toMatchInlineSnapshot(`
|
|
1617
|
+
"
|
|
1618
|
+
{
|
|
1619
|
+
\\"version\\": 1,
|
|
1620
|
+
\\"description\\": \\"Custom _routes.json file\\",
|
|
1621
|
+
\\"include\\": [\\"/api/*\\"],
|
|
1622
|
+
\\"exclude\\": []
|
|
1623
|
+
}
|
|
1624
|
+
"
|
|
1625
|
+
`);
|
|
1626
|
+
});
|
|
1627
|
+
|
|
1628
|
+
return {
|
|
1629
|
+
url: "https://abcxyz.foo.pages.dev/",
|
|
1630
|
+
};
|
|
1631
|
+
}
|
|
1632
|
+
);
|
|
1633
|
+
|
|
1634
|
+
await runWrangler("pages publish public --project-name=foo");
|
|
1635
|
+
|
|
1636
|
+
expect(std.out).toMatchInlineSnapshot(`
|
|
1637
|
+
"✨ Success! Uploaded 1 files (TIMINGS)
|
|
1638
|
+
|
|
1639
|
+
✨ Uploading _worker.js
|
|
1640
|
+
✨ Uploading _routes.json
|
|
1641
|
+
✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/"
|
|
1642
|
+
`);
|
|
1643
|
+
|
|
1644
|
+
expect(std.warn).toMatchInlineSnapshot(`
|
|
1645
|
+
"[33m▲ [43;33m[[43;30mWARNING[43;33m][0m [1m_routes.json is an experimental feature and is subject to change. Please use with care.[0m
|
|
1646
|
+
|
|
1647
|
+
"
|
|
1648
|
+
`);
|
|
1649
|
+
expect(std.err).toMatchInlineSnapshot(`""`);
|
|
1650
|
+
});
|
|
1651
|
+
|
|
1652
|
+
it("should not deploy Advanced Mode projects that provide an invalid _routes.json file", async () => {
|
|
1653
|
+
// set up the directory of static files to upload.
|
|
1654
|
+
mkdirSync("public");
|
|
1655
|
+
writeFileSync("public/README.md", "This is a readme");
|
|
1656
|
+
|
|
1657
|
+
// set up _routes.json
|
|
1658
|
+
writeFileSync(
|
|
1659
|
+
"public/_routes.json",
|
|
1660
|
+
`
|
|
1661
|
+
{
|
|
1662
|
+
"description": "Custom _routes.json file",
|
|
1663
|
+
"include": [],
|
|
1664
|
+
"exclude": []
|
|
1665
|
+
}
|
|
1666
|
+
`
|
|
1667
|
+
);
|
|
1668
|
+
|
|
1669
|
+
// set up _worker.js
|
|
1670
|
+
writeFileSync(
|
|
1671
|
+
"public/_worker.js",
|
|
1672
|
+
`
|
|
1673
|
+
export default {
|
|
1674
|
+
async fetch(request, env) {
|
|
1675
|
+
const url = new URL(request.url);
|
|
1676
|
+
return url.pathname.startsWith('/api/') ? new Response('Ok') : env.ASSETS.fetch(request);
|
|
1677
|
+
};
|
|
1678
|
+
`
|
|
1679
|
+
);
|
|
1680
|
+
|
|
1681
|
+
mockGetToken("<<funfetti-auth-jwt>>");
|
|
1682
|
+
|
|
1683
|
+
setMockResponse(
|
|
1684
|
+
"/pages/assets/check-missing",
|
|
1685
|
+
"POST",
|
|
1686
|
+
async (_, init) => {
|
|
1687
|
+
const body = JSON.parse(init.body as string) as { hashes: string[] };
|
|
1688
|
+
assertLater(() => {
|
|
1689
|
+
expect(init.headers).toMatchObject({
|
|
1690
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
1691
|
+
});
|
|
1692
|
+
expect(body).toMatchObject({
|
|
1693
|
+
hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
|
|
1694
|
+
});
|
|
1695
|
+
});
|
|
1696
|
+
return body.hashes;
|
|
1697
|
+
}
|
|
1698
|
+
);
|
|
1699
|
+
|
|
1700
|
+
setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
|
|
1701
|
+
assertLater(() => {
|
|
1702
|
+
expect(init.headers).toMatchObject({
|
|
1703
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
1704
|
+
});
|
|
1705
|
+
const body = JSON.parse(init.body as string) as UploadPayloadFile[];
|
|
1706
|
+
expect(body).toMatchObject([
|
|
1707
|
+
{
|
|
1708
|
+
key: "13a03eaf24ae98378acd36ea00f77f2f",
|
|
1709
|
+
value: Buffer.from("This is a readme").toString("base64"),
|
|
1710
|
+
metadata: {
|
|
1711
|
+
contentType: "text/markdown",
|
|
1712
|
+
},
|
|
1713
|
+
base64: true,
|
|
1714
|
+
},
|
|
1715
|
+
]);
|
|
1716
|
+
});
|
|
1717
|
+
});
|
|
1718
|
+
|
|
1719
|
+
await expect(runWrangler("pages publish public --project-name=foo"))
|
|
1720
|
+
.rejects.toThrowErrorMatchingInlineSnapshot(`
|
|
1721
|
+
"Invalid _routes.json file found at: public/_routes.json. Please make sure the JSON object has the following format:
|
|
1722
|
+
{
|
|
1723
|
+
version: ${ROUTES_SPEC_VERSION};
|
|
1724
|
+
include: string[];
|
|
1725
|
+
exclude: string[];
|
|
1726
|
+
}
|
|
1727
|
+
and that at least one include rule is provided.
|
|
1728
|
+
"
|
|
1729
|
+
`);
|
|
1730
|
+
});
|
|
1005
1731
|
});
|
|
1006
1732
|
|
|
1007
1733
|
describe("project upload", () => {
|
|
@@ -1063,10 +1789,10 @@ describe("pages", () => {
|
|
|
1063
1789
|
await runWrangler("pages project upload .");
|
|
1064
1790
|
|
|
1065
1791
|
expect(std.out).toMatchInlineSnapshot(`
|
|
1066
|
-
|
|
1792
|
+
"✨ Success! Uploaded 1 files (TIMINGS)
|
|
1067
1793
|
|
|
1068
|
-
|
|
1069
|
-
|
|
1794
|
+
✨ Upload complete!"
|
|
1795
|
+
`);
|
|
1070
1796
|
});
|
|
1071
1797
|
|
|
1072
1798
|
it("should retry uploads", async () => {
|
|
@@ -1131,10 +1857,10 @@ describe("pages", () => {
|
|
|
1131
1857
|
}
|
|
1132
1858
|
|
|
1133
1859
|
expect(std.out).toMatchInlineSnapshot(`
|
|
1134
|
-
|
|
1860
|
+
"✨ Success! Uploaded 1 files (TIMINGS)
|
|
1135
1861
|
|
|
1136
|
-
|
|
1137
|
-
|
|
1862
|
+
✨ Upload complete!"
|
|
1863
|
+
`);
|
|
1138
1864
|
});
|
|
1139
1865
|
|
|
1140
1866
|
it("should try to use multiple buckets (up to the max concurrency)", async () => {
|
|
@@ -1217,10 +1943,10 @@ describe("pages", () => {
|
|
|
1217
1943
|
);
|
|
1218
1944
|
|
|
1219
1945
|
expect(std.out).toMatchInlineSnapshot(`
|
|
1220
|
-
|
|
1946
|
+
"✨ Success! Uploaded 4 files (TIMINGS)
|
|
1221
1947
|
|
|
1222
|
-
|
|
1223
|
-
|
|
1948
|
+
✨ Upload complete!"
|
|
1949
|
+
`);
|
|
1224
1950
|
});
|
|
1225
1951
|
|
|
1226
1952
|
it("should not error when directory names contain periods and houses a extensionless file", async () => {
|