supercov 3.0.3 → 3.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -101,7 +101,7 @@ npx supercov runs latest assertions --test "closes the stream" # what one test
101
101
  ```text
102
102
  Run run_4f2a: 93.8% asserted (2731 of 2913 executed statements)
103
103
 
104
- Files, most statements not asserted first: a statement is not asserted when none of the tests asked about it was judged to fail if it changed. Up to 15 of the tests that run a statement are asked, so a test never asked can still catch it.
104
+ Files, most statements not asserted first: a statement is not asserted when none of the tests asked about it was judged to fail if it changed. Up to 18 of the tests that run a statement are asked, so a test never asked can still catch it.
105
105
  NOT ASSERTED ASSERTED FILE
106
106
  41 388/429 src/adapters.ts
107
107
  ...
@@ -120,7 +120,11 @@ nothing the asked tests assert depends on what the statement does. Five of the
120
120
  tests that run a statement are asked first, and up to 15 when none of those
121
121
  catches it: tests whose file quotes text the statement writes (a log line, a
122
122
  message), then tests named like the source file, then one per test file and
123
- describe block. A statement many tests run can still be caught by one that was
123
+ describe block. When none of the 15 catches it, up to three more are asked, the
124
+ ones most likely written for the statement: tests whose name shares words with
125
+ the statement's line (`corsOrigin: a false value` for
126
+ `return corsOrigin(origin)`), and among those the tests that ran the least
127
+ other code. A statement many tests run can still be caught by one that was
124
128
  never asked; the statement view (`assertions <file>:<line>`) says how many were.
125
129
 
126
130
  ## Which tests check a change
package/docs/cli.md CHANGED
@@ -142,14 +142,14 @@ npx supercov runs <run-id> [query] [options]
142
142
  | --- | --- |
143
143
  | no query | Read the overall result, test outcome, completeness, and timings |
144
144
  | `gaps` | See only files with uncovered behavior or measurement limits |
145
- | `files` | See every included file, including fully covered files |
145
+ | `files` | See every included file, including fully covered files; `--group dir` shows coverage by directory, split by test kind |
146
146
  | `file <path>` | Inspect the open obligations in one file |
147
147
  | `decision <id \| path:line>` | Understand missing boolean outcomes and MC/DC witnesses |
148
148
  | `line <path:line>` | See one line's state, obligations, and covering tests |
149
149
  | `test <id \| name>` | See the coverage attributed to one test |
150
150
  | `kinds` | Group coverage by test level, such as unit or E2E |
151
151
  | `runners` | Group coverage by test runner |
152
- | `scope` | Review included, excluded, and ambiguous source files |
152
+ | `scope` | See what is source and what is not, by directory and reason; `--files` lists every file |
153
153
  | `assertions` | Read the share of executed statements the tests assert, and the ones they do not; `assertions assess` works it out |
154
154
  | `source <path>` | Read matching current project source with line numbers |
155
155
  | `minimize` | Find a small test subset that preserves a coverage target |
@@ -164,6 +164,27 @@ npx supercov runs latest line app/routes/checkout.ts:57
164
164
  npx supercov runs latest test "checkout retry"
165
165
  ```
166
166
 
167
+ To see where the coverage is, read it by directory. Each row is a directory,
168
+ with what it holds and how much of it each kind of test covers; `--depth`
169
+ keeps more levels, and `--metric` picks branches, functions, statements or
170
+ MC/DC instead of lines:
171
+
172
+ ```sh supercov
173
+ npx supercov runs latest files --group dir
174
+ npx supercov runs latest files --group dir --depth 2 --metric branches
175
+ ```
176
+
177
+ ```
178
+ Directory Files Lines e2e unit All
179
+ app 4 15 86.67% 0.00% 100.00%
180
+ lib 1 10 90.00% 40.00% 90.00%
181
+ components 1 2 100.00% 0.00% 100.00%
182
+ ```
183
+
184
+ In `--json`, every file of `files` and `gaps` carries `totals` and `covered`
185
+ for each metric beside what is missing, so a percentage can be worked out for
186
+ any file or set of files.
187
+
167
188
  Run any query with `--help` to see only the options valid for that query:
168
189
 
169
190
  ```sh supercov
@@ -509,6 +530,7 @@ terminal or offline environment after the package has been downloaded.
509
530
  | --- | --- |
510
531
  | `SUPERCOV_SOURCE_ROOTS` | Comma-separated directories or files that hold your own code, in any language; everything else is left out |
511
532
  | `SUPERCOV_TEST_KIND` | Label the wrapped command as a test level such as `unit` or `e2e` |
533
+ | `SUPERCOV_KEEP_WORKSPACE` | Set to `1` to leave the instrumented copy of the project in `.supercov/workspaces/` after the run, to inspect what the command ran. It is kept without this when the build Supercov runs before the tests fails |
512
534
  | `SUPERCOV_BUILD_COMMAND` | The build a JavaScript project's tests need, as words or a JSON array, such as `yarn workspace web build` in a monorepo whose root `build` builds every package. Without it Supercov runs the project's `build` script, through the package manager that started the tests, when the tests need built output |
513
535
 
514
536
  Examples:
@@ -94,6 +94,18 @@ Both are useful:
94
94
  - exact evidence helps you inspect or minimize individual tests;
95
95
  - aggregate evidence still shows whether the whole suite reached the source.
96
96
 
97
+ Code that runs while no test is running counts in the run's total and in no
98
+ test's: a server starting before the first test, modules loading, work between
99
+ tests. When a run has any, the summary's `By test kind` table ends with a
100
+ `no test` row for what only that covered, which is why a run with one kind of
101
+ test can show a total above that kind's own:
102
+
103
+ ```
104
+ By test kind
105
+ e2e 3 test(s) lines 80.00% branches 66.67% MC/DC 25.00%
106
+ no test lines 17.14% branches 0.00% MC/DC 0.00%
107
+ ```
108
+
97
109
  See [Supported suites](supported-suites.md) for the attribution available from
98
110
  each runner.
99
111
 
@@ -128,6 +140,17 @@ If the summary reports ambiguous source scope, inspect it:
128
140
  npx supercov runs latest scope
129
141
  ```
130
142
 
143
+ It prints the scope by directory and reason, the ambiguous places first, and
144
+ the `SUPERCOV_SOURCE_ROOTS` value that would settle them. The summary names
145
+ the same places under `Instrumentation`. Add `--files` to list every file.
146
+
147
+ ```
148
+ Files Status Directory Reason
149
+ 79 AMBIGUOUS components unclassified first-party source
150
+ 227 INCLUDED app discovered package source root
151
+ 311 EXCLUDED tests test or fixture source
152
+ ```
153
+
131
154
  When first-party source lives in unusual directories, declare it explicitly:
132
155
 
133
156
  ```sh supercov
@@ -145,6 +168,20 @@ without a conventional source directory is measured as a whole. Functions passed
145
168
  to compile-time style macros (`stylex.create(...)`) are left as written because
146
169
  the bundler consumes them at build time; nothing about them runs.
147
170
 
171
+ Inside the roots, tests, fixtures, tool scripts and configuration files are
172
+ still recognised by their path and left out. A root you name settles what it
173
+ names: with `SUPERCOV_SOURCE_ROOTS=src,scripts` the `scripts/` directory is
174
+ source, and so is `src/test-utils` when it is named as a root. Only what lies
175
+ below a named root is still judged by its path, and a root that is a single
176
+ file is always measured.
177
+
178
+ In a Next.js application, root `components/` and `pages/`, and the root files
179
+ Next.js reads by name (`proxy`, `middleware`, `instrumentation`) are source
180
+ without being declared. Under `app/` a folder is a URL segment, so the files
181
+ the App Router serves (`route.ts`, `page.tsx`, `layout.tsx` and the rest) are
182
+ source whatever their folders are called: `app/api/wordpress/test/route.ts` is
183
+ the handler of `/api/wordpress/test`, not a test.
184
+
148
185
  Choose roots that describe code the repository owns. Do not include dependencies
149
186
  or generated output merely to make a warning disappear.
150
187
 
@@ -32,7 +32,8 @@ unusual directory, declare the source roots explicitly:
32
32
  SUPERCOV_SOURCE_ROOTS=src,app npx supercov -- npm test
33
33
  ```
