From e967c398352da89fa8e6c981d2aa47efb538e88b Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin Date: Mon, 17 Aug 2026 09:51:53 +0100 Subject: [PATCH 1/5] [wrangler] Skip container deploy e2e tests on non-Linux CI (#15233) --- .../e2e/durable-objects-exports.test.ts | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/packages/wrangler/e2e/durable-objects-exports.test.ts b/packages/wrangler/e2e/durable-objects-exports.test.ts index 08a2609f0e4..9a0475521db 100644 --- a/packages/wrangler/e2e/durable-objects-exports.test.ts +++ b/packages/wrangler/e2e/durable-objects-exports.test.ts @@ -1,6 +1,7 @@ import assert from "node:assert"; import { setTimeout } from "node:timers/promises"; import { getCloudflareContainerRegistry } from "@cloudflare/containers-shared"; +import ci from "ci-info"; import dedent from "ts-dedent"; import { afterAll, beforeAll, describe, it } from "vitest"; import { CLOUDFLARE_ACCOUNT_ID } from "./helpers/account-id"; @@ -13,6 +14,13 @@ const TIMEOUT = 60_000; // `wrangler deploy`. const CONTAINER_DEPLOY_TIMEOUT = 240_000; +// The container deploy tests never *run* a container, but they do have to build +// and push a `linux/amd64` image, which needs Docker. That rules out the hosted +// non-Linux CI runners. +const skipContainerDeployTests = + Boolean(process.env.LOCAL_TESTS_WITHOUT_DOCKER) || + (ci.isCI && process.platform !== "linux"); + describe.skipIf(!CLOUDFLARE_ACCOUNT_ID)( "durable-objects-exports", { timeout: TIMEOUT }, @@ -624,9 +632,7 @@ describe.skipIf(!CLOUDFLARE_ACCOUNT_ID)( }); }); - // Pushing the container image needs Docker. Unlike the local dev tests we - // never *run* the container, so this is not restricted to Linux. - describe.skipIf(process.env.LOCAL_TESTS_WITHOUT_DOCKER)( + describe.skipIf(skipContainerDeployTests)( "containers attached via `exports`: deploy", { timeout: CONTAINER_DEPLOY_TIMEOUT }, () => { @@ -682,7 +688,16 @@ describe.skipIf(!CLOUDFLARE_ACCOUNT_ID)( `, }); - await helper.run(`wrangler containers build . -t ${imageTag} -p`); + const build = await helper.run( + `wrangler containers build . -t ${imageTag} -p` + ); + // Assert here rather than letting the tests below fail on a missing + // image, so that a broken or missing Docker installation is reported + // as such instead of as an unrelated assertion in `getDeployedUrl()`. + assert( + build.status === 0, + `Failed to build and push ${imageTag} (exit code ${build.status}):\n${build.stderr}` + ); // Give the registry a moment to make the pushed image available. await setTimeout(5_000); }, CONTAINER_DEPLOY_TIMEOUT); From bc5726bd0b88856f6781c62b4cb3c9c47b84eb07 Mon Sep 17 00:00:00 2001 From: Nithin <52503252+nithin42@users.noreply.github.com> Date: Mon, 17 Aug 2026 16:24:07 +0530 Subject: [PATCH 2/5] Pass access.dev through to Miniflare via `unstable_getMiniflareWorkerOptions()` (#15211) Co-authored-by: James Opstad <13586373+jamesopstad@users.noreply.github.com> --- .changeset/access-dev-vitest-pool.md | 6 +++ ...table-get-miniflare-worker-options.test.ts | 51 +++++++++++++++++++ .../src/api/integrations/platform/index.ts | 1 + 3 files changed, 58 insertions(+) create mode 100644 .changeset/access-dev-vitest-pool.md diff --git a/.changeset/access-dev-vitest-pool.md b/.changeset/access-dev-vitest-pool.md new file mode 100644 index 00000000000..a2b897207e1 --- /dev/null +++ b/.changeset/access-dev-vitest-pool.md @@ -0,0 +1,6 @@ +--- +"wrangler": patch +"@cloudflare/vitest-pool-workers": patch +--- + +Honor `access.dev` when running Workers with `@cloudflare/vitest-pool-workers`, so `ctx.access.getIdentity()` returns the configured identity just as it does with `wrangler dev`. diff --git a/packages/wrangler/src/__tests__/unstable-get-miniflare-worker-options.test.ts b/packages/wrangler/src/__tests__/unstable-get-miniflare-worker-options.test.ts index 7dbb4868de9..a12bcc71e0d 100644 --- a/packages/wrangler/src/__tests__/unstable-get-miniflare-worker-options.test.ts +++ b/packages/wrangler/src/__tests__/unstable-get-miniflare-worker-options.test.ts @@ -146,6 +146,57 @@ describe("unstable_getMiniflareWorkerOptions", () => { }); }); + describe("Cloudflare Access local dev simulation (`ctx.access`)", () => { + it("passes `access.dev` through to the Miniflare worker options", ({ + expect, + }) => { + writeWranglerConfig( + { + name: "test-worker", + main: "./index.js", + compatibility_date: "2024-10-04", + access: { + dev: { + aud: "my-app-aud-tag", + identity: { + email: "user@example.com", + name: "Test User", + }, + }, + }, + }, + "./wrangler.json" + ); + const { workerOptions } = + unstable_getMiniflareWorkerOptions("./wrangler.json"); + // Without this, `ctx.access` resolves to `undefined` under + // @cloudflare/vitest-pool-workers even though `wrangler dev` honours it. + expect(workerOptions.access).toEqual({ + aud: "my-app-aud-tag", + identity: { + email: "user@example.com", + name: "Test User", + }, + }); + }); + + it("leaves `access` undefined when no `access` config is present", ({ + expect, + }) => { + writeWranglerConfig( + { + name: "test-worker", + main: "./index.js", + compatibility_date: "2024-10-04", + }, + "./wrangler.json" + ); + const { workerOptions } = + unstable_getMiniflareWorkerOptions("./wrangler.json"); + expect(workerOptions.access).toBeUndefined(); + }); + }); + describe("typed services bindings with `dev.plugin`", () => { it("routes a typed service binding with `dev.plugin` to miniflare's unsafe-binding plugin pathway", ({ expect, diff --git a/packages/wrangler/src/api/integrations/platform/index.ts b/packages/wrangler/src/api/integrations/platform/index.ts index 5a2cf467e31..6830ae765e2 100644 --- a/packages/wrangler/src/api/integrations/platform/index.ts +++ b/packages/wrangler/src/api/integrations/platform/index.ts @@ -513,6 +513,7 @@ export function unstable_getMiniflareWorkerOptions( compatibilityFlags: config.compatibility_flags, modulesRules, zone: getZoneFromConfig(config), + access: config.access?.dev, ...bindingOptions, ...sitesOptions, From b6e26e98159b93ba2469626e93d8dd34f43c87a7 Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin Date: Mon, 17 Aug 2026 12:17:07 +0100 Subject: [PATCH 3/5] [fixtures] De-flake the dev-registry tests on Windows by making tail teardown safe (#15017) --- .../dev-registry/tests/dev-registry.test.ts | 273 ++++++++++++------ ...rangler.exported-handler-with-assets.jsonc | 5 +- .../wrangler.exported-handler.jsonc | 5 - .../wrangler.external-durable-object.jsonc | 5 - ...angler.worker-entrypoint-with-assets.jsonc | 5 - .../wrangler.worker-entrypoint.jsonc | 5 + .../shared/src/run-wrangler-long-lived.ts | 42 ++- 7 files changed, 216 insertions(+), 124 deletions(-) diff --git a/fixtures/dev-registry/tests/dev-registry.test.ts b/fixtures/dev-registry/tests/dev-registry.test.ts index c60c9e7ac41..bd12900743b 100644 --- a/fixtures/dev-registry/tests/dev-registry.test.ts +++ b/fixtures/dev-registry/tests/dev-registry.test.ts @@ -4,7 +4,7 @@ import * as path from "node:path"; import { resolve } from "node:path"; /* eslint-disable workers-sdk/no-vitest-import-expect -- uses expect in module-scope helper functions */ import { - describe as baseDescribe, + describe, expect, onTestFailed, onTestFinished, @@ -18,11 +18,6 @@ import { } from "../../../packages/vite-plugin-cloudflare/e2e/helpers"; import { runWranglerDev as baseRunWranglerDev } from "../../shared/src/run-wrangler-long-lived"; -// TODO: These tests are consistently failing on Windows in CI and are blocking -// other work. Skipping them there as a temporary measure until the underlying -// issue is fixed. There's still value in running them on macOS and Linux. -const describe = baseDescribe.skipIf(process.platform === "win32"); - const waitForTimeout = 20_000; const cwd = resolve(__dirname, ".."); const tmpPathBase = path.join(os.tmpdir(), "wrangler-tests"); @@ -32,8 +27,18 @@ const it = test.extend<{ // Fixture for creating a temporary directory async devRegistryPath({}, use) { const tmpPath = await fs.realpath(await fs.mkdtemp(tmpPathBase)); + + // Fixture teardown runs *before* `onTestFinished` callbacks, so removing + // the directory here would pull the registry out from under dev sessions + // that are still running. Registering the cleanup as an + // `onTestFinished` callback during fixture setup instead makes it the + // first one registered, and therefore the last one to run under Vitest's + // LIFO ordering — after every dev session has exited. + onTestFinished(async () => { + await fs.rm(tmpPath, { recursive: true, maxRetries: 10 }); + }); + await use(tmpPath); - await fs.rm(tmpPath, { recursive: true, maxRetries: 10 }); }, }); @@ -94,6 +99,27 @@ async function runWranglerDev( return url; } +/** + * Starts a tail consumer, then its producer, returning both URLs. + * + * Vitest runs `onTestFinished` callbacks in LIFO order, so the session started + * last is torn down first. Starting the producer last therefore guarantees it + * is killed while its consumer is still running. + * + * The reverse order is not safe: killing a dev session that another running + * session is forwarding tail events to aborts workerd on the surviving side on + * Windows, which restarts the dev server mid-teardown and times the test out. + * The `tail_consumers` in this fixture are one-directional for the same reason + * — with a cycle there is no order that keeps every producer shorter-lived than + * its consumer. + */ +async function startTailPair( + startConsumer: () => Promise, + startProducer: () => Promise +): Promise<[consumer: string, producer: string]> { + return [await startConsumer(), await startProducer()]; +} + async function setupPlatformProxy(config: string, devRegistryPath?: string) { vi.stubEnv("WRANGLER_REGISTRY_PATH", devRegistryPath); @@ -400,17 +426,25 @@ describe("Dev Registry: wrangler dev <-> wrangler dev", () => { }, waitForTimeout); }); - it("supports tail handler", async ({ devRegistryPath }) => { - const exportedHandlerWithAssets = await runWranglerDev( - "wrangler.exported-handler-with-assets.jsonc", - devRegistryPath - ); - const workerEntrypoint = await runWranglerDev( - [ - "wrangler.worker-entrypoint.jsonc", - "wrangler.internal-durable-object.jsonc", - ], - devRegistryPath + it("supports tail handler when the consumer has assets", async ({ + devRegistryPath, + }) => { + // The producer runs alongside a second worker so that its logs are + // prefixed with the worker name, exercising multi-worker sessions too + const [exportedHandlerWithAssets, workerEntrypoint] = await startTailPair( + () => + runWranglerDev( + "wrangler.exported-handler-with-assets.jsonc", + devRegistryPath + ), + () => + runWranglerDev( + [ + "wrangler.worker-entrypoint.jsonc", + "wrangler.internal-durable-object.jsonc", + ], + devRegistryPath + ) ); const searchParams = new URLSearchParams({ @@ -418,29 +452,7 @@ describe("Dev Registry: wrangler dev <-> wrangler dev", () => { }); await vi.waitFor(async () => { - // Trigger tail handler of worker-entrypoint via exported handler - await fetch(`${exportedHandlerWithAssets}?${searchParams}`, { - method: "POST", - body: JSON.stringify(["hello world", "this is the 2nd log"]), - }); - await fetch(`${exportedHandlerWithAssets}?${searchParams}`, { - method: "POST", - body: JSON.stringify(["some other log"]), - }); - - const response = await fetch(`${workerEntrypoint}?${searchParams}`); - - expect(await response.json()).toEqual({ - worker: "Worker Entrypoint", - tailEvents: expect.arrayContaining([ - [["[exported-handler]"], ["hello world", "this is the 2nd log"]], - [["[exported-handler]"], ["some other log"]], - ]), - }); - }, waitForTimeout); - - await vi.waitFor(async () => { - // Trigger tail handler of exported-handler via worker-entrypoint + // Trigger tail handler of exported-handler-with-assets via worker-entrypoint await fetch(`${workerEntrypoint}?${searchParams}`, { method: "POST", body: JSON.stringify(["hello from test"]), @@ -469,6 +481,45 @@ describe("Dev Registry: wrangler dev <-> wrangler dev", () => { }, waitForTimeout); }); + it("supports tail handler when the producer has assets", async ({ + devRegistryPath, + }) => { + const [exportedHandler, exportedHandlerWithAssets] = await startTailPair( + () => runWranglerDev("wrangler.exported-handler.jsonc", devRegistryPath), + () => + runWranglerDev( + "wrangler.exported-handler-with-assets.jsonc", + devRegistryPath + ) + ); + + const searchParams = new URLSearchParams({ + "test-method": "tail", + }); + + await vi.waitFor(async () => { + // Trigger tail handler of exported-handler via exported-handler-with-assets + await fetch(`${exportedHandlerWithAssets}?${searchParams}`, { + method: "POST", + body: JSON.stringify(["hello world", "this is the 2nd log"]), + }); + await fetch(`${exportedHandlerWithAssets}?${searchParams}`, { + method: "POST", + body: JSON.stringify(["some other log"]), + }); + + const response = await fetch(`${exportedHandler}?${searchParams}`); + + expect(await response.json()).toEqual({ + worker: "exported-handler", + tailEvents: expect.arrayContaining([ + [["[exported-handler]"], ["hello world", "this is the 2nd log"]], + [["[exported-handler]"], ["some other log"]], + ]), + }); + }, waitForTimeout); + }); + it("supports queues across dev sessions", async ({ devRegistryPath }) => { const exportedHandler = await runWranglerDev( "wrangler.exported-handler.jsonc", @@ -715,14 +766,16 @@ describe("Dev Registry: vite dev <-> vite dev", () => { }, waitForTimeout); }); - it("supports tail handler", async ({ devRegistryPath }) => { - const exportedHandler = await runViteDev( - "vite.exported-handler.config.ts", - devRegistryPath - ); - const workerEntrypointWithAssets = await runViteDev( - "vite.worker-entrypoint-with-assets.config.ts", - devRegistryPath + it("supports tail handler when the consumer has assets", async ({ + devRegistryPath, + }) => { + const [exportedHandlerWithAssets, workerEntrypoint] = await startTailPair( + () => + runViteDev( + "vite.exported-handler-with-assets.config.ts", + devRegistryPath + ), + () => runViteDev("vite.worker-entrypoint.config.ts", devRegistryPath) ); const searchParams = new URLSearchParams({ @@ -730,38 +783,55 @@ describe("Dev Registry: vite dev <-> vite dev", () => { }); await vi.waitFor(async () => { - // Trigger tail handler of worker-entrypoint via exported-handler - await fetch(`${exportedHandler}?${searchParams}`, { + // Trigger tail handler of exported-handler-with-assets via worker-entrypoint + await fetch(`${workerEntrypoint}?${searchParams}`, { method: "POST", - body: JSON.stringify(["hello world", "this is the 2nd log"]), + body: JSON.stringify(["hello from test"]), }); - await fetch(`${exportedHandler}?${searchParams}`, { + await fetch(`${workerEntrypoint}?${searchParams}`, { method: "POST", - body: JSON.stringify(["some other log"]), + body: JSON.stringify(["yet another log", "and another one"]), }); const response = await fetch( - `${workerEntrypointWithAssets}?${searchParams}` + `${exportedHandlerWithAssets}?${searchParams}` ); expect(await response.json()).toEqual({ - worker: "Worker Entrypoint", + worker: "exported-handler", tailEvents: expect.arrayContaining([ - [["[exported-handler]"], ["hello world", "this is the 2nd log"]], - [["[exported-handler]"], ["some other log"]], + [["[Worker Entrypoint]"], ["hello from test"]], + [["[Worker Entrypoint]"], ["yet another log", "and another one"]], ]), }); }, waitForTimeout); + }); + + it("supports tail handler when the producer has assets", async ({ + devRegistryPath, + }) => { + const [exportedHandler, exportedHandlerWithAssets] = await startTailPair( + () => runViteDev("vite.exported-handler.config.ts", devRegistryPath), + () => + runViteDev( + "vite.exported-handler-with-assets.config.ts", + devRegistryPath + ) + ); + + const searchParams = new URLSearchParams({ + "test-method": "tail", + }); await vi.waitFor(async () => { - // Trigger tail handler of exported-handler via worker-entrypoint - await fetch(`${workerEntrypointWithAssets}?${searchParams}`, { + // Trigger tail handler of exported-handler via exported-handler-with-assets + await fetch(`${exportedHandlerWithAssets}?${searchParams}`, { method: "POST", - body: JSON.stringify(["hello from test"]), + body: JSON.stringify(["hello world", "this is the 2nd log"]), }); - await fetch(`${workerEntrypointWithAssets}?${searchParams}`, { + await fetch(`${exportedHandlerWithAssets}?${searchParams}`, { method: "POST", - body: JSON.stringify(["yet another log", "and another one"]), + body: JSON.stringify(["some other log"]), }); const response = await fetch(`${exportedHandler}?${searchParams}`); @@ -769,8 +839,8 @@ describe("Dev Registry: vite dev <-> vite dev", () => { expect(await response.json()).toEqual({ worker: "exported-handler", tailEvents: expect.arrayContaining([ - [["[Worker Entrypoint]"], ["hello from test"]], - [["[Worker Entrypoint]"], ["yet another log", "and another one"]], + [["[exported-handler]"], ["hello world", "this is the 2nd log"]], + [["[exported-handler]"], ["some other log"]], ]), }); }, waitForTimeout); @@ -977,14 +1047,16 @@ describe("Dev Registry: vite dev <-> wrangler dev", () => { }, waitForTimeout); }); - it("supports tail handler", async ({ devRegistryPath }) => { - const exportedHandlerWithStaticAssets = await runViteDev( - "vite.exported-handler-with-assets.config.ts", - devRegistryPath - ); - const workerEntrypoint = await runWranglerDev( - "wrangler.worker-entrypoint.jsonc", - devRegistryPath + it("supports tail handler from wrangler dev to vite dev", async ({ + devRegistryPath, + }) => { + const [exportedHandlerWithAssets, workerEntrypoint] = await startTailPair( + () => + runViteDev( + "vite.exported-handler-with-assets.config.ts", + devRegistryPath + ), + () => runWranglerDev("wrangler.worker-entrypoint.jsonc", devRegistryPath) ); const searchParams = new URLSearchParams({ @@ -992,47 +1064,64 @@ describe("Dev Registry: vite dev <-> wrangler dev", () => { }); await vi.waitFor(async () => { - // Trigger tail handler of worker-entrypoint via exported-handler - await fetch(`${exportedHandlerWithStaticAssets}?${searchParams}`, { + // Trigger tail handler of exported-handler-with-assets via worker-entrypoint + await fetch(`${workerEntrypoint}?${searchParams}`, { method: "POST", - body: JSON.stringify(["hello world", "this is the 2nd log"]), + body: JSON.stringify(["hello from test"]), }); - await fetch(`${exportedHandlerWithStaticAssets}?${searchParams}`, { + await fetch(`${workerEntrypoint}?${searchParams}`, { method: "POST", - body: JSON.stringify(["some other log"]), + body: JSON.stringify(["yet another log", "and another one"]), }); - const response = await fetch(`${workerEntrypoint}?${searchParams}`); + const response = await fetch( + `${exportedHandlerWithAssets}?${searchParams}` + ); expect(await response.json()).toEqual({ - worker: "Worker Entrypoint", + worker: "exported-handler", tailEvents: expect.arrayContaining([ - [["[exported-handler]"], ["hello world", "this is the 2nd log"]], - [["[exported-handler]"], ["some other log"]], + [["[Worker Entrypoint]"], ["hello from test"]], + [["[Worker Entrypoint]"], ["yet another log", "and another one"]], ]), }); }, waitForTimeout); + }); + + it("supports tail handler from vite dev to wrangler dev", async ({ + devRegistryPath, + }) => { + const [exportedHandler, exportedHandlerWithAssets] = await startTailPair( + () => runWranglerDev("wrangler.exported-handler.jsonc", devRegistryPath), + () => + runViteDev( + "vite.exported-handler-with-assets.config.ts", + devRegistryPath + ) + ); + + const searchParams = new URLSearchParams({ + "test-method": "tail", + }); await vi.waitFor(async () => { - // Trigger tail handler of exported-handler via worker-entrypoint - await fetch(`${workerEntrypoint}?${searchParams}`, { + // Trigger tail handler of exported-handler via exported-handler-with-assets + await fetch(`${exportedHandlerWithAssets}?${searchParams}`, { method: "POST", - body: JSON.stringify(["hello from test"]), + body: JSON.stringify(["hello world", "this is the 2nd log"]), }); - await fetch(`${workerEntrypoint}?${searchParams}`, { + await fetch(`${exportedHandlerWithAssets}?${searchParams}`, { method: "POST", - body: JSON.stringify(["yet another log", "and another one"]), + body: JSON.stringify(["some other log"]), }); - const response = await fetch( - `${exportedHandlerWithStaticAssets}?${searchParams}` - ); + const response = await fetch(`${exportedHandler}?${searchParams}`); expect(await response.json()).toEqual({ worker: "exported-handler", tailEvents: expect.arrayContaining([ - [["[Worker Entrypoint]"], ["hello from test"]], - [["[Worker Entrypoint]"], ["yet another log", "and another one"]], + [["[exported-handler]"], ["hello world", "this is the 2nd log"]], + [["[exported-handler]"], ["some other log"]], ]), }); }, waitForTimeout); diff --git a/fixtures/dev-registry/wrangler.exported-handler-with-assets.jsonc b/fixtures/dev-registry/wrangler.exported-handler-with-assets.jsonc index 322ca0243e2..d41abdc6e15 100644 --- a/fixtures/dev-registry/wrangler.exported-handler-with-assets.jsonc +++ b/fixtures/dev-registry/wrangler.exported-handler-with-assets.jsonc @@ -34,9 +34,12 @@ "entrypoint": "NamedEntrypoint", }, ], + // Middle link of the one-directional tail chain described in + // wrangler.worker-entrypoint.jsonc. Pointing this back at worker-entrypoint + // would close the cycle. "tail_consumers": [ { - "service": "worker-entrypoint", + "service": "exported-handler", }, ], } diff --git a/fixtures/dev-registry/wrangler.exported-handler.jsonc b/fixtures/dev-registry/wrangler.exported-handler.jsonc index f8af4671b3e..1cf153dfbe1 100644 --- a/fixtures/dev-registry/wrangler.exported-handler.jsonc +++ b/fixtures/dev-registry/wrangler.exported-handler.jsonc @@ -27,11 +27,6 @@ "entrypoint": "NamedEntrypoint", }, ], - "tail_consumers": [ - { - "service": "worker-entrypoint-with-assets", - }, - ], "queues": { "producers": [ { diff --git a/fixtures/dev-registry/wrangler.external-durable-object.jsonc b/fixtures/dev-registry/wrangler.external-durable-object.jsonc index c74e28cbb7a..43dd46d96c4 100644 --- a/fixtures/dev-registry/wrangler.external-durable-object.jsonc +++ b/fixtures/dev-registry/wrangler.external-durable-object.jsonc @@ -12,9 +12,4 @@ }, ], }, - "tail_consumers": [ - { - "service": "exported-handler", - }, - ], } diff --git a/fixtures/dev-registry/wrangler.worker-entrypoint-with-assets.jsonc b/fixtures/dev-registry/wrangler.worker-entrypoint-with-assets.jsonc index 77b873a3924..d51c286fd06 100644 --- a/fixtures/dev-registry/wrangler.worker-entrypoint-with-assets.jsonc +++ b/fixtures/dev-registry/wrangler.worker-entrypoint-with-assets.jsonc @@ -29,9 +29,4 @@ "entrypoint": "NamedEntrypoint", }, ], - "tail_consumers": [ - { - "service": "exported-handler", - }, - ], } diff --git a/fixtures/dev-registry/wrangler.worker-entrypoint.jsonc b/fixtures/dev-registry/wrangler.worker-entrypoint.jsonc index 61ddb2eeb05..1a94c73f2ef 100644 --- a/fixtures/dev-registry/wrangler.worker-entrypoint.jsonc +++ b/fixtures/dev-registry/wrangler.worker-entrypoint.jsonc @@ -26,6 +26,11 @@ "entrypoint": "NamedEntrypoint", }, ], + // Tail relationships across these configs form a one-directional chain: + // worker-entrypoint -> exported-handler-with-assets -> exported-handler. + // Keep it acyclic and confined to the tail tests. A dev session that + // outlives a tail consumer it has already connected to aborts workerd on + // Windows, and a cycle makes a safe shutdown order impossible to pick. "tail_consumers": [ { "service": "exported-handler-with-assets", diff --git a/fixtures/shared/src/run-wrangler-long-lived.ts b/fixtures/shared/src/run-wrangler-long-lived.ts index 8e4c8e190b6..cf342ae4d9f 100644 --- a/fixtures/shared/src/run-wrangler-long-lived.ts +++ b/fixtures/shared/src/run-wrangler-long-lived.ts @@ -189,23 +189,17 @@ async function runLongLivedWrangler( async function stop() { stopping = true; - return new Promise((resolve) => { - if (processExited) { - // Already dead — nothing to kill. Avoid noisy Windows taskkill errors. - resolve(); - return; - } - assert( - wranglerProcess.pid, - `Command "${command.join(" ")}" had no process id` - ); - treeKill(wranglerProcess.pid, (e) => { + if (processExited) { + // Already dead — nothing to kill. Avoid noisy Windows taskkill errors. + return; + } + const pid = wranglerProcess.pid; + assert(pid, `Command "${command.join(" ")}" had no process id`); + + await new Promise((resolve) => { + treeKill(pid, (e) => { if (e) { - console.error( - "Failed to kill command: " + command.join(" "), - wranglerProcess.pid, - e - ); + console.error("Failed to kill command: " + command.join(" "), pid, e); } // fallthrough to resolve() because either the process is already dead // or don't have permission to kill it or some other reason? @@ -213,6 +207,22 @@ async function runLongLivedWrangler( resolve(); }); }); + + // The kill callback only tells us the signal was delivered (on Windows it + // is the exit of `taskkill`), not that the process is gone. Tests that + // stop several sessions in sequence rely on each one being fully dead + // before the next is stopped, so wait for the actual exit — with a bound, + // since failing to reap a child should not fail the test. + if (processExited) { + return; + } + await new Promise((resolve) => { + const timeoutHandle = setTimeout(resolve, 10_000); + wranglerProcess.once("exit", () => { + clearTimeout(timeoutHandle); + resolve(); + }); + }); } const { ip, port } = await ready; From 3a4fc6b2fce883248dac4734699d8df89dc7662a Mon Sep 17 00:00:00 2001 From: James Opstad <13586373+jamesopstad@users.noreply.github.com> Date: Mon, 17 Aug 2026 12:56:08 +0100 Subject: [PATCH 4/5] Pass access configuration to Router Worker (#15238) --- .changeset/access-dev-vite-plugin.md | 5 +++++ .../worker-\342\231\253/__tests__/worker.spec.ts" | 12 ++++++++++++ .../playground/worker-\342\231\253/src/index.ts" | 8 +++++++- .../playground/worker-\342\231\253/wrangler.jsonc" | 9 +++++++++ .../vite-plugin-cloudflare/src/miniflare-options.ts | 1 + 5 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 .changeset/access-dev-vite-plugin.md diff --git a/.changeset/access-dev-vite-plugin.md b/.changeset/access-dev-vite-plugin.md new file mode 100644 index 00000000000..812b295b651 --- /dev/null +++ b/.changeset/access-dev-vite-plugin.md @@ -0,0 +1,5 @@ +--- +"@cloudflare/vite-plugin": patch +--- + +Honor `access.dev` when running Workers with `@cloudflare/vite-plugin`, so `ctx.access.getIdentity()` returns the configured identity. diff --git "a/packages/vite-plugin-cloudflare/playground/worker-\342\231\253/__tests__/worker.spec.ts" "b/packages/vite-plugin-cloudflare/playground/worker-\342\231\253/__tests__/worker.spec.ts" index 3c665d43708..29f6d8e9efa 100644 --- "a/packages/vite-plugin-cloudflare/playground/worker-\342\231\253/__tests__/worker.spec.ts" +++ "b/packages/vite-plugin-cloudflare/playground/worker-\342\231\253/__tests__/worker.spec.ts" @@ -17,6 +17,18 @@ test("basic hello-world functionality", async ({ expect }) => { ); }); +test("provides the configured Access identity", async ({ expect }) => { + expect(await getTextResponse("/access")).toBe( + JSON.stringify({ + aud: "vite-plugin-test-audience", + identity: { + email: "vite-plugin@example.com", + name: "Vite Plugin Test User", + }, + }) + ); +}); + test("the project path can contain a non-ascii character", async ({ expect, }) => { diff --git "a/packages/vite-plugin-cloudflare/playground/worker-\342\231\253/src/index.ts" "b/packages/vite-plugin-cloudflare/playground/worker-\342\231\253/src/index.ts" index 41173df68b2..a776810a215 100644 --- "a/packages/vite-plugin-cloudflare/playground/worker-\342\231\253/src/index.ts" +++ "b/packages/vite-plugin-cloudflare/playground/worker-\342\231\253/src/index.ts" @@ -1,8 +1,14 @@ import { a } from "./a"; export default { - async fetch(request) { + async fetch(request, _env, ctx) { const url = new URL(request.url); + if (url.pathname === "/access") { + return Response.json({ + aud: ctx.access?.aud, + identity: await ctx.access?.getIdentity(), + }); + } if ( url.pathname === diff --git "a/packages/vite-plugin-cloudflare/playground/worker-\342\231\253/wrangler.jsonc" "b/packages/vite-plugin-cloudflare/playground/worker-\342\231\253/wrangler.jsonc" index f7cbbd43293..4153878c249 100644 --- "a/packages/vite-plugin-cloudflare/playground/worker-\342\231\253/wrangler.jsonc" +++ "b/packages/vite-plugin-cloudflare/playground/worker-\342\231\253/wrangler.jsonc" @@ -2,6 +2,15 @@ "name": "worker", "main": "./src/index.ts", // compatibility date omitted to test fallback + "access": { + "dev": { + "aud": "vite-plugin-test-audience", + "identity": { + "email": "vite-plugin@example.com", + "name": "Vite Plugin Test User", + }, + }, + }, "services": [ { "binding": "TEST_IF_VITE_CRASH_WITH_UNKNOWN_NAMED_ENTRYPOINT", diff --git a/packages/vite-plugin-cloudflare/src/miniflare-options.ts b/packages/vite-plugin-cloudflare/src/miniflare-options.ts index 1ad8fd2e198..956c8a08c15 100644 --- a/packages/vite-plugin-cloudflare/src/miniflare-options.ts +++ b/packages/vite-plugin-cloudflare/src/miniflare-options.ts @@ -159,6 +159,7 @@ export async function getDevMiniflareOptions( const assetWorkers: Array = [ { name: ROUTER_WORKER_NAME, + access: entryWorkerConfig?.access?.dev, unsafeRegisterWorker: false, compatibilityDate: INTERNAL_WORKERS_COMPATIBILITY_DATE, compatibilityFlags: ["enable_ctx_exports"], From 1552bce66c0fbe0271cf51a33f19373894e8bcad Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin Date: Mon, 17 Aug 2026 13:11:40 +0100 Subject: [PATCH 5/5] [wrangler] Quieten warnings and stray output in tests (#15209) --- .../test/durable-objects.test.ts | 3 +-- .../test/integration-self.test.ts | 8 ++++++-- .../d1/vitest.config.ts | 2 +- .../vitest.config.ts | 2 +- packages/miniflare/vitest.config.mts | 10 +++++----- .../e2e/vitest.config.ts | 2 +- .../playground/assets/vite.config.ts | 2 +- .../vite.config.nodejs-compat.ts | 2 +- .../module-resolution/vite.config.ts | 2 +- .../static-mpa/vite.config.cf-build-output.ts | 10 +++++----- .../playground/static-mpa/vite.config.ts | 10 +++++----- ...vite.config.with-worker-configs-warning.ts | 10 +++++----- packages/workers-auth/vitest.config.mts | 4 ++-- packages/workers-editor-shared/vite.config.ts | 2 +- packages/workers-utils/vitest.config.mts | 2 +- packages/wrangler/e2e/vitest.config.mts | 2 +- .../wrangler/src/__tests__/ai.local.test.ts | 19 +++++++++++-------- .../versions/versions.upload.test.ts | 12 ++++++++---- packages/wrangler/vitest.config.mts | 16 +++++++++++----- 19 files changed, 68 insertions(+), 52 deletions(-) diff --git a/fixtures/vitest-pool-workers-examples/context-exports/test/durable-objects.test.ts b/fixtures/vitest-pool-workers-examples/context-exports/test/durable-objects.test.ts index 504129057c3..25e3c56445e 100644 --- a/fixtures/vitest-pool-workers-examples/context-exports/test/durable-objects.test.ts +++ b/fixtures/vitest-pool-workers-examples/context-exports/test/durable-objects.test.ts @@ -1,6 +1,6 @@ import { runInDurableObject } from "cloudflare:test"; import { exports } from "cloudflare:workers"; -import { it, vi } from "vitest"; +import { it } from "vitest"; it("can access imported context exports for Durable Objects", async ({ expect, @@ -30,7 +30,6 @@ it("will can access Durable Object context exports that could not be guessed on // In this test, we are trying to access a durable-object that is wildcard (*) re-exported from a virtual module. // This virtual module is understood by Vitest and TypeScript but not the lightweight esbuild that we use to guess exports. // But since Durable Objects require explicit "migration" configuration in wrangler, we can still make this work. - const warnSpy = vi.spyOn(console, "warn"); const response = await exports.default.fetch( "http://example.com/virtual-durable-object" ); diff --git a/fixtures/vitest-pool-workers-examples/context-exports/test/integration-self.test.ts b/fixtures/vitest-pool-workers-examples/context-exports/test/integration-self.test.ts index e92516a5460..15b32f6cb92 100644 --- a/fixtures/vitest-pool-workers-examples/context-exports/test/integration-self.test.ts +++ b/fixtures/vitest-pool-workers-examples/context-exports/test/integration-self.test.ts @@ -20,7 +20,9 @@ it("can use context exports (parameterized with props) on the main worker", asyn it("will warn on missing context exports on the main worker", async ({ expect, }) => { - const warnSpy = vi.spyOn(console, "warn"); + // `mockImplementation` so the warning this test asserts on doesn't also get + // printed to the real console and pollute the test output. + const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {}); const response = await exports.default.fetch( "http://example.com/invalid-export" ); @@ -37,7 +39,9 @@ it("will warn on implicit re-exports that will exist in production but cannot no }) => { // In this test, we are trying to access an entry-point that is wildcard (*) re-exported from a virtual module. // This virtual module is understood by Vitest and TypeScript but not the lightweight esbuild that we use to guess exports. - const warnSpy = vi.spyOn(console, "warn"); + // `mockImplementation` so the warning this test asserts on doesn't also get + // printed to the real console and pollute the test output. + const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {}); const response = await exports.default.fetch( "http://example.com/virtual-implicit" ); diff --git a/fixtures/vitest-pool-workers-examples/d1/vitest.config.ts b/fixtures/vitest-pool-workers-examples/d1/vitest.config.ts index 0d05cabc08a..fb6e66b73e4 100644 --- a/fixtures/vitest-pool-workers-examples/d1/vitest.config.ts +++ b/fixtures/vitest-pool-workers-examples/d1/vitest.config.ts @@ -8,7 +8,7 @@ import configShared from "../../../vitest.shared"; export default defineConfig(async () => { // Read all migrations in the `migrations` directory - const migrationsPath = path.join(__dirname, "migrations"); + const migrationsPath = path.join(import.meta.dirname, "migrations"); const migrations = await readD1Migrations(migrationsPath); return mergeConfig( diff --git a/fixtures/vitest-pool-workers-examples/pages-functions-unit-integration-self/vitest.config.ts b/fixtures/vitest-pool-workers-examples/pages-functions-unit-integration-self/vitest.config.ts index 89818cea6d3..854b278fec3 100644 --- a/fixtures/vitest-pool-workers-examples/pages-functions-unit-integration-self/vitest.config.ts +++ b/fixtures/vitest-pool-workers-examples/pages-functions-unit-integration-self/vitest.config.ts @@ -6,7 +6,7 @@ import { import { defineProject, mergeConfig } from "vitest/config"; import configShared from "../../../vitest.shared"; -const assetsPath = path.join(__dirname, "public"); +const assetsPath = path.join(import.meta.dirname, "public"); export default mergeConfig( configShared, diff --git a/packages/miniflare/vitest.config.mts b/packages/miniflare/vitest.config.mts index 15b10f6ec56..02bfbdc9e9c 100644 --- a/packages/miniflare/vitest.config.mts +++ b/packages/miniflare/vitest.config.mts @@ -9,7 +9,7 @@ export default defineConfig({ pool: "forks", maxWorkers: 1, include: ["test/**/*.spec.ts"], - setupFiles: [path.resolve(__dirname, "test/setup.mjs")], + setupFiles: [path.resolve(import.meta.dirname, "test/setup.mjs")], globals: true, env: { MINIFLARE_ASSERT_BODIES_CONSUMED: "true", @@ -17,22 +17,22 @@ export default defineConfig({ }, resolve: { alias: { - miniflare: path.resolve(__dirname, "dist/src/index.js"), + miniflare: path.resolve(import.meta.dirname, "dist/src/index.js"), // Exposes the worker-side raw-TCP relay helper to focused unit tests // without importing it by a real path (which would drag worker-typed // source into the node-side tsconfig, whose `exclude` covers // `src/workers/**`). The spec imports this id with an `@ts-expect-error` // since tsc has no matching path mapping. "@relay-under-test": path.resolve( - __dirname, + import.meta.dirname, "src/workers/shared/remote-bindings-utils.ts" ), "miniflare:shared": path.resolve( - __dirname, + import.meta.dirname, "src/workers/shared/index.ts" ), "miniflare:zod": path.resolve( - __dirname, + import.meta.dirname, "src/workers/shared/zod.worker.ts" ), }, diff --git a/packages/vite-plugin-cloudflare/e2e/vitest.config.ts b/packages/vite-plugin-cloudflare/e2e/vitest.config.ts index 628c19df2af..f136f079b6e 100644 --- a/packages/vite-plugin-cloudflare/e2e/vitest.config.ts +++ b/packages/vite-plugin-cloudflare/e2e/vitest.config.ts @@ -5,7 +5,7 @@ export default defineConfig({ reporters: ["default"], include: ["**/*.test.ts"], cache: false, - root: __dirname, + root: import.meta.dirname, testTimeout: 1000 * 60 * 10, // 10 min for lengthy installs fileParallelism: false, globalSetup: ["global-setup.ts"], diff --git a/packages/vite-plugin-cloudflare/playground/assets/vite.config.ts b/packages/vite-plugin-cloudflare/playground/assets/vite.config.ts index 0220eec15f2..ef58b4d53d5 100644 --- a/packages/vite-plugin-cloudflare/playground/assets/vite.config.ts +++ b/packages/vite-plugin-cloudflare/playground/assets/vite.config.ts @@ -7,7 +7,7 @@ export default defineConfig({ client: { build: { rollupOptions: { - input: path.resolve(__dirname, "html-page.html"), + input: path.resolve(import.meta.dirname, "html-page.html"), }, }, }, diff --git a/packages/vite-plugin-cloudflare/playground/module-resolution/vite.config.nodejs-compat.ts b/packages/vite-plugin-cloudflare/playground/module-resolution/vite.config.nodejs-compat.ts index e61f9104389..31f0765d90e 100644 --- a/packages/vite-plugin-cloudflare/playground/module-resolution/vite.config.nodejs-compat.ts +++ b/packages/vite-plugin-cloudflare/playground/module-resolution/vite.config.nodejs-compat.ts @@ -7,7 +7,7 @@ import { defineConfig } from "vite"; export default defineConfig({ resolve: { alias: { - "@alias/test": resolve(__dirname, "./src/aliasing.ts"), + "@alias/test": resolve(import.meta.dirname, "./src/aliasing.ts"), }, }, environments: { diff --git a/packages/vite-plugin-cloudflare/playground/module-resolution/vite.config.ts b/packages/vite-plugin-cloudflare/playground/module-resolution/vite.config.ts index e61f9104389..31f0765d90e 100644 --- a/packages/vite-plugin-cloudflare/playground/module-resolution/vite.config.ts +++ b/packages/vite-plugin-cloudflare/playground/module-resolution/vite.config.ts @@ -7,7 +7,7 @@ import { defineConfig } from "vite"; export default defineConfig({ resolve: { alias: { - "@alias/test": resolve(__dirname, "./src/aliasing.ts"), + "@alias/test": resolve(import.meta.dirname, "./src/aliasing.ts"), }, }, environments: { diff --git a/packages/vite-plugin-cloudflare/playground/static-mpa/vite.config.cf-build-output.ts b/packages/vite-plugin-cloudflare/playground/static-mpa/vite.config.cf-build-output.ts index 8a7b041a628..2e4e3a9099c 100644 --- a/packages/vite-plugin-cloudflare/playground/static-mpa/vite.config.cf-build-output.ts +++ b/packages/vite-plugin-cloudflare/playground/static-mpa/vite.config.cf-build-output.ts @@ -8,11 +8,11 @@ export default defineConfig({ build: { rollupOptions: { input: { - main: path.resolve(__dirname, "index.html"), - contact: path.resolve(__dirname, "contact.html"), - "404": path.resolve(__dirname, "404.html"), - about: path.resolve(__dirname, "about/index.html"), - "about-404": path.resolve(__dirname, "about/404.html"), + main: path.resolve(import.meta.dirname, "index.html"), + contact: path.resolve(import.meta.dirname, "contact.html"), + "404": path.resolve(import.meta.dirname, "404.html"), + about: path.resolve(import.meta.dirname, "about/index.html"), + "about-404": path.resolve(import.meta.dirname, "about/404.html"), }, }, }, diff --git a/packages/vite-plugin-cloudflare/playground/static-mpa/vite.config.ts b/packages/vite-plugin-cloudflare/playground/static-mpa/vite.config.ts index cfb132ea3e8..ffe3e948a66 100644 --- a/packages/vite-plugin-cloudflare/playground/static-mpa/vite.config.ts +++ b/packages/vite-plugin-cloudflare/playground/static-mpa/vite.config.ts @@ -8,11 +8,11 @@ export default defineConfig({ build: { rollupOptions: { input: { - main: path.resolve(__dirname, "index.html"), - contact: path.resolve(__dirname, "contact.html"), - "404": path.resolve(__dirname, "404.html"), - about: path.resolve(__dirname, "about/index.html"), - "about-404": path.resolve(__dirname, "about/404.html"), + main: path.resolve(import.meta.dirname, "index.html"), + contact: path.resolve(import.meta.dirname, "contact.html"), + "404": path.resolve(import.meta.dirname, "404.html"), + about: path.resolve(import.meta.dirname, "about/index.html"), + "about-404": path.resolve(import.meta.dirname, "about/404.html"), }, }, }, diff --git a/packages/vite-plugin-cloudflare/playground/static-mpa/vite.config.with-worker-configs-warning.ts b/packages/vite-plugin-cloudflare/playground/static-mpa/vite.config.with-worker-configs-warning.ts index 5302a7ebe73..b7999abd0a0 100644 --- a/packages/vite-plugin-cloudflare/playground/static-mpa/vite.config.with-worker-configs-warning.ts +++ b/packages/vite-plugin-cloudflare/playground/static-mpa/vite.config.with-worker-configs-warning.ts @@ -8,11 +8,11 @@ export default defineConfig({ build: { rollupOptions: { input: { - main: path.resolve(__dirname, "index.html"), - contact: path.resolve(__dirname, "contact.html"), - "404": path.resolve(__dirname, "404.html"), - about: path.resolve(__dirname, "about/index.html"), - "about-404": path.resolve(__dirname, "about/404.html"), + main: path.resolve(import.meta.dirname, "index.html"), + contact: path.resolve(import.meta.dirname, "contact.html"), + "404": path.resolve(import.meta.dirname, "404.html"), + about: path.resolve(import.meta.dirname, "about/index.html"), + "about-404": path.resolve(import.meta.dirname, "about/404.html"), }, }, }, diff --git a/packages/workers-auth/vitest.config.mts b/packages/workers-auth/vitest.config.mts index c742459c927..be177563d30 100644 --- a/packages/workers-auth/vitest.config.mts +++ b/packages/workers-auth/vitest.config.mts @@ -6,8 +6,8 @@ export default defineConfig({ testTimeout: 15_000, pool: "forks", include: ["**/tests/**/*.test.ts"], - globalSetup: path.resolve(__dirname, "tests/vitest.global.ts"), - setupFiles: [path.resolve(__dirname, "tests/vitest.setup.ts")], + globalSetup: path.resolve(import.meta.dirname, "tests/vitest.global.ts"), + setupFiles: [path.resolve(import.meta.dirname, "tests/vitest.setup.ts")], reporters: ["default"], unstubEnvs: true, mockReset: true, diff --git a/packages/workers-editor-shared/vite.config.ts b/packages/workers-editor-shared/vite.config.ts index d78b16a4c06..748d57849ef 100644 --- a/packages/workers-editor-shared/vite.config.ts +++ b/packages/workers-editor-shared/vite.config.ts @@ -28,7 +28,7 @@ export default defineConfig({ build: { chunkSizeWarningLimit: 1000, lib: { - entry: resolve(__dirname, "lib/index.ts"), + entry: resolve(import.meta.dirname, "lib/index.ts"), formats: ["es"], fileName: "index", }, diff --git a/packages/workers-utils/vitest.config.mts b/packages/workers-utils/vitest.config.mts index 29e70e6238d..83488529a2d 100644 --- a/packages/workers-utils/vitest.config.mts +++ b/packages/workers-utils/vitest.config.mts @@ -6,7 +6,7 @@ export default defineConfig({ testTimeout: 15_000, pool: "forks", include: ["**/tests/**/*.test.ts"], - globalSetup: path.resolve(__dirname, "tests/vitest.global.ts"), + globalSetup: path.resolve(import.meta.dirname, "tests/vitest.global.ts"), reporters: ["default"], unstubEnvs: true, mockReset: true, diff --git a/packages/wrangler/e2e/vitest.config.mts b/packages/wrangler/e2e/vitest.config.mts index 78558e4ddc7..3382a7634a8 100644 --- a/packages/wrangler/e2e/vitest.config.mts +++ b/packages/wrangler/e2e/vitest.config.mts @@ -9,7 +9,7 @@ export default defineConfig({ isolate: false, include: [process.env.WRANGLER_E2E_TEST_FILE || "e2e/**/*.test.ts"], outputFile: process.env.TEST_REPORT_PATH ?? ".e2e-test-report/index.html", - globalSetup: path.resolve(__dirname, "./validate-environment.ts"), + globalSetup: path.resolve(import.meta.dirname, "./validate-environment.ts"), reporters: ["verbose", "html"], bail: 1, chaiConfig: { diff --git a/packages/wrangler/src/__tests__/ai.local.test.ts b/packages/wrangler/src/__tests__/ai.local.test.ts index c5088c9cdd0..1231076afa8 100644 --- a/packages/wrangler/src/__tests__/ai.local.test.ts +++ b/packages/wrangler/src/__tests__/ai.local.test.ts @@ -4,13 +4,15 @@ import { Headers, Response } from "undici"; import { afterEach, describe, it, vi } from "vitest"; import { getAIFetcher } from "../ai/fetcher"; import * as internal from "../cfetch/internal"; -import { logger } from "../logger"; import * as user from "../user"; +import { mockConsoleMethods } from "./helpers/mock-console"; const AIFetcher = getAIFetcher(COMPLIANCE_REGION_CONFIG_UNKNOWN); describe("ai", () => { describe("fetcher", () => { + const std = mockConsoleMethods(); + afterEach(() => { vi.restoreAllMocks(); }); @@ -89,15 +91,18 @@ describe("ai", () => { { status: 403 } ); }); - const errorSpy = vi.spyOn(logger, "error"); const resp = await AIFetcher( new Request("http://internal.ai/ai/test/path", { method: "POST" }) ); expect(resp.status).toBe(403); - expect(errorSpy).toHaveBeenCalledWith( - "Authentication error (code 1031): Your API token may have expired or lacks the required permissions. Please refresh your token by running `wrangler login`." + expect(std.err).toMatchInlineSnapshot( + ` + "X [ERROR] Authentication error (code 1031): Your API token may have expired or lacks the required permissions. Please refresh your token by running \`wrangler login\`. + + " + ` ); }); @@ -115,14 +120,13 @@ describe("ai", () => { { status: 403 } ); }); - const errorSpy = vi.spyOn(logger, "error"); const resp = await AIFetcher( new Request("http://internal.ai/ai/test/path", { method: "POST" }) ); expect(resp.status).toBe(403); - expect(errorSpy).not.toHaveBeenCalled(); + expect(std.err).toMatchInlineSnapshot(`""`); }); it("should not throw on 403 with unparseable body", async ({ @@ -134,14 +138,13 @@ describe("ai", () => { vi.spyOn(internal, "performApiFetch").mockImplementation(async () => { return new Response("not json", { status: 403 }); }); - const errorSpy = vi.spyOn(logger, "error"); const resp = await AIFetcher( new Request("http://internal.ai/ai/test/path", { method: "POST" }) ); expect(resp.status).toBe(403); - expect(errorSpy).not.toHaveBeenCalled(); + expect(std.err).toMatchInlineSnapshot(`""`); }); }); }); diff --git a/packages/wrangler/src/__tests__/versions/versions.upload.test.ts b/packages/wrangler/src/__tests__/versions/versions.upload.test.ts index cae70128ed6..d68fe947107 100644 --- a/packages/wrangler/src/__tests__/versions/versions.upload.test.ts +++ b/packages/wrangler/src/__tests__/versions/versions.upload.test.ts @@ -2727,12 +2727,16 @@ describe("versions upload", () => { const mockExecSync = vi.fn(); +// At the top level because `vi.mock` is hoisted to module scope regardless of +// where it is written, so nesting it in the `describe` misrepresented its +// scope: it mocks `child_process` for the whole file, not just these tests. +vi.mock("child_process", () => ({ + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- vi.mock callback needs untyped rest args to forward to mock + execSync: (...args: any[]) => mockExecSync(...args), +})); + describe("generatePreviewAlias", () => { mockConsoleMethods(); - vi.mock("child_process", () => ({ - // eslint-disable-next-line @typescript-eslint/no-explicit-any -- vi.mock callback needs untyped rest args to forward to mock - execSync: (...args: any[]) => mockExecSync(...args), - })); beforeEach(() => { mockExecSync.mockReset(); diff --git a/packages/wrangler/vitest.config.mts b/packages/wrangler/vitest.config.mts index 31e8dbb799e..0f4fe5f30c6 100644 --- a/packages/wrangler/vitest.config.mts +++ b/packages/wrangler/vitest.config.mts @@ -5,9 +5,9 @@ import { dedent } from "ts-dedent"; import { defineConfig } from "vitest/config"; import type { PluginOption } from "vite"; -const TEMPLATES_DIR = path.join(__dirname, "templates"); +const TEMPLATES_DIR = path.join(import.meta.dirname, "templates"); -const OUTDIR = path.resolve(__dirname, "./.tmp/vitest-workers"); +const OUTDIR = path.resolve(import.meta.dirname, "./.tmp/vitest-workers"); function embedWorkersPlugin() { return { name: "embed-workers", @@ -42,7 +42,7 @@ function embedWorkersPlugin() { ); assert(scriptPath); const absoluteScriptPath = JSON.stringify( - path.resolve(__dirname, scriptPath) + path.resolve(import.meta.dirname, scriptPath) ); for (const file of watchFiles) { @@ -65,8 +65,14 @@ export default defineConfig({ include: ["**/__tests__/**/*.test.ts", "**/__tests__/**/*.test.tsx"], // eslint-disable-next-line turbo/no-undeclared-env-vars -- TEST_REPORT_PATH is optionally set by CI outputFile: process.env.TEST_REPORT_PATH ?? ".e2e-test-report/index.html", - setupFiles: path.resolve(__dirname, "src/__tests__/vitest.setup.ts"), - globalSetup: path.resolve(__dirname, "src/__tests__/vitest.global.ts"), + setupFiles: path.resolve( + import.meta.dirname, + "src/__tests__/vitest.setup.ts" + ), + globalSetup: path.resolve( + import.meta.dirname, + "src/__tests__/vitest.global.ts" + ), reporters: ["default", "html"], globals: true, unstubEnvs: true,