Skip to content

Commit 20a0f17

Browse files
authored
WfP Assets support (#7448)
* WfP Assets support * Add e2e test for WfP & Assets
1 parent 21a9e24 commit 20a0f17

File tree

7 files changed

+244
-83
lines changed

7 files changed

+244
-83
lines changed

.changeset/smart-plants-wash.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"wrangler": minor
3+
---
4+
5+
feat: Allow Workers for Platforms scripts (scripts deployed with `--dispatch-namespace`) to bring along `assets`

packages/wrangler/e2e/deployments.test.ts

Lines changed: 142 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import assert from "node:assert";
22
import dedent from "ts-dedent";
33
import { fetch } from "undici";
4-
import { afterAll, describe, expect, it, vi } from "vitest";
4+
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
55
import { CLOUDFLARE_ACCOUNT_ID } from "./helpers/account-id";
66
import { WranglerE2ETestHelper } from "./helpers/e2e-wrangler-test";
77
import { generateResourceName } from "./helpers/generate-resource-name";
@@ -14,6 +14,8 @@ const normalize = (str: string) =>
1414
[CLOUDFLARE_ACCOUNT_ID]: "CLOUDFLARE_ACCOUNT_ID",
1515
}).replaceAll(/^Author:(\s+).+@.+$/gm, "Author:[email protected]");
1616
const workerName = generateResourceName();
17+
const dispatchNamespaceName = generateResourceName("dispatch");
18+
const dispatchWorkerName = generateResourceName();
1719

