React

Useful coverage: the threshold that makes sense

Coverage counts executed lines, not checked lines. A useful threshold starts at 80% on lines and 70% on branches, per folder rather than on the total.

Key points

  • The percentage counts executed lines: a test with no assertion raises it while proving nothing.
  • Thresholds belong per folder: a total hides the module with no tests.
  • 80% lines and 70% branches cover the code that decides behaviour; beyond that you chase getters.

Coverage measures executed lines, not checked lines: a test with no assertion raises the number and proves nothing. The useful threshold goes per folder, not on the project total.

What the number measures

The v8 provider in Vitest, under the MIT licence, reads the counters of the JavaScript engine and reports four values: lines, branches, functions and statements. None of the four looks at assertions.

A configuration that holds

// vitest.config.ts
import { defineConfig } from "vitest/config";

export default defineConfig({
  test: {
    coverage: {
      provider: "v8",
      reporter: ["text", "json-summary"],
      thresholds: { lines: 80, branches: 70, functions: 80, statements: 80 },
    },
  },
});

Thresholds make the command fail instead of printing a number: that is the difference between a metric and a contract. On a monorepo, add a per-folder threshold with perFile.

The command

npm i -D vitest @vitest/coverage-v8
npx vitest run --coverage

The @vitest/coverage-v8 package is MIT and reuses the counters Node already keeps: no external service, no upload, and the report stays in CI.

Live records in the catalogue

Three records with real branches to cover: filters, data-table and progress-indicator. To browse by category start from 111,985 components.

The limitation

Coverage cannot see assertion quality: a file at 100% may verify nothing. It does not measure code that does not exist yet either, meaning the edge cases nobody wrote, and those come from reading the component, not the report.

Where to continue

The test model is in Testing Library: the five tests; the double calls that inflate counters are in StrictMode; the framework comparison is in frontend frameworks compared; the render profile is in React Profiler.

Frequently asked questions

Which coverage threshold makes sense?

80% on lines and 70% on branches per folder. Below that, important code stays untested; above it you chase getters and constants.

Does 100% coverage mean zero bugs?

No. It means every line ran at least once, not that an assertion checked the result.

Lines or branches?

Branches, when you must choose. An if statement covered only on the true path remains half untested.

Does coverage slow CI down?

Barely. The v8 provider reuses the engine counters, so the cost is almost entirely writing the report.

Should the report be published?

No, if it holds internal paths. It belongs in the pipeline; publish at most the per-folder number.