From bf4fe8030a72fcb78257581b394daec44d67fa06 Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Fri, 27 Mar 2026 15:55:03 +0000 Subject: [PATCH 1/3] [vitest-pool-workers] Reject V8 coverage provider with a clear error V8 native coverage requires node:inspector which is non-functional in workerd. Detect this early in the Vite plugin config hook and throw a clear error directing users to Istanbul coverage instead. Fixes #5266 --- .changeset/reject-v8-coverage-provider.md | 9 +++ .../vitest-pool-workers/src/pool/plugin.ts | 29 ++++++++ .../test/validation.test.ts | 74 +++++++++++++++++++ 3 files changed, 112 insertions(+) create mode 100644 .changeset/reject-v8-coverage-provider.md diff --git a/.changeset/reject-v8-coverage-provider.md b/.changeset/reject-v8-coverage-provider.md new file mode 100644 index 0000000000..01f787f071 --- /dev/null +++ b/.changeset/reject-v8-coverage-provider.md @@ -0,0 +1,9 @@ +--- +"@cloudflare/vitest-pool-workers": patch +--- + +Reject V8 coverage provider with a clear error message + +V8 native code coverage (`@vitest/coverage-v8`) requires `node:inspector` to collect profiling data from V8's runtime. workerd only provides `node:inspector` as a non-functional stub, so V8 coverage would silently fail or crash with a confusing `No such module "node:inspector"` error. + +The pool now detects this configuration early — during Vite plugin setup, before Vitest tries to load the coverage provider — and throws a clear error directing users to use Istanbul coverage instead, which works by instrumenting source code at build time and runs on any JavaScript runtime. diff --git a/packages/vitest-pool-workers/src/pool/plugin.ts b/packages/vitest-pool-workers/src/pool/plugin.ts index ef120d6beb..4b5945b27d 100644 --- a/packages/vitest-pool-workers/src/pool/plugin.ts +++ b/packages/vitest-pool-workers/src/pool/plugin.ts @@ -71,6 +71,35 @@ export function cloudflareTest( config.test ??= {}; config.test.server ??= {}; config.test.server.deps ??= {}; + + // V8 coverage requires `node:inspector` to collect coverage data from + // V8's profiler. workerd provides `node:inspector` as a non-functional + // stub, so V8 coverage silently fails or crashes. Istanbul works because + // it instruments source code at build time without needing V8 access. + // See: https://github.com/cloudflare/workers-sdk/issues/5266 + const coverage = config.test.coverage; + if ( + coverage && + typeof coverage === "object" && + !Array.isArray(coverage) && + coverage.enabled + ) { + const provider = "provider" in coverage ? coverage.provider : undefined; + if (provider === "v8" || provider === undefined) { + const lines = [ + `Coverage provider "v8" is not supported by \`@cloudflare/vitest-pool-workers\`.`, + "V8 native coverage requires \`node:inspector\` which is not functional in the Workers runtime.", + "", + "Use Istanbul instead — it works by instrumenting source code and runs on any JavaScript runtime:", + "", + " 1. Install: pnpm add -D @vitest/coverage-istanbul", + ' 2. Set \`test.coverage.provider\` to "istanbul" in your Vitest config', + "", + "See https://vitest.dev/guide/coverage#istanbul-provider for more details.", + ]; + throw new Error(lines.join("\n")); + } + } // See https://vitest.dev/config/server.html#inline // Without this Vitest delegates to native import() for external deps in node_modules config.test.server.deps.inline = true; diff --git a/packages/vitest-pool-workers/test/validation.test.ts b/packages/vitest-pool-workers/test/validation.test.ts index 322e6ec5ac..6e3141dc5f 100644 --- a/packages/vitest-pool-workers/test/validation.test.ts +++ b/packages/vitest-pool-workers/test/validation.test.ts @@ -1,5 +1,6 @@ import path from "node:path"; import dedent from "ts-dedent"; +import { describe } from "vitest"; import { test, vitestConfig } from "./helpers"; test( @@ -107,3 +108,76 @@ test( expect(result.stderr).toMatch(expected); } ); + +describe("coverage provider validation", () => { + test( + "rejects v8 coverage provider with a clear error", + { timeout: 45_000 }, + async ({ expect, seed, vitestRun }) => { + await seed({ + "vitest.config.mts": vitestConfig( + {}, + { coverage: { enabled: true, provider: "v8" } } + ), + "index.test.ts": dedent /* javascript */ ` + import { it, expect } from "vitest"; + it("works", () => { + expect(1 + 1).toBe(2); + }); + `, + }); + const result = await vitestRun(); + expect(await result.exitCode).toBe(1); + expect(result.stderr).toMatch( + 'Coverage provider "v8" is not supported by `@cloudflare/vitest-pool-workers`' + ); + expect(result.stderr).toMatch("Use Istanbul instead"); + } + ); + + test( + "rejects default coverage provider (v8) with a clear error", + { timeout: 45_000 }, + async ({ expect, seed, vitestRun }) => { + // When no provider is specified, Vitest defaults to v8 + await seed({ + "vitest.config.mts": vitestConfig({}, { coverage: { enabled: true } }), + "index.test.ts": dedent /* javascript */ ` + import { it, expect } from "vitest"; + it("works", () => { + expect(1 + 1).toBe(2); + }); + `, + }); + const result = await vitestRun(); + expect(await result.exitCode).toBe(1); + expect(result.stderr).toMatch( + 'Coverage provider "v8" is not supported by `@cloudflare/vitest-pool-workers`' + ); + } + ); + + test( + "allows istanbul coverage provider", + { timeout: 60_000 }, + async ({ expect, seed, vitestRun }) => { + await seed({ + "vitest.config.mts": vitestConfig( + {}, + { coverage: { enabled: true, provider: "istanbul" } } + ), + "index.test.ts": dedent /* javascript */ ` + import { it, expect } from "vitest"; + it("works", () => { + expect(1 + 1).toBe(2); + }); + `, + }); + const result = await vitestRun(); + // Should not fail with a coverage provider error + expect(result.stderr).not.toMatch( + 'Coverage provider "v8" is not supported' + ); + } + ); +}); From 0557efffeb20a93e19b6766860f01246dca8124a Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Mon, 30 Mar 2026 14:34:49 +0100 Subject: [PATCH 2/3] fix: Remove unnecessary escape characters in error message strings --- packages/vitest-pool-workers/src/pool/plugin.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/vitest-pool-workers/src/pool/plugin.ts b/packages/vitest-pool-workers/src/pool/plugin.ts index 4b5945b27d..bc886d9a6f 100644 --- a/packages/vitest-pool-workers/src/pool/plugin.ts +++ b/packages/vitest-pool-workers/src/pool/plugin.ts @@ -87,13 +87,13 @@ export function cloudflareTest( const provider = "provider" in coverage ? coverage.provider : undefined; if (provider === "v8" || provider === undefined) { const lines = [ - `Coverage provider "v8" is not supported by \`@cloudflare/vitest-pool-workers\`.`, - "V8 native coverage requires \`node:inspector\` which is not functional in the Workers runtime.", + 'Coverage provider "v8" is not supported by `@cloudflare/vitest-pool-workers`.', + "V8 native coverage requires `node:inspector` which is not functional in the Workers runtime.", "", "Use Istanbul instead — it works by instrumenting source code and runs on any JavaScript runtime:", "", " 1. Install: pnpm add -D @vitest/coverage-istanbul", - ' 2. Set \`test.coverage.provider\` to "istanbul" in your Vitest config', + ' 2. Set `test.coverage.provider` to "istanbul" in your Vitest config', "", "See https://vitest.dev/guide/coverage#istanbul-provider for more details.", ]; From 1460c3c8f2c8850046c5effee0a21e361d7bacf1 Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Thu, 2 Apr 2026 12:12:58 +0100 Subject: [PATCH 3/3] =?UTF-8?q?fix:=20Address=20review=20comments=20?= =?UTF-8?q?=E2=80=94=20simplify=20coverage=20check,=20use=20generic=20npm?= =?UTF-8?q?=20install?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/vitest-pool-workers/src/pool/plugin.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/vitest-pool-workers/src/pool/plugin.ts b/packages/vitest-pool-workers/src/pool/plugin.ts index bc886d9a6f..1e1b4cf1b6 100644 --- a/packages/vitest-pool-workers/src/pool/plugin.ts +++ b/packages/vitest-pool-workers/src/pool/plugin.ts @@ -78,12 +78,7 @@ export function cloudflareTest( // it instruments source code at build time without needing V8 access. // See: https://github.com/cloudflare/workers-sdk/issues/5266 const coverage = config.test.coverage; - if ( - coverage && - typeof coverage === "object" && - !Array.isArray(coverage) && - coverage.enabled - ) { + if (coverage && coverage.enabled) { const provider = "provider" in coverage ? coverage.provider : undefined; if (provider === "v8" || provider === undefined) { const lines = [ @@ -92,7 +87,7 @@ export function cloudflareTest( "", "Use Istanbul instead — it works by instrumenting source code and runs on any JavaScript runtime:", "", - " 1. Install: pnpm add -D @vitest/coverage-istanbul", + " 1. Install: npm i -D @vitest/coverage-istanbul", ' 2. Set `test.coverage.provider` to "istanbul" in your Vitest config', "", "See https://vitest.dev/guide/coverage#istanbul-provider for more details.",