Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changeset/reject-v8-coverage-provider.md
Original file line number Diff line number Diff line change
@@ -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.
24 changes: 24 additions & 0 deletions packages/vitest-pool-workers/src/pool/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,30 @@ 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 && 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: 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.",
];
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;
Expand Down
74 changes: 74 additions & 0 deletions packages/vitest-pool-workers/test/validation.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import path from "node:path";
import dedent from "ts-dedent";
import { describe } from "vitest";
import { test, vitestConfig } from "./helpers";

test(
Expand Down Expand Up @@ -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 },
Comment thread
penalosa marked this conversation as resolved.
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'
);
}
);
});
Loading