1820
describe("deployments", { timeout: TIMEOUT }, () => {
1921
let deployedUrl: string;
@@ -250,11 +252,118 @@ const checkAssets = async (testCases: AssetTestCase[], deployedUrl: string) => {
250252
}
251253
};
252254

253-
describe("Workers + Assets deployment", { timeout: TIMEOUT }, () => {
254-
let deployedUrl: string;
255+
describe.each([
256+
{
257+
name: "regular Worker",
258+
flags: "",
259+
async beforeAll() {},
260+
async afterAll(helper: WranglerE2ETestHelper) {
261+
await helper.run(`wrangler delete`);
262+
},
263+
expectInitialStdout: (output: string) => {
264+
expect(output).toEqual(`🌀 Building list of assets...
265+
🌀 Starting asset upload...
266+
🌀 Found 3 new or modified static assets to upload. Proceeding with upload...
267+
+ /404.html
268+
+ /index.html
269+
+ /[boop].html
270+
Uploaded 1 of 3 assets
271+
Uploaded 2 of 3 assets
272+
Uploaded 3 of 3 assets
273+
✨ Success! Uploaded 3 files (TIMINGS)
274+
Total Upload: xx KiB / gzip: xx KiB
275+
Uploaded tmp-e2e-worker-00000000-0000-0000-0000-000000000000 (TIMINGS)
276+
Deployed tmp-e2e-worker-00000000-0000-0000-0000-000000000000 triggers (TIMINGS)
277+
https://tmp-e2e-worker-00000000-0000-0000-0000-000000000000.SUBDOMAIN.workers.dev
278+
Current Version ID: 00000000-0000-0000-0000-000000000000`);
279+
},
280+
expectSubsequentStdout: (output: string) => {
281+
expect(output).toEqual(`🌀 Building list of assets...
282+
🌀 Starting asset upload...
283+
No files to upload. Proceeding with deployment...
284+
Total Upload: xx KiB / gzip: xx KiB
285+
Uploaded tmp-e2e-worker-00000000-0000-0000-0000-000000000000 (TIMINGS)
286+
Deployed tmp-e2e-worker-00000000-0000-0000-0000-000000000000 triggers (TIMINGS)
287+
https://tmp-e2e-worker-00000000-0000-0000-0000-000000000000.SUBDOMAIN.workers.dev
288+
Current Version ID: 00000000-0000-0000-0000-000000000000`);
289+
},
290+
},
291+
{
292+
name: "Workers for Platforms",
293+
flags: `--dispatch-namespace ${dispatchNamespaceName}`,
294+
url: "",
295+
async beforeAll(helper: WranglerE2ETestHelper) {
296+
await helper.seed({
297+
"dispatch-worker/wrangler.toml": dedent`
298+
name = "${dispatchWorkerName}"
299+
main = "./src/index.js"
300+
compatibility_date = "2023-01-01"
301+
302+
[[dispatch_namespaces]]
303+
binding = "DISPATCH"
304+
namespace = "${dispatchNamespaceName}"
305+
`,
306+
"dispatch-worker/src/index.js": dedent`
307+
export default {
308+
async fetch(request, env, ctx) {
309+
const stub = env.DISPATCH.get("${workerName}");
310+
return stub.fetch(request);
311+
}
312+
}
313+
`,
314+
});
315+
await helper.run(
316+
`wrangler dispatch-namespace create ${dispatchNamespaceName}`
317+
);
318+
const { stdout } = await helper.run(
319+
`wrangler deploy -c dispatch-worker/wrangler.toml`
320+
);
321+
const match = stdout.match(
322+
/(?<url>https:\/\/tmp-e2e-.+?\..+?\.workers\.dev)/
323+
);
324+
assert(match?.groups);
325+
this.url = match.groups.url;
326+
},
327+
async afterAll(helper: WranglerE2ETestHelper) {
328+
await helper.run(`wrangler delete -c dispatch-worker/wrangler.toml`);
329+
await helper.run(
330+
`wrangler dispatch-namespace delete ${dispatchNamespaceName}`
331+
);
332+
},
333+
expectInitialStdout: (output: string) => {
334+
expect(output).toEqual(`🌀 Building list of assets...
335+
🌀 Starting asset upload...
336+
🌀 Found 3 new or modified static assets to upload. Proceeding with upload...
337+
+ /404.html
338+
+ /index.html
339+
+ /[boop].html
340+
Uploaded 1 of 3 assets
341+
Uploaded 2 of 3 assets
342+
Uploaded 3 of 3 assets
343+
✨ Success! Uploaded 3 files (TIMINGS)
344+
Total Upload: xx KiB / gzip: xx KiB
345+
Uploaded tmp-e2e-worker-00000000-0000-0000-0000-000000000000 (TIMINGS)
346+
Dispatch Namespace: tmp-e2e-dispatch-00000000-0000-0000-0000-000000000000
347+
Current Version ID: 00000000-0000-0000-0000-000000000000`);
348+
},
349+
expectSubsequentStdout: (output: string) => {
350+
expect(output).toEqual(`🌀 Building list of assets...
351+
🌀 Starting asset upload...
352+
No files to upload. Proceeding with deployment...
353+
Total Upload: xx KiB / gzip: xx KiB
354+
Uploaded tmp-e2e-worker-00000000-0000-0000-0000-000000000000 (TIMINGS)
355+
Dispatch Namespace: tmp-e2e-dispatch-00000000-0000-0000-0000-000000000000
356+
Current Version ID: 00000000-0000-0000-0000-000000000000`);
357+
},
358+
},
359+
])("Workers + Assets deployment: $name", { timeout: TIMEOUT }, (testcase) => {
360+
let deployedUrl: string | undefined;
255361
const helper = new WranglerE2ETestHelper();
362+
beforeAll(async () => {
363+
await testcase.beforeAll(helper);
364+
});
256365
afterAll(async () => {
257-
await helper.run(`wrangler delete`);
366+
await testcase.afterAll(helper);
258367
});
259368
it("deploys a Workers + Assets project with assets only", async () => {
260369
await helper.seed({
@@ -267,29 +376,17 @@ describe("Workers + Assets deployment", { timeout: TIMEOUT }, () => {
267376
...initialAssets,
268377
});
269378

270-
const output = await helper.run(`wrangler deploy`);
271-
expect(normalize(output.stdout)).toMatchInlineSnapshot(`
272-
"🌀 Building list of assets...
273-
🌀 Starting asset upload...
274-
🌀 Found 3 new or modified static assets to upload. Proceeding with upload...
275-
+ /404.html
276-
+ /index.html
277-
+ /[boop].html
278-
Uploaded 1 of 3 assets
279-
Uploaded 2 of 3 assets
280-
Uploaded 3 of 3 assets
281-
✨ Success! Uploaded 3 files (TIMINGS)
282-
Total Upload: xx KiB / gzip: xx KiB
283-
Uploaded tmp-e2e-worker-00000000-0000-0000-0000-000000000000 (TIMINGS)
284-
Deployed tmp-e2e-worker-00000000-0000-0000-0000-000000000000 triggers (TIMINGS)
285-
https://tmp-e2e-worker-00000000-0000-0000-0000-000000000000.SUBDOMAIN.workers.dev
286-
Current Version ID: 00000000-0000-0000-0000-000000000000"
287-
`);
288-
const match = output.stdout.match(
289-
/(?<url>https:\/\/tmp-e2e-.+?\..+?\.workers\.dev)/
290-
);
291-
assert(match?.groups);
292-
deployedUrl = match.groups.url;
379+
const output = await helper.run(`wrangler deploy ${testcase.flags}`);
380+
testcase.expectInitialStdout(normalize(output.stdout));
381+
if (testcase.url) {
382+
deployedUrl = testcase.url;
383+
} else {
384+
const match = output.stdout.match(
385+
/(?<url>https:\/\/tmp-e2e-.+?\..+?\.workers\.dev)/
386+
);
387+
assert(match?.groups);
388+
deployedUrl = match.groups.url;
389+
}
293390

294391
const testCases: AssetTestCase[] = [
295392
// Tests html_handling = "auto_trailing_slash" (default):
@@ -349,23 +446,16 @@ describe("Workers + Assets deployment", { timeout: TIMEOUT }, () => {
349446
}`,
350447
...initialAssets,
351448
});
352-
const output = await helper.run(`wrangler deploy`);
449+
const output = await helper.run(`wrangler deploy ${testcase.flags}`);
353450
// expect only no asset files to be uploaded as no new asset files have been added
354-
expect(normalize(output.stdout)).toMatchInlineSnapshot(`
355-
"🌀 Building list of assets...
356-
🌀 Starting asset upload...
357-
No files to upload. Proceeding with deployment...
358-
Total Upload: xx KiB / gzip: xx KiB
359-
Uploaded tmp-e2e-worker-00000000-0000-0000-0000-000000000000 (TIMINGS)
360-
Deployed tmp-e2e-worker-00000000-0000-0000-0000-000000000000 triggers (TIMINGS)
361-
https://tmp-e2e-worker-00000000-0000-0000-0000-000000000000.SUBDOMAIN.workers.dev
362-
Current Version ID: 00000000-0000-0000-0000-000000000000"
363-
`);
364-
const match = output.stdout.match(
365-
/(?<url>https:\/\/tmp-e2e-.+?\..+?\.workers\.dev)/
366-
);
367-
assert(match?.groups);
368-
deployedUrl = match.groups.url;
451+
testcase.expectSubsequentStdout(normalize(output.stdout));
452+
if (!deployedUrl) {
453+
const match = output.stdout.match(
454+
/(?<url>https:\/\/tmp-e2e-.+?\..+?\.workers\.dev)/
455+
);
456+
assert(match?.groups);
457+
deployedUrl = match.groups.url;
458+
}
369459

370460
const testCases: AssetTestCase[] = [
371461
// because html handling has now been set to "none", only exact matches will be served
@@ -400,7 +490,6 @@ describe("Workers + Assets deployment", { timeout: TIMEOUT }, () => {
400490
);
401491
expect(text).toContain("<h1>404.html</h1>");
402492
});
403-
404493
it("runs user worker ahead of matching assets when serve_directly = false", async () => {
405494
await helper.seed({
406495
"wrangler.toml": dedent`
@@ -423,24 +512,16 @@ describe("Workers + Assets deployment", { timeout: TIMEOUT }, () => {
423512
...initialAssets,
424513
});
425514

426-
const output = await helper.run(`wrangler deploy`);
515+
const output = await helper.run(`wrangler deploy ${testcase.flags}`);
427516
// expect only no asset files to be uploaded as no new asset files have been added
428-
expect(normalize(output.stdout)).toMatchInlineSnapshot(`
429-
"🌀 Building list of assets...
430-
🌀 Starting asset upload...
431-
No files to upload. Proceeding with deployment...
432-
Total Upload: xx KiB / gzip: xx KiB
433-
Uploaded tmp-e2e-worker-00000000-0000-0000-0000-000000000000 (TIMINGS)
434-
Deployed tmp-e2e-worker-00000000-0000-0000-0000-000000000000 triggers (TIMINGS)
435-
https://tmp-e2e-worker-00000000-0000-0000-0000-000000000000.SUBDOMAIN.workers.dev
436-
Current Version ID: 00000000-0000-0000-0000-000000000000"
437-
`);
438-
439-
const match = output.stdout.match(
440-
/(?<url>https:\/\/tmp-e2e-.+?\..+?\.workers\.dev)/
441-
);
442-
assert(match?.groups);
443-
deployedUrl = match.groups.url;
517+
testcase.expectSubsequentStdout(normalize(output.stdout));
518+
if (!deployedUrl) {
519+
const match = output.stdout.match(
520+
/(?<url>https:\/\/tmp-e2e-.+?\..+?\.workers\.dev)/
521+
);
522+
assert(match?.groups);
523+
deployedUrl = match.groups.url;
524+
}
444525

445526
const testCases: AssetTestCase[] = [
446527
{

packages/wrangler/e2e/helpers/e2e-wrangler-test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,20 @@ export class WranglerE2ETestHelper {
6868
return id;
6969
}
7070

71+
async dispatchNamespace(isLocal: boolean) {
72+
const name = generateResourceName("dispatch");
73+
if (isLocal) {
74+
throw new Error(
75+
"Dispatch namespaces are not supported in local mode (yet)"
76+
);
77+
}
78+
await this.run(`wrangler dispatch-namespace create ${name}`);
79+
onTestFinished(async () => {
80+
await this.run(`wrangler dispatch-namespace delete ${name}`);
81+
});
82+
return name;
83+
}
84+
7185
async r2(isLocal: boolean) {
7286
const name = generateResourceName("r2");
7387
if (isLocal) {

packages/wrangler/src/__tests__/deploy.test.ts

Lines changed: 69 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5140,6 +5140,36 @@ addEventListener('fetch', event => {});`
51405140
});
51415141
await runWrangler("deploy");
51425142
});
5143+
5144+
it("should be able to upload to a WfP script", async () => {
5145+
const assets = [
5146+
{ filePath: "file-1.txt", content: "Content of file-1" },
5147+
{ filePath: "boop/file-2.txt", content: "Content of file-2" },
5148+
];
5149+
writeAssets(assets);
5150+
writeWorkerSource({ format: "js" });
5151+
writeWranglerConfig({
5152+
compatibility_date: "2024-09-27",
5153+
compatibility_flags: ["nodejs_compat"],
5154+
assets: {
5155+
directory: "assets",
5156+
html_handling: "none",
5157+
},
5158+
});
5159+
await mockAUSRequest(undefined, undefined, undefined, "my-namespace");
5160+
mockSubDomainRequest();
5161+
mockUploadWorkerRequest({
5162+
expectedAssets: {
5163+
jwt: "<<aus-completion-token>>",
5164+
config: { html_handling: "none" },
5165+
},
5166+
expectedCompatibilityDate: "2024-09-27",
5167+
expectedCompatibilityFlags: ["nodejs_compat"],
5168+
expectedMainModule: undefined,
5169+
expectedDispatchNamespace: "my-namespace",
5170+
});
5171+
await runWrangler("deploy --dispatch-namespace my-namespace");
5172+
});
51435173
});
51445174

51455175
describe("workers_dev setting", () => {
@@ -12542,25 +12572,46 @@ function mockPostQueueHTTPConsumer(
1254212572
const mockAUSRequest = async (
1254312573
bodies?: AssetManifest[],
1254412574
buckets: string[][] = [[]],
12545-
jwt: string = "<<aus-completion-token>>"
12575+
jwt: string = "<<aus-completion-token>>",
12576+
dispatchNamespace?: string
1254612577
) => {
12547-
msw.use(
12548-
http.post<never, AssetManifest>(
12549-
`*/accounts/some-account-id/workers/scripts/test-name/assets-upload-session`,
12550-
async ({ request }) => {
12551-
bodies?.push(await request.json());
12552-
return HttpResponse.json(
12553-
{
12554-
success: true,
12555-
errors: [],
12556-
messages: [],
12557-
result: { jwt, buckets },
12558-
},
12559-
{ status: 201 }
12560-
);
12561-
}
12562-
)
12563-
);
12578+
if (dispatchNamespace) {
12579+
msw.use(
12580+
http.post<never, AssetManifest>(
12581+
`*/accounts/some-account-id/workers/dispatch/namespaces/my-namespace/scripts/test-name/assets-upload-session`,
12582+
async ({ request }) => {
12583+
bodies?.push(await request.json());
12584+
return HttpResponse.json(
12585+
{
12586+
success: true,
12587+
errors: [],
12588+
messages: [],
12589+
result: { jwt, buckets },
12590+
},
12591+
{ status: 201 }
12592+
);
12593+
}
12594+
)
12595+
);
12596+
} else {
12597+
msw.use(
12598+
http.post<never, AssetManifest>(
12599+
`*/accounts/some-account-id/workers/scripts/test-name/assets-upload-session`,
12600+
async ({ request }) => {
12601+
bodies?.push(await request.json());
12602+
return HttpResponse.json(
12603+
{
12604+
success: true,
12605+
errors: [],
12606+
messages: [],
12607+
result: { jwt, buckets },
12608+
},
12609+
{ status: 201 }
12610+
);
12611+
}
12612+
)
12613+
);
12614+
}
1256412615
};
1256512616

1256612617
const mockAssetUploadRequest = async (

0 commit comments

Comments
 (0)