Background
The frontend has a test:coverage script (vitest run --coverage), but CI only runs npm run test, which does not collect or enforce coverage. Combined with the size of the app — roughly 266 components against about 56 test files — this means large parts of the UI are untested and nothing prevents that ratio from getting worse. A PR can add several new components with no tests and CI stays perfectly green.
Why this matters
The goal here is not to demand high coverage overnight — that would be unrealistic for a codebase this size and would just invite low-value tests. The goal is a ratchet: measure where coverage honestly is today, pin that as the floor, and make CI fail if a change drops below it. That guarantees the app only ever gets better-tested, never worse, and it channels new test effort toward the code being actively changed.
What needs to be done
- Measure first. Run
npm run test:coverage and record the current real coverage numbers (lines/functions/branches/statements).
- Set thresholds to that baseline in the vitest coverage config — the current measured numbers, not aspirational ones — so the gate is realistic and immediately passable, then only tightens over time.
- Add a coverage step to
.github/workflows/ci.yml (run npm run test:coverage) that fails the build when coverage regresses below the baseline.
- Exclude generated files, config, and non-testable entry points from the coverage denominator so the number reflects real application code.
- Optionally upload the coverage report as a CI artifact for reviewer visibility.
Where to look
package.json — the test:coverage script
vitest.config.ts (or the equivalent config) — where coverage thresholds and excludes live
.github/workflows/ci.yml — where to add the gate
Acceptance criteria
Notes
The whole point is to start at today's number and ratchet upward — resist the urge to set an ambitious threshold that would fail on day one.
Background
The frontend has a
test:coveragescript (vitest run --coverage), but CI only runsnpm run test, which does not collect or enforce coverage. Combined with the size of the app — roughly 266 components against about 56 test files — this means large parts of the UI are untested and nothing prevents that ratio from getting worse. A PR can add several new components with no tests and CI stays perfectly green.Why this matters
The goal here is not to demand high coverage overnight — that would be unrealistic for a codebase this size and would just invite low-value tests. The goal is a ratchet: measure where coverage honestly is today, pin that as the floor, and make CI fail if a change drops below it. That guarantees the app only ever gets better-tested, never worse, and it channels new test effort toward the code being actively changed.
What needs to be done
npm run test:coverageand record the current real coverage numbers (lines/functions/branches/statements)..github/workflows/ci.yml(runnpm run test:coverage) that fails the build when coverage regresses below the baseline.Where to look
package.json— thetest:coveragescriptvitest.config.ts(or the equivalent config) — where coverage thresholds and excludes live.github/workflows/ci.yml— where to add the gateAcceptance criteria
Notes
The whole point is to start at today's number and ratchet upward — resist the urge to set an ambitious threshold that would fail on day one.