diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 3f79ea788ecf..a43e5d51226a 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -59,7 +59,7 @@ jobs: run: npm ci - name: Run builds - run: npm run -w wrangler build + run: npm run build env: NODE_ENV: "production" diff --git a/packages/wrangler/e2e/c3-integration.test.ts b/packages/wrangler/e2e/c3-integration.test.ts index f1d61294494f..7bb5db63f4fc 100644 --- a/packages/wrangler/e2e/c3-integration.test.ts +++ b/packages/wrangler/e2e/c3-integration.test.ts @@ -19,14 +19,16 @@ describe("c3 integration", () => { let workerName: string; let workerPath: string; let workersDev: string | null = null; - let run: typeof shellac; + let runInRoot: typeof shellac; + let runInWorker: typeof shellac; let normalize: (str: string) => string; beforeAll(async () => { const root = await makeRoot(); - run = shellac.in(root).env(process.env); + runInRoot = shellac.in(root).env(process.env); workerName = `smoke-test-worker-${crypto.randomBytes(4).toString("hex")}`; workerPath = path.join(root, workerName); + runInWorker = shellac.in(workerPath).env(process.env); normalize = (str) => normalizeOutput(str, { [workerName]: "smoke-test-worker" }); }); @@ -36,15 +38,19 @@ describe("c3 integration", () => { const env = { ...process.env, WRANGLER_C3_COMMAND: `exec ${pathToC3}`, + GIT_AUTHOR_NAME: "test-user", + GIT_AUTHOR_EMAIL: "test-user@cloudflare.com", + GIT_COMMITTER_NAME: "test-user", + GIT_COMMITTER_EMAIL: "test-user@cloudflare.com", }; - await run.env(env)`$$ ${WRANGLER} init ${workerName} --yes`; + await runInRoot.env(env)`$ ${WRANGLER} init ${workerName} --yes`; expect(existsSync(workerPath)).toBe(true); }); it("deploy the worker", async () => { - const { stdout, stderr } = await run.in(workerPath)`$ ${WRANGLER} deploy`; + const { stdout, stderr } = await runInWorker`$ ${WRANGLER} deploy`; expect(normalize(stdout)).toMatchInlineSnapshot(` "Total Upload: xx KiB / gzip: xx KiB Uploaded smoke-test-worker (TIMINGS) @@ -54,22 +60,30 @@ describe("c3 integration", () => { `); expect(stderr).toMatchInlineSnapshot('""'); workersDev = matchWorkersDev(stdout); - const responseText = await retry("", () => - fetch(`https://${workerName}.${workersDev}`).then((r) => r.text()) + const { text } = await retry( + (s) => s.status !== 200, + async () => { + const r = await fetch(`https://${workerName}.${workersDev}`); + return { text: await r.text(), status: r.status }; + } ); - expect(responseText).toMatchInlineSnapshot('"Hello World!"'); + expect(text).toMatchInlineSnapshot('"Hello World!"'); }); - it("deletes the worker", async () => { - const { stdout, stderr } = await run.in(workerPath)`$ ${WRANGLER} delete`; + it("delete the worker", async () => { + const { stdout, stderr } = await runInWorker`$$ ${WRANGLER} delete`; expect(normalize(stdout)).toMatchInlineSnapshot(` "? Are you sure you want to delete smoke-test-worker? This action cannot be undone. 🤖 Using default value in non-interactive context: yes Successfully deleted smoke-test-worker" `); expect(stderr).toMatchInlineSnapshot('""'); - const status = await retry(200, () => - fetch(`https://${workerName}.${workersDev}`).then((r) => r.status) + const { status } = await retry( + (s) => s.status === 200 || s.status === 500, + async () => { + const r = await fetch(`https://${workerName}.${workersDev}`); + return { text: await r.text(), status: r.status }; + } ); expect(status).toBe(404); }); diff --git a/packages/wrangler/e2e/deploy.test.ts b/packages/wrangler/e2e/deploy.test.ts index 17c29e80a907..78d9ccc4dd41 100644 --- a/packages/wrangler/e2e/deploy.test.ts +++ b/packages/wrangler/e2e/deploy.test.ts @@ -68,10 +68,14 @@ describe("deploy", () => { expect(stderr).toMatchInlineSnapshot('""'); workersDev = matchWorkersDev(stdout); - const responseText = await retry("", () => - fetch(`https://${workerName}.${workersDev}`).then((r) => r.text()) + const { text } = await retry( + (s) => s.status !== 200, + async () => { + const r = await fetch(`https://${workerName}.${workersDev}`); + return { text: await r.text(), status: r.status }; + } ); - expect(responseText).toMatchInlineSnapshot('"Hello World!"'); + expect(text).toMatchInlineSnapshot('"Hello World!"'); }); it("modify & deploy worker", async () => { @@ -94,10 +98,14 @@ describe("deploy", () => { expect(stderr).toMatchInlineSnapshot('""'); workersDev = matchWorkersDev(stdout); - const responseText = await retry("Hello World!", () => - fetch(`https://${workerName}.${workersDev}`).then((r) => r.text()) + const { text } = await retry( + (s) => s.status !== 200 || s.text === "Hello World!", + async () => { + const r = await fetch(`https://${workerName}.${workersDev}`); + return { text: await r.text(), status: r.status }; + } ); - expect(responseText).toMatchInlineSnapshot('"Updated Worker!"'); + expect(text).toMatchInlineSnapshot('"Updated Worker!"'); }); it("delete worker", async () => { @@ -108,8 +116,12 @@ describe("deploy", () => { Successfully deleted smoke-test-worker" `); expect(stderr).toMatchInlineSnapshot('""'); - const status = await retry(200, () => - fetch(`https://${workerName}.${workersDev}`).then((r) => r.status) + const { status } = await retry( + (s) => s.status === 200 || s.status === 500, + async () => { + const r = await fetch(`https://${workerName}.${workersDev}`); + return { text: await r.text(), status: r.status }; + } ); expect(status).toBe(404); }); diff --git a/packages/wrangler/e2e/deployments.test.ts b/packages/wrangler/e2e/deployments.test.ts index 1c0006db07b1..f370b956a8d0 100644 --- a/packages/wrangler/e2e/deployments.test.ts +++ b/packages/wrangler/e2e/deployments.test.ts @@ -41,7 +41,7 @@ describe("deployments", () => { [workerName]: "smoke-test-worker", [email]: "person@example.com", }); - }); + }, 50_000); it("init worker", async () => { const { stdout } = @@ -78,10 +78,14 @@ describe("deployments", () => { expect(stderr).toMatchInlineSnapshot('""'); workersDev = matchWorkersDev(stdout); - const responseText = await retry("", () => - fetch(`https://${workerName}.${workersDev}`).then((r) => r.text()) + const { text } = await retry( + (s) => s.status !== 200, + async () => { + const r = await fetch(`https://${workerName}.${workersDev}`); + return { text: await r.text(), status: r.status }; + } ); - expect(responseText).toMatchInlineSnapshot('"Hello World!"'); + expect(text).toMatchInlineSnapshot('"Hello World!"'); }); it("list 1 deployment", async () => { @@ -119,10 +123,14 @@ describe("deployments", () => { expect(stderr).toMatchInlineSnapshot('""'); workersDev = matchWorkersDev(stdout); - const responseText = await retry("Hello World!", () => - fetch(`https://${workerName}.${workersDev}`).then((r) => r.text()) + const { text } = await retry( + (s) => s.status !== 200 || s.text === "Hello World!", + async () => { + const r = await fetch(`https://${workerName}.${workersDev}`); + return { text: await r.text(), status: r.status }; + } ); - expect(responseText).toMatchInlineSnapshot('"Updated Worker!"'); + expect(text).toMatchInlineSnapshot('"Updated Worker!"'); }); it("list 2 deployments", async () => { @@ -186,8 +194,9 @@ describe("deployments", () => { Successfully deleted smoke-test-worker" `); expect(stderr).toMatchInlineSnapshot('""'); - const status = await retry(200, () => - fetch(`https://${workerName}.${workersDev}`).then((r) => r.status) + const status = await retry( + (s) => s === 200 || s === 500, + () => fetch(`https://${workerName}.${workersDev}`).then((r) => r.status) ); expect(status).toBe(404); }); diff --git a/packages/wrangler/e2e/dev.test.ts b/packages/wrangler/e2e/dev.test.ts index aa36d4cfa0d5..9d1115e994d7 100644 --- a/packages/wrangler/e2e/dev.test.ts +++ b/packages/wrangler/e2e/dev.test.ts @@ -22,7 +22,7 @@ async function runDevSession( const bg = await shellac.env(process.env).bg` in ${workerPath} { exits { - $$ ${WRANGLER} dev ${flags} --port ${port} + $ ${WRANGLER} dev ${flags} --port ${port} } } `; @@ -66,10 +66,14 @@ describe("basic dev tests", () => { it("can modify worker during dev session (local)", async () => { await runDevSession(workerPath, "", async (port) => { - const responseText = await retry("", () => - fetch(`http://127.0.0.1:${port}`).then((r) => r.text()) + const { text } = await retry( + (s) => s.status !== 200, + async () => { + const r = await fetch(`http://127.0.0.1:${port}`); + return { text: await r.text(), status: r.status }; + } ); - expect(responseText).toMatchInlineSnapshot('"Hello World!"'); + expect(text).toMatchInlineSnapshot('"Hello World!"'); await seed(workerPath, { "src/index.ts": dedent` @@ -80,19 +84,27 @@ describe("basic dev tests", () => { }`, }); - const response2Text = await retry("Hello World!", () => - fetch(`http://127.0.0.1:${port}`).then((r) => r.text()) + const { text: text2 } = await retry( + (s) => s.status !== 200 || s.text === "Hello World!", + async () => { + const r = await fetch(`http://127.0.0.1:${port}`); + return { text: await r.text(), status: r.status }; + } ); - expect(response2Text).toMatchInlineSnapshot('"Updated Worker!"'); + expect(text2).toMatchInlineSnapshot('"Updated Worker!"'); }); }); it("can modify worker during dev session (remote)", async () => { await runDevSession(workerPath, "--remote --ip 127.0.0.1", async (port) => { - const responseText = await retry("", () => - fetch(`http://127.0.0.1:${port}`).then((r) => r.text()) + const { text } = await retry( + (s) => s.status !== 200 || s.text === "", + async () => { + const r = await fetch(`http://127.0.0.1:${port}`); + return { text: await r.text(), status: r.status }; + } ); - expect(responseText).toMatchInlineSnapshot('"Hello World!"'); + expect(text).toMatchInlineSnapshot('"Hello World!"'); await seed(workerPath, { "src/index.ts": dedent` @@ -104,12 +116,17 @@ describe("basic dev tests", () => { }); // Give a bit of time for the change to propagate. + // Otherwise the process has a tendency to hang. await setTimeout(5000); - const response2Text = await retry("Hello World!", () => - fetch(`http://127.0.0.1:${port}`).then((r) => r.text()) + const { text: text2 } = await retry( + (s) => s.status !== 200 || s.text === "Hello World!", + async () => { + const r = await fetch(`http://127.0.0.1:${port}`); + return { text: await r.text(), status: r.status }; + } ); - expect(response2Text).toMatchInlineSnapshot('"Updated Worker!"'); + expect(text2).toMatchInlineSnapshot('"Updated Worker!"'); }); }); }); diff --git a/packages/wrangler/e2e/helpers/normalize.ts b/packages/wrangler/e2e/helpers/normalize.ts index c8c2f62fa05b..5ca1f6c95ef1 100644 --- a/packages/wrangler/e2e/helpers/normalize.ts +++ b/packages/wrangler/e2e/helpers/normalize.ts @@ -104,7 +104,7 @@ export function stripTimings(stdout: string): string { export function npmStripTimings(stdout: string): string { return stdout .replace( - /added \d+ packages, and audited \d+ packages in \d+s/, + /added \d+ packages, and audited \d+ packages in [\dms]+/, "added (N) packages, and audited (N) packages in (TIMINGS)" ) .replace( diff --git a/packages/wrangler/e2e/helpers/retry.ts b/packages/wrangler/e2e/helpers/retry.ts index a8e803667998..d749998b6322 100644 --- a/packages/wrangler/e2e/helpers/retry.ts +++ b/packages/wrangler/e2e/helpers/retry.ts @@ -1,20 +1,22 @@ import { setTimeout } from "node:timers/promises"; export async function retry( - originalState: T, + retryIf: (currentState: T) => boolean, action: () => Promise, - n = 20 + n = 30 ): Promise { + const states: T[] = []; while (n >= 0) { try { const currentState = await action(); - if (currentState !== originalState) { + if (!retryIf(currentState)) { return currentState; } - } catch (e) { - await setTimeout(2_000); - n--; - } + states.push(currentState); + } catch {} + await setTimeout(2_000); + n--; } + console.error(states); throw new Error("Timed out waiting for state to change"); }