Instrument Unit Tests with a Coverage Threshold
Enable coverage instrumentation and set an enforceable threshold so new code cannot merge below the agreed bar.
Task
Configure coverage collection with a threshold that fails CI below the target.
When to use this
Coverage is measured but never enforced, so it drifts down release after release.
Prerequisites
- A test runner with coverage such as vitest or jest
- A CI pipeline
- An agreed coverage target
Steps
1. Enable coverage with thresholds per metric.
export default {
test: {
coverage: {
provider: 'v8',
thresholds: { lines: 80, functions: 75, branches: 70 },
},
},
};Expected output: A run below any threshold exits non-zero, failing CI.
2. Run coverage and confirm the gate.
npx vitest run --coverage || echo 'coverage gate failed'Expected output: The summary reports each metric against its threshold and fails when below.
Troubleshooting
Problem
Legacy code drags the number down
Solution
Ratchet per-directory thresholds and raise them as areas improve.
Problem
Coverage inflated by trivial tests
Solution
Pair coverage with mutation testing for critical modules.
Limitations
- Coverage measures execution, not correctness.
- Thresholds can be gamed.
- Generated code skews metrics.
What this recipe does
Configure coverage collection with a threshold that fails CI below the target.
Coverage is measured but never enforced, so it drifts down release after release.
Prerequisites
- A test runner with coverage such as vitest or jest
- A CI pipeline
- An agreed coverage target
Procedure
- Enable coverage with thresholds per metric.
export default {
test: {
coverage: {
provider: 'v8',
thresholds: { lines: 80, functions: 75, branches: 70 },
},
},
};
Expected result: A run below any threshold exits non-zero, failing CI.
- Run coverage and confirm the gate.
npx vitest run --coverage || echo 'coverage gate failed'
Expected result: The summary reports each metric against its threshold and fails when below.
How to confirm it worked
Run the commands above and confirm every expected result in order. If a step does not produce the stated output, use the troubleshooting notes before continuing. A passing run shows a commit that removes a test drops coverage below the threshold and fails CI.
Troubleshooting
Legacy code drags the number down — Ratchet per-directory thresholds and raise them as areas improve.
Coverage inflated by trivial tests — Pair coverage with mutation testing for critical modules.
Limitations
- Coverage measures execution, not correctness.
- Thresholds can be gamed.
- Generated code skews metrics.