supercov 4.2.0 → 4.3.0

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.
@@ -86,6 +86,8 @@ npx supercov runs latest assertions
86
86
  Supercov renders what the test ran -- its code, its helpers, and the source it
87
87
  executed -- and asks [Jev](https://typesafe.ai) whether the test would fail for
88
88
  each statement's change. It prints an estimate first; `--dry-run` sends nothing.
89
+ The estimate gives the first round and the most the pass can send, which is
90
+ what it sends when no test is judged to catch anything.
89
91
  It needs a TypeSafe AI API key in `TYPESAFE_API_KEY`.
90
92
 
91
93
  `assertions` reads the saved result with no network and no key, a page at a
package/docs/cli.md CHANGED
@@ -61,7 +61,8 @@ the score is arithmetic this command does over the answers. Text reports a band,
61
61
  `good`, `fair` or `weak`; `--json` carries the number and every check with what
62
62
  is known about it. `--all` includes test files, generated output and anything
63
63
  outside a source root, all of which are left out by default. `--dry-run` prints
64
- the exact requests and contacts nothing.
64
+ the exact requests and contacts nothing; how many there are and what they cost
65
+ is one line on stderr.
65
66
 
66
67
  `quality diff` reports what changed between two assessments: which files lost
67
68
  or gained health, each check that moved in them with its value before and after,
@@ -354,7 +355,17 @@ npx supercov diff <older-run> <newer-run>
354
355
 
355
356
  `diff` reports gains and losses. Use it after adding a test to prove that the
356
357
  expected behavior became covered without an unexplained regression elsewhere.
357
- Neither input run is changed.
358
+ Neither input run is changed. Under the totals it lists what was lost, marked
359
+ `-`, and then what was gained, marked `+`:
360
+
361
+ ```
362
+ gained: 1 lines, 1 branches, 0 MC/DC conditions
363
+ lost: 1 lines, 1 branches, 0 MC/DC conditions
364
+ - line src/fee.js:5
365
+ - branch src/fee.js:2 false
366
+ + line src/fee.js:3
367
+ + branch src/fee.js:2 true
368
+ ```
358
369
 
359
370
  Two runs of the same code can differ a little: what an end-to-end suite
360
371
  reaches depends on timing, on the order of tests, and on state outside the
@@ -497,6 +508,11 @@ Merge creates a new run. The inputs must describe the same source,
497
508
  configuration, toolchain, schema, and coverage denominator. Supercov rejects an
498
509
  incompatible merge rather than publishing a misleading aggregate.
499
510
 
511
+ `assertions assess` assesses a merged run across every suite merged into it,
512
+ reusing the answers saved when its parts were assessed. `tests affected` is
513
+ asked of the runs that were merged, which hold the record of what each test
514
+ ran.
515
+
500
516
  ## Clean local data
501
517
 
502
518
  ```sh supercov
package/docs/quality.md CHANGED
@@ -153,6 +153,12 @@ Source roots come from your package manifests and from what they declare, so a
153
153
  Test files, generated output, tool scripts, examples, benchmarks and
154
154
  documentation are left out, each with its reason. `--all` includes everything.
155
155
 
156
+ A JavaScript or TypeScript file a coverage run would measure is always read,
157
+ by `quality` and by `security`: the App Router handler at
158
+ `app/api/wordpress/test/route.ts` is a route, not a test, and a root named in
159
+ `SUPERCOV_SOURCE_ROOTS` is not second-guessed by its own name. Generated and
160
+ vendored files stay out.
161
+
156
162
  If some of your code sits somewhere none of that recognises, Supercov asks Jev
157
163
  about those paths with your whole tree as context, and says how many it decided
158
164
  that way. To decide yourself:
package/docs/security.md CHANGED
@@ -183,6 +183,12 @@ many of its measured lines no test reached. A handler that builds a query from
183
183
  request input is one thing; the same handler that no test ever executes is a
184
184
  stronger claim, and one that needs both halves of this product to make.
185
185
 
186
+ When the run's assertions were assessed (`runs <run> assertions assess`), the
187
+ report also says which flagged lines a test is judged to catch a change to, and
188
+ which flagged files tests run without catching any line of. A run that was not
189
+ assessed says so instead: nobody asked its tests, which is not the same as
190
+ their catching nothing.
191
+
186
192
  ## What a change introduced
187
193
 
188
194
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "supercov",
3
- "version": "4.2.0",
3
+ "version": "4.3.0",
4
4
  "description": "Coverage, security and code quality for coding agents",
5
5
  "keywords": [
6
6
  "coverage",
@@ -119,14 +119,14 @@
119
119
  "test:windows-tls": "node scripts/windows-tls-test.mjs"
120
120
  },
121
121
  "optionalDependencies": {
122
- "@supercov/cli-darwin-arm64": "4.2.0",
123
- "@supercov/cli-darwin-x64": "4.2.0",
124
- "@supercov/cli-linux-arm64-gnu": "4.2.0",
125
- "@supercov/cli-linux-arm64-musl": "4.2.0",
126
- "@supercov/cli-linux-x64-gnu": "4.2.0",
127
- "@supercov/cli-linux-x64-musl": "4.2.0",
128
- "@supercov/cli-win32-arm64": "4.2.0",
129
- "@supercov/cli-win32-x64": "4.2.0"
122
+ "@supercov/cli-darwin-arm64": "4.3.0",
123
+ "@supercov/cli-darwin-x64": "4.3.0",
124
+ "@supercov/cli-linux-arm64-gnu": "4.3.0",
125
+ "@supercov/cli-linux-arm64-musl": "4.3.0",
126
+ "@supercov/cli-linux-x64-gnu": "4.3.0",
127
+ "@supercov/cli-linux-x64-musl": "4.3.0",
128
+ "@supercov/cli-win32-arm64": "4.3.0",
129
+ "@supercov/cli-win32-x64": "4.3.0"
130
130
  },
131
131
  "peerDependencies": {
132
132
  "@playwright/test": ">=1.55.0",
@@ -198,6 +198,7 @@ class CoveragePhaseController {
198
198
  cdpSessions = new Map();
199
199
  newDocumentScriptIds = new Map();
200
200
  pendingRegistrations = new Set();
201
+ pageRegistrations = new WeakMap();
201
202
  scriptUpdate = Promise.resolve();
202
203
  proxyCache = new WeakMap();
203
204
  runtimeSnapshots;
@@ -381,8 +382,27 @@ class CoveragePhaseController {
381
382
  }
382
383
  }
383
384
  }
384
- async registerPage(page) {
385
- if (this.pages.has(page) || this.disposed)
385
+ /**
386
+ * A page is registered once, and whoever asks while that is under way
387
+ * waits for it. Playwright announces a page to the context's listener
388
+ * before the fixture that hands it to the test has it, so the listener
389
+ * started the registration and the fixture, finding the page known,
390
+ * returned at once: the test's first `page.goto` began before the page had
391
+ * the session a phase is installed through. The document it loaded did not
392
+ * know its phase, and its hits were left to be placed by their time.
393
+ */
394
+ registerPage(page) {
395
+ if (this.disposed)
396
+ return Promise.resolve();
397
+ let registration = this.pageRegistrations.get(page);
398
+ if (!registration) {
399
+ registration = this.registerNewPage(page);
400
+ this.pageRegistrations.set(page, registration);
401
+ }
402
+ return registration;
403
+ }
404
+ async registerNewPage(page) {
405
+ if (this.pages.has(page))
386
406
  return;
387
407
  timingCount("registerPage");
388
408
  this.pages.add(page);
@@ -393,8 +413,15 @@ class CoveragePhaseController {
393
413
  adopted: !this.contexts.has(context) && tracked && !headersKnown,
394
414
  });
395
415
  const cdp = await page.context().newCDPSession(page).catch(() => undefined);
396
- if (cdp)
416
+ if (cdp) {
417
+ // Chromium runs a session's new-document scripts only once the
418
+ // session has enabled the Page domain. Without it the script that
419
+ // tells a document its phase was accepted and never ran: a page
420
+ // learned its phase only from the next action, after it had
421
+ // loaded, and everything it ran while loading was placed by time.
422
+ await cdp.send("Page.enable").catch(() => undefined);
397
423
  this.cdpSessions.set(page, cdp);
424
+ }
398
425
  const phaseId = this.requestPhaseId();
399
426
  if (phaseId)
400
427
  await this.activatePage(page, phaseId);