Our coverage report says 76%, and it is measuring 122 statements out of a 1,009 file library
Here is the whole of CogniPrep's coverage output. Not an excerpt: Test Files 355 passed (355) Tests 7729 passed | 1 skipped (7730) Duration 39.14s % Coverage report from v8 -------------------|---------
Here is the whole of CogniPrep's coverage output. Not an excerpt:
Test Files 355 passed (355)
Tests 7729 passed | 1 skipped (7730)
Duration 39.14s
% Coverage report from v8
-------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-------------------|---------|----------|---------|---------|-------------------
All files | 76.22 | 66.23 | 77.77 | 74.07 |
api | 63.04 | 52.94 | 64.28 | 63.63 |
...on-schemas.ts | 55.26 | 11.11 | 61.53 | 55.55 | 51,82,109,118-143
auth | 100 | 92.85 | 100 | 100 |
...identifier.ts | 100 | 92.85 | 100 | 100 | 45
email | 100 | 33.33 | 100 | 100 |
...scribe-url.ts | 100 | 33.33 | 100 | 100 | 9
games | 94.59 | 83.87 | 89.47 | 93.1 | 154,164
constants.ts | 94.59 | 83.87 | 89.47 | 93.1 | 154,164
plan | 37.5 | 16.66 | 25 | 33.33 | 35-41,57-85
plan.ts | 37.5 | 16.66 | 25 | 33.33 | 35-41,57-85
-------------------|---------|----------|---------|---------|-------------------
Statements : 76.22% ( 93/122 )
Seven and a half thousand tests, and the report underneath them describes 122 statements. The lib directory of this project contains 1,009 TypeScript files. Five of them are in that table.
That is on purpose, and I think it is the more useful arrangement. Here is the argument.
A project-wide percentage is a number you cannot act on
coverage.include in vitest.config.ts is an explicit list, with a comment saying why those files and not others:
coverage: {
provider: 'v8',
// Focus coverage on the architectural / high-risk modules the tests target:
// access control, API validation, billing tier mapping, email signing, and
// the two fail-closed / anti-spoofing helpers guarding the cron and rate
// limit boundaries.
include: [
'lib/games/constants.ts',
'lib/api/validation-schemas.ts',
'lib/api/cron-helpers.ts',
'lib/auth/client-identifier.ts',
'lib/plan/plan.ts',
'lib/email/unsubscribe-url.ts',
],
},
Turn that list off and the headline becomes some number in the sixties across a thousand files, and every subsequent conversation is about the number. Line coverage across a whole app is dominated by whatever happens to be biggest, and in this codebase that is content: static data, copy, page components, per-provider definitions. Those are tested, heavily, by assertions about their content rather than by executing them, and dragging them into a percentage means the number moves whenever somebody adds a page.
The six files in the list are the ones where a wrong branch is a quiet failure rather than a visible one. Boundaries, not volume.
The scoped report immediately told me something
Two rows in that table are the point of having it at all.
plan.ts, which maps a purchase to what an account is allowed to do, is at 37.5% of statements and 25% of functions, with lines 57 to 85 never executed. It is on the list because it is high risk, and the report's answer is that the tests barely touch it. That is an actionable sentence. "The project is at 64%" is not.
validation-schemas.ts is the other one: 55% of statements, and 11.11% of branches, one branch out of nine. For a file whose entire job is branching on whether input is acceptable, branch coverage is the only column that means anything, and it is the worst number on the board.
A six-file report made both of those impossible to miss. A thousand-file report would have buried them in the noise of a hundred page components.
The row that is not in the table
There is a sixth file in the include list. Count the rows above: cron-helpers.ts is not there.
It is not untested. It has two test files of its own, and the JSON artifact has it at 8 of 8 statements, 1 of 1 functions and 8 of 8 branches:
lib/api/cron-helpers.ts stmts 8/8 funcs 1/1 branches 8/8
lib/api/validation-schemas.ts stmts 21/38 funcs 8/13 branches 1/9
lib/auth/client-identifier.ts stmts 18/18 funcs 6/6 branches 13/14
lib/email/unsubscribe-url.ts stmts 5/5 funcs 2/2 branches 1/3
lib/games/constants.ts stmts 35/37 funcs 17/19 branches 26/31
lib/plan/plan.ts stmts 6/16 funcs 1/4 branches 2/12
The only file at 100% on all four metrics is the only file the text reporter leaves out. Every other row in the table has at least one column under 100, including the two that show 100 for statements and lines but not for branches. So the file you would most want to point at in a review, the fail-closed one that is actually fully exercised, reads as missing, and the api directory row averages it in while hiding it.
Worth knowing before you conclude from a terminal table that something is untested. Read coverage-final.json if the answer matters:
python3 -c "import json;d=json.load(open('coverage/coverage-final.json'));print(list(d))"
Two things about the include glob while I am here
include: ['**/__tests__/**/*.test.ts'],
354 of the 355 test files live under the top-level __tests__ directory. The 355th is components/games/shared/diagrams/__tests__/diagrams.test.ts, sitting next to the component it tests, and the leading ** is the only reason it runs. Both conventions work and the glob does not care which you pick.
It does care about the extension. *.test.ts means a file named something.test.tsx is collected by nothing and reported by nothing: a green run with a file silently absent. There are zero of those today, which is exactly the condition under which a trap like that survives, so it goes in the config's comments rather than in my memory.
See it
The best covered file in the list is also the only one whose output you can count from outside the app. lib/games/constants.ts re-exports the provider registry that derives the site's routes, so:
curl -s https://cogniprep.app/sitemap.xml | grep -c '<loc>'
curl -s https://cogniprep.app/sitemap.xml | grep -o '<loc>https://cogniprep.app/games/[^<]*</loc>' | wc -l
375 URLs, of which 56 are provider hubs, one per provider in that file. A single provider added to it moves both numbers, which is why the file sits at 94% rather than at whatever a page component gets, and you can watch it from cogniprep.app/games without reading a line of our code. The thing those tests are protecting is at cogniprep.app.
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes β full credit and traffic to the original publisher.