34
34
 
35
- Then inspect what Supercov included and excluded:
35
+ Then inspect what Supercov included and excluded, by directory, or file by
36
+ file with `--files`:
36
37
 
37
38
  ```sh supercov
38
39
  npx supercov runs latest scope
@@ -41,6 +42,10 @@ npx supercov runs latest scope
41
42
  Do not broaden the roots to dependencies or generated output merely to remove a
42
43
  warning. The goal is an honest boundary around code the repository owns.
43
44
 
45
+ A file `scope` lists as `test or fixture source` or `conventional tool script`
46
+ was recognised by its path. If it is your code, name its directory, or the file
47
+ itself, as a root: a named root is source whatever it is called.
48
+
44
49
  ## Too much is measured
45
50
 
46
51
  Vendored or generated code beside your own is measured like the rest of the
@@ -34,6 +34,8 @@ and the instrumented copy is not what you wrote:
34
34
 
35
35
  - Linters, formatters and `tsc --noEmit` (ESLint, Prettier, standard, xo and
36
36
  the like) read each file as you wrote it, and don't see `.supercov`.
37
+ - The type check `next build` runs reads each file as you wrote it too, while
38
+ the build itself compiles the instrumented copy.
37
39
  - Coverage tools the command runs itself (tap, c8, nyc, Jest's and Vitest's
38
40
  `--coverage`) still collect and report coverage. They measure the
39
41
  instrumented copy, and report close to what they report without Supercov,
@@ -42,12 +44,23 @@ and the instrumented copy is not what you wrote:
42
44
 
43
45
  Files the wrapped command creates or changes inside the isolated workspace are
44
46
  synced back to the project after the run, so `supercov -- npm test -- -u`
45
- updates snapshots in the repository exactly as `npm test -- -u` would. Two
47
+ updates snapshots in the repository exactly as `npm test -- -u` would. Three
46
48
  exceptions are reported instead of applied: changes the command makes to
47
49
  instrumented source files (the instrumented copies must never overwrite your
48
- sources) and deletions (never propagated automatically). Changes inside any
49
- `node_modules` directory are neither applied nor reported: dependency trees are
50
- not command outputs.
50
+ sources), a build the command made from them, and deletions (never propagated
51
+ automatically). Such a build stays behind whole: when a file in `.next/`,
52
+ `dist/` or another directory that git ignores or the project does not have was
53
+ built from instrumented source, nothing in that directory is copied, so the
54
+ project never holds an instrumented build. Changes inside any `node_modules`
55
+ directory are neither applied nor reported: dependency trees are not command
56
+ outputs.
57
+
58
+ The run prints where the synced files went, what stayed behind and what the
59
+ command deleted, by top-level directory (`test-results/ 6`, `.next/ 2547`).
60
+
61
+ When the build Supercov runs before the tests fails, the instrumented copy is
62
+ left in `.supercov/workspaces/` until the next run, and the run prints its
63
+ path. `SUPERCOV_KEEP_WORKSPACE=1` leaves it after any run.
51
64
 
52
65
  ## Files Supercov creates
53
66
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "supercov",
3
- "version": "3.0.3",
3
+ "version": "3.0.5",
4
4
  "description": "Coverage, security and code quality for coding agents",
5
5
  "keywords": [
6
6
  "coverage",
@@ -66,6 +66,7 @@
66
66
  "sync:rust-assets": "node scripts/sync-rust-package-assets.mjs",
67
67
  "test:rust-assets": "node scripts/sync-rust-package-assets.mjs --check",
68
68
  "test": "cargo test --workspace",
69
+ "test:next-playwright": "cargo build -p supercov && npm --prefix tests/fixtures/next-playwright ci && node scripts/next-playwright-integration.mjs",
69
70
  "test:react": "cargo build -p supercov && node scripts/rust-vitest-projects-integration.mjs && npm --prefix examples/react-verification ci && npm --prefix examples/react-verification run demo && node scripts/react-hydration-compatibility.mjs",
70
71
  "test:release-tooling": "node --test tests/release/*.test.mjs",
71
72
  "test:runtime": "node --test tests/runtime/*.test.mjs",
@@ -118,14 +119,14 @@
118
119
  "test:windows-tls": "node scripts/windows-tls-test.mjs"
119
120
  },
120
121
  "optionalDependencies": {
121
- "@supercov/cli-darwin-arm64": "3.0.3",
122
- "@supercov/cli-darwin-x64": "3.0.3",
123
- "@supercov/cli-linux-arm64-gnu": "3.0.3",
124
- "@supercov/cli-linux-arm64-musl": "3.0.3",
125
- "@supercov/cli-linux-x64-gnu": "3.0.3",
126
- "@supercov/cli-linux-x64-musl": "3.0.3",
127
- "@supercov/cli-win32-arm64": "3.0.3",
128
- "@supercov/cli-win32-x64": "3.0.3"
122
+ "@supercov/cli-darwin-arm64": "3.0.5",
123
+ "@supercov/cli-darwin-x64": "3.0.5",
124
+ "@supercov/cli-linux-arm64-gnu": "3.0.5",
125
+ "@supercov/cli-linux-arm64-musl": "3.0.5",
126
+ "@supercov/cli-linux-x64-gnu": "3.0.5",
127
+ "@supercov/cli-linux-x64-musl": "3.0.5",
128
+ "@supercov/cli-win32-arm64": "3.0.5",
129
+ "@supercov/cli-win32-x64": "3.0.5"
129
130
  },
130
131
  "peerDependencies": {
131
132
  "@playwright/test": ">=1.55.0",
@@ -178,6 +178,24 @@ const isAnalysisEntrypoint = new RegExp(`/node_modules/(?:\\.bin/(?:${analysisTo
178
178
  process.argv.includes("--noEmit"));
179
179
  if (isAnalysisEntrypoint)
180
180
  installAuthoredSourceView();
181
+ // `next build` type-checks in a worker of its own instead of running tsc. A
182
+ // probe in a condition stops TypeScript narrowing through it, so an inferred
183
+ // return type widens, and a file outside the source roots that calls the
184
+ // function fails the build on code nobody wrote ("'client' is possibly
185
+ // 'null'"). Only that worker gets the authored view: the bundler, and `next
186
+ // dev`, which sets TypeScript up in its main process, must read the copies.
187
+ else if (/\/node_modules\/next\/dist\/compiled\/jest-worker\/processChild\.js$/.test(entrypoint) ||
188
+ (!workerThreads.isMainThread && /\/node_modules\/(?:\.bin\/next$|next\/dist\/)/.test(entrypoint))) {
189
+ const compile = Module.prototype._compile;
190
+ let installed = false;
191
+ Module.prototype._compile = function _compile(content, filename, ...rest) {
192
+ if (!installed && /[\\/]next[\\/]dist[\\/]lib[\\/]verify-typescript-setup\.js$/.test(filename)) {
193
+ installed = true;
194
+ installAuthoredSourceView();
195
+ }
196
+ return Reflect.apply(compile, this, [content, filename, ...rest]);
197
+ };
198
+ }
181
199
  function installAuthoredSourceView() {
182
200
  let authored;
183
201
  try {
@@ -890,7 +890,7 @@ function cleanInstrumentationStack(error) {
890
890
  if (!error || typeof error !== "object" || typeof error.stack !== "string")
891
891
  return error;
892
892
  const lines = error.stack.split("\n");
893
- const visible = lines.filter((line, index) => index === 0 || !/[\\/]\.supercov[\\/](?:playwright|nodeTest|vitest|runtime|launchSupervisor|nodeAssert|nodeAssertStrict|nodeAssertAdapter|register|resolve-loader)\.(?:js|mjs)(?::|\))/u.test(line));
893
+ const visible = lines.filter((line, index) => index === 0 || !/[\\/]\.supercov[\\/](?:node_modules[\\/])?(?:playwright|nodeTest|vitest|runtime|launchSupervisor|nodeAssert|nodeAssertStrict|nodeAssertAdapter|register|resolve-loader)\.(?:js|mjs)(?::|\))/u.test(line));
894
894
  if (visible.length !== lines.length) {
895
895
  try {
896
896
  error.stack = visible.join("\n");