# Vitest coverage: V8 vs Istanbul > Use V8 on Node.js or Chromium, and Istanbul where V8 coverage isn't available, such as Firefox. Since Vitest 3.2 both produce the same reports. Web page: https://supercov.com/compare/vitest-coverage · Published 2026-09-13, updated 2026-10-12 All Supercov pages for agents: https://supercov.com/llms.txt · Full text: https://supercov.com/llms-full.txt ## V8 vs Istanbul: which provider should you use? Start with V8 on Node.js or Chromium. Use Istanbul when your test environment cannot expose V8 coverage, such as Firefox. These are two ways to collect coverage for Vitest, not different test runners. Since Vitest 3.2, the V8 provider uses AST-based remapping to produce the same coverage reports as Istanbul. “Istanbul is more accurate” is no longer a good general reason to switch. That is specific to Vitest, not every V8-based tool. See the [official provider comparison](https://vitest.dev/guide/coverage). ## Set up coverage for your source files Install the coverage package that matches your Vitest version. For Vitest 5.0.0: ```sh npm install -D @vitest/coverage-v8@5.0.0 npx vitest run --coverage ``` Merge this coverage section into your existing configuration: ```ts import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { coverage: { provider: 'v8', include: ['src/**/*.{js,ts,jsx,tsx}'], reporter: ['text', 'html', 'json-summary'], }, }, }); ``` Use your actual source directory. Without an explicit include pattern, unimported source files may be absent from the report. For Istanbul, install the matching `@vitest/coverage-istanbul` package and change `provider` to `'istanbul'`. Keep the tests and source scope unchanged. Your agent can run these commands too. Current Vitest also [adapts its text reporter for agents](https://vitest.dev/guide/coverage#coverage-in-agent-environments). Agent-readable output alone is not a reason to add Supercov. ## Same tests, three coverage reports [Download the comparison](https://supercov.com/downloads/supercov-coverage-comparisons.zip), extract it and open the `javascript` folder. It contains a checkout function, two Vitest tests and pinned dependencies. Run: ```sh npm ci npx vitest run --coverage --coverage.provider=v8 npx vitest run --coverage --coverage.provider=istanbul npx supercov -- npx vitest run npx supercov runs latest ``` The rule is simple: checkout needs a signed-in customer whose session has not expired. It returns a status and the total: ```js export function checkout(signedIn, expired, price, quantity) { if (signedIn && !expired) { const total = price * quantity; return { status: 'confirmed', total }; } return { status: 'denied', total: 0 }; } ``` The starter tests check a valid session and a signed-out visitor. Both check the status; neither checks the total. These are measured results using Vitest 5.0.0 and Supercov 2.0.0. The Vitest runs are from September 14, 2026; Supercov's were repeated with 2.0.0 on September 25 and matched. All three runs use **the same Vitest tests**. | Report | Lines | Branches | MC/DC | | --- | --- | --- | --- | | Vitest V8 | 100% (4/4) | 100% (4/4) | Not reported | | Vitest Istanbul | 100% (4/4) | 100% (4/4) | Not reported | | Supercov wrapping Vitest | 100% (5/5) | 100% (2/2) | 50% (1/2) | Tools count executable lines and branches differently. Those denominators are not an accuracy ranking. The useful difference here is the additional question MC/DC asks. ## What test is missing? Inspect the decision: ```sh npx supercov runs latest decision src/session.js:2 ``` An excerpt from the actual output: ```text signedIn && !expired C1 covered: signedIn C2 MISSING: !expired confidence executed vectors: TT -> T tests=1 confidence=executed F- -> F tests=1 confidence=executed ``` No test tries a signed-in customer with an expired session. The expression `!expired` is never shown changing the outcome. Add this case to the suite: ```js test('rejects an expired session', () => { const order = checkout(true, true, 25, 2); assert.equal(order.status, 'denied'); }); ``` The download already imports `test` from Vitest and `assert` from `node:assert/strict`. The [MC/DC guide](https://supercov.com/docs/mcdc.md) explains how the three cases establish independent condition coverage. ## A second gap: a wrong total still passes The original tests also pass if `price * quantity` becomes `price * quantity - 1`. Everything still runs, and checkout still returns `'confirmed'`. None of the original assertions check the amount. The completed tests in `completed-tests.txt` add the expiry case and check `order.total === 50` for a price of 25 and quantity of 2. Replace `tests/session.test.js` with that file's contents, then repeat the commands. | Check | Starter tests | Completed tests | | --- | --- | --- | | Tests against the original code | Pass: 2 tests | Pass: 3 tests | | Native line and branch coverage | 100% | 100% | | MC/DC | 50% (1/2) | 100% (2/2) | | Remove the expiry guard | Still pass | Fail | | Subtract 1 from the total | Still pass | Fail | We ran both code changes separately and restored the source between checks. These are two selected faults, not a general mutation score or a demonstration that Supercov automatically finds every weak assertion. Assertions were not assessed in this comparison, which was recorded with Supercov 2.0. The reports say assertions are unassessed, not 0% or 100%. To assess them, run `runs latest assertions assess`; see [assertion coverage](https://supercov.com/docs/assertions.md). ## Browser Mode and component tests Both providers work in Vitest Browser Mode, where your component tests run in a real browser. So does Supercov: it measures a browser-mode run per test, with any provider and no extra configuration, and reports MC/DC and assertion coverage there too. One measurement detail matters more in component tests than anywhere else. A JSX tree is a single statement, so everything rendered inside it counts as covered the moment the component renders once -- including an expression that never evaluated. ![A JSX return statement. A bracket marks the whole tree as one statement to a line-based tool, while the aria-label expression and the child expression are highlighted separately; each is labelled with the assertion that reads it -- toHaveAccessibleName for the attribute, toHaveTextContent for the child.](https://supercov.com/assets/supercov-jsx-obligations-1280.d864e6c9a8.webp) *One statement to a line-based tool. Three obligations to Supercov, and two an assertion can name apart.* That is also the seam a UI assertion attaches to. `toHaveAccessibleName` is about the attribute and `toHaveTextContent` about the child; with one statement for the whole tree, neither can be named apart from the other, so neither can be credited to the test that checks it. Expressions that cannot independently fail to evaluate stay out of the count: `{value}` is reached exactly when the tree is, and `onClick={() => save()}` is measured where the handler is called rather than where it is created. See [supported suites](https://supercov.com/docs/supported-suites.md#vitest-browser-mode) for the rules. ## When is another tool worth adding? Keep native coverage for finding code that never runs. Add MC/DC when you want to inspect individual decision conditions. Use assertion coverage to find executed statements no test is judged to catch a change to; use mutation testing to run particular code changes against the suite. | Feature | Vitest · V8 5.0.0 | Vitest · Istanbul 5.0.0 | Supercov 4.3.0 | |---|---|---|---| | Code quality scoring | × Not built in | × Not built in | ✓ Supported | | Security review | × Not built in | × Not built in | ✓ Supported | | Line coverage | ✓ Supported | ✓ Supported | ✓ Supported | | Branch coverage | ✓ Supported | ✓ Supported | ✓ Supported | | MC/DC | × Not built in | × Not built in | ✓ Supported | | Per-test coverage | × Not built in | × Not built in | ✓ Supported | | Assertion coverage | × Not built in | × Not built in | ✓ Supported | | Reports | ✓ Supported | ✓ Supported | ✓ Supported | Standard coverage workflows in the versions shown; custom plugins are outside this table. Vitest uses its standard V8 or Istanbul coverage provider here. Supercov works with your existing test runner. Per-test coverage means individual tests, not just test files. Supercov needs a supported runner. Assertion coverage is Jev’s judgment, test by test, of whether changing each executed statement would make the test fail; it is not a mutation score or a correctness guarantee. The [recording](https://supercov.com/downloads/coverage-comparisons-2026-09-14.json) contains the source, exact commands, full output and before-and-after tests. This small example measures coverage criteria, not general accuracy or speed. For a broader choice, see [QA tools for coding agents](https://supercov.com/compare/qa-tools-for-coding-agents.md). If you are choosing a test runner rather than a coverage provider, see [Vitest vs Jest](https://supercov.com/compare/vitest-vs-jest.md). Jest has two providers of its own: see [Jest coverage: V8 vs Babel](https://supercov.com/compare/jest-coverage.md). ## Feature sources - [Vitest: V8 / Istanbul coverage](https://vitest.dev/guide/coverage) - [Vitest: Coverage provider API](https://github.com/vitest-dev/vitest/blob/v5.0.0/packages/vitest/src/node/types/coverage.ts) - [Supercov: Coverage model](https://github.com/supercorp-ai/supercov/blob/v4.3.0/docs/coverage-model.md) - [Supercov: Supported runners](https://github.com/supercorp-ai/supercov/blob/v4.3.0/docs/supported-suites.md) - [Supercov: Assertion coverage](https://github.com/supercorp-ai/supercov/blob/v4.3.0/docs/assertions.md) - [Supercov: Code quality](https://github.com/supercorp-ai/supercov/blob/v4.3.0/docs/quality.md) - [Supercov: Security](https://github.com/supercorp-ai/supercov/blob/v4.3.0/docs/security.md) - [Supercov: Reports](https://github.com/supercorp-ai/supercov/blob/v4.3.0/docs/reports.md) - [Supercov: CLI reference](https://github.com/supercorp-ai/supercov/blob/v4.3.0/docs/cli.md) Example evidence: [source, commands and full results (JSON)](https://supercov.com/downloads/coverage-comparisons-2026-09-14.json) · [runnable examples (ZIP)](https://supercov.com/downloads/supercov-coverage-comparisons.zip). Measured September 14, 2026; Supercov runs repeated with 2.0.0 on September 25, unchanged. Same-runner fixtures, not a performance benchmark or a general conformance test.