supercov 0.0.44 → 0.0.46
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.
- package/README.md +21 -12
- package/docs/agent-loop.md +17 -9
- package/docs/assertion-agent.md +146 -0
- package/docs/assertion-evidence.md +72 -663
- package/docs/assertion-maps.md +236 -0
- package/docs/assertions.md +132 -0
- package/docs/cli.md +40 -8
- package/docs/coverage-model.md +18 -0
- package/docs/evidence.md +28 -0
- package/docs/performance.md +16 -0
- package/docs/supported-suites.md +64 -147
- package/package.json +36 -35
- package/runtime/javascript/launchSupervisor.mjs +5 -0
- package/runtime/javascript/nodeTest.mjs +57 -41
- package/runtime/javascript/provenance.mjs +4 -1
- package/runtime/javascript/register.mjs +9 -5
- package/runtime/javascript/runnerEvidence.mjs +4 -1
- package/runtime/javascript/runtime.mjs +62 -36
- package/schemas/assertions.schema.json +276 -0
- package/analyzers/typescript/README.md +0 -59
- package/analyzers/typescript/bin/compiler-identity.mjs +0 -78
- package/analyzers/typescript/bin/identity.mjs +0 -71
- package/analyzers/typescript/bin/query.mjs +0 -29
- package/analyzers/typescript/dist/analyze.js +0 -5273
- package/analyzers/typescript/dist/archive.js +0 -337
- package/analyzers/typescript/dist/awaited-observations.js +0 -376
- package/analyzers/typescript/dist/build-identity.json +0 -1
- package/analyzers/typescript/dist/compiler.js +0 -32
- package/analyzers/typescript/dist/frontend.js +0 -75
- package/analyzers/typescript/dist/mock-counts.js +0 -2517
- package/analyzers/typescript/dist/native-frontend.js +0 -271
- package/analyzers/typescript/dist/pragmas.js +0 -186
- package/analyzers/typescript/dist/types.js +0 -1
- package/analyzers/typescript/package.json +0 -27
- package/analyzers/typescript/src/analyze.ts +0 -6180
- package/analyzers/typescript/src/archive.ts +0 -471
- package/analyzers/typescript/src/awaited-observations.ts +0 -561
- package/analyzers/typescript/src/compiler.ts +0 -49
- package/analyzers/typescript/src/frontend.ts +0 -136
- package/analyzers/typescript/src/mock-counts.ts +0 -3219
- package/analyzers/typescript/src/native-frontend.ts +0 -315
- package/analyzers/typescript/src/pragmas.ts +0 -284
- package/analyzers/typescript/src/types.ts +0 -45
- package/analyzers/typescript/tsconfig.json +0 -12
- package/docs/code-verification.md +0 -4
package/docs/supported-suites.md
CHANGED
|
@@ -45,7 +45,7 @@ Supercov reports the level it actually observed. It does not guess.
|
|
|
45
45
|
| --- | --- |
|
|
46
46
|
| Playwright | Exact per test, worker, retry, outcome, action, and assertion phase |
|
|
47
47
|
| Vitest | Exact per test, with setup execution kept separate |
|
|
48
|
-
| Jest | Exact per test, including parameterized tests, with the user's own configuration, setup files and reporters kept; `expect`
|
|
48
|
+
| Jest | Exact per test, including parameterized tests, with the user's own configuration, setup files and reporters kept; passing `expect` occurrences are identified for assertion maps |
|
|
49
49
|
| `node:test` | Exact per test |
|
|
50
50
|
| AVA and Mocha | Aggregate structural coverage |
|
|
51
51
|
| Other Node-based runners | Aggregate when their processes remain visible to Supercov |
|
|
@@ -63,19 +63,15 @@ TypeScript, and TSX are supported.
|
|
|
63
63
|
Supercov instruments an isolated copy. It does not ask you to add an import,
|
|
64
64
|
reporter, plugin, or alternate build output.
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
Supercov
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
part of the run, and a `build` script is run inside the isolated copy first.
|
|
71
|
-
Without it the server under test would never exist. A launch that only names a
|
|
72
|
-
build subcommand, such as `vite build`, is not taken as consuming a build.
|
|
66
|
+
If tests import compiled output such as `dist/` or launch a script that uses it,
|
|
67
|
+
Supercov runs the project's build inside the isolated copy before testing.
|
|
68
|
+
Keep using your normal test and build commands. Instrumentation does not
|
|
69
|
+
require changing the project's TypeScript settings.
|
|
73
70
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
command builds under measurement exactly as it does without it.
|
|
71
|
+
For assertion maps, Node, Vitest, Jest and Playwright's Node-side assertions
|
|
72
|
+
supply supported passing-occurrence evidence. Custom assertion wrappers and
|
|
73
|
+
browser-side checks can have additional observation limits. See
|
|
74
|
+
[Assertion evidence](assertion-evidence.md) before interpreting a missing occurrence.
|
|
79
75
|
|
|
80
76
|
### Browsers, servers, and child processes
|
|
81
77
|
|
|
@@ -114,22 +110,16 @@ whatever was still buffered.
|
|
|
114
110
|
| cargo-nextest | Exact test, attempt, retry, and binary identity | cargo-nextest 0.9.138 or 0.9.140 |
|
|
115
111
|
|
|
116
112
|
Supercov preserves Cargo's test selection, scheduling, fail-fast behavior,
|
|
117
|
-
environment
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
included), match arms, `&&` and `||`, `for` and `while` loops and the `?`
|
|
128
|
-
operator each take a probe; what a thread recorded before it passed an
|
|
129
|
-
`assert!`, `assert_eq!` or `assert_ne!` is linked to that assertion, so the
|
|
130
|
-
report can separate code a test checked from code it merely ran; const contexts and macro expansions stay in the
|
|
131
|
-
denominator behind an explicit limitation. Use the repository's normal flags after the
|
|
132
|
-
wrapped command:
|
|
113
|
+
environment and exit status. Doctests run with their own identities; nextest
|
|
114
|
+
retries remain separate attempts.
|
|
115
|
+
|
|
116
|
+
Measured source follows the modules rustc compiles, including `#[path]` and
|
|
117
|
+
literal `include!` calls. Undeclared `.rs` files are not treated as application
|
|
118
|
+
modules. Statements, functions, branches, boolean decisions, loops and error
|
|
119
|
+
propagation are measured. Const contexts and macro expansions remain visible
|
|
120
|
+
with explicit measurement limitations.
|
|
121
|
+
|
|
122
|
+
Use the repository's normal flags after the wrapped command:
|
|
133
123
|
|
|
134
124
|
```sh
|
|
135
125
|
npx supercov -- cargo test --workspace
|
|
@@ -149,35 +139,22 @@ attribution.
|
|
|
149
139
|
| pytest-rerunfailures | Exact per attempt; flaky tests are reported as such | |
|
|
150
140
|
| `python -m unittest` | Exact test and setUp/test/tearDown phase identity | Serial in-process; skips and expected failures are recorded; subtest failures roll up to the parent test |
|
|
151
141
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
Each interpreter writes commit-framed evidence to a process-owned mmap. A hard
|
|
170
|
-
kill preserves completed observations and an incomplete tail is ignored; an
|
|
171
|
-
exhausted transport or corrupt committed frame fails the run closed.
|
|
172
|
-
|
|
173
|
-
Measured obligations are statements (including several on one line), function
|
|
174
|
-
entry, boolean decisions with MC/DC vectors, `for` and comprehension iteration,
|
|
175
|
-
`and`/`or` short-circuiting, `match` case selection, and `try` completion,
|
|
176
|
-
handler selection and exception propagation, all derived from CPython's own
|
|
177
|
-
instruction positions rather than from exception hooks.
|
|
178
|
-
|
|
179
|
-
Interpreters launched with `-I`, `-E`, or `-S` ignore `PYTHONPATH` and are not
|
|
180
|
-
measured. Code compiled from strings at runtime has no source obligations.
|
|
142
|
+
Your project runs in place with its own interpreter and virtual environment.
|
|
143
|
+
Supercov adds its monitoring and runner hooks through the process environment;
|
|
144
|
+
you do not need to rewrite tests or configure a different build.
|
|
145
|
+
|
|
146
|
+
Coverage includes statements, functions, boolean decisions, loops,
|
|
147
|
+
comprehensions, short-circuit operators, `match` cases and exception paths.
|
|
148
|
+
Child interpreters, threads and thread pools can retain the calling test's
|
|
149
|
+
identity. The report also distinguishes execution before a passing assertion
|
|
150
|
+
from later execution. These phase records alone do not prove which values the
|
|
151
|
+
assertion checks.
|
|
152
|
+
|
|
153
|
+
Interpreters launched with `-I`, `-E` or `-S` ignore the required startup hook
|
|
154
|
+
and are not measured. Code compiled from strings at runtime has no source
|
|
155
|
+
obligations. Completed observations can survive a hard kill, but a corrupt or
|
|
156
|
+
exhausted evidence channel fails the run rather than reporting partial data as
|
|
157
|
+
complete.
|
|
181
158
|
|
|
182
159
|
```sh
|
|
183
160
|
npx supercov -- pytest
|
|
@@ -197,95 +174,35 @@ npx supercov -- python -m unittest
|
|
|
197
174
|
| Thread-parallel Minitest (`parallelize_me!`, `parallelize(with: :threads)`) | Probe observations exact per test; line, method and simple-branch observations made while phases overlapped go to the run, declared | |
|
|
198
175
|
| Cucumber | Exact scenario identity (`features/x.feature:LINE`), hook steps as setup/teardown | `cucumber`, `bundle exec cucumber` |
|
|
199
176
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
On Ruby 3.4 and newer, Supercov asks the `Coverage` module for line events
|
|
230
|
-
alone. Each test phase is sampled from `Coverage`, and asking for its branch
|
|
231
|
-
and method tables too made every sample rebuild both for every loaded file,
|
|
232
|
-
gems included, which was most of what a Ruby test suite paid under Supercov.
|
|
233
|
-
Instead, the statement that starts a branch body or a method body proves the
|
|
234
|
-
branch, the method and the decision outcome it witnesses, and what has no such
|
|
235
|
-
statement is probed: an `if` without `else`, a modifier `if`, a ternary, `&.`,
|
|
236
|
-
a `case` without `else`, an empty body. Ruby 3.3 cannot apply probes and keeps
|
|
237
|
-
reading `Coverage`'s branch and method keys.
|
|
238
|
-
`if true`/`if false`/`if nil` and other literal predicates are folded the way
|
|
239
|
-
Ruby folds them: no branch, and the dead arm is not an obligation. Code inside
|
|
240
|
-
a `Ractor.new` block gets no probes: a non-main Ractor cannot read the probe
|
|
241
|
-
receiver, so a probe there would raise where the untouched program ran. Its
|
|
242
|
-
lines are still counted; what only a probe could have proven inside it is
|
|
243
|
-
declared unmeasured at the block. A Spring
|
|
244
|
-
preloader started before the run has no hook and fails closed; JRuby and
|
|
245
|
-
TruffleRuby are not supported.
|
|
246
|
-
|
|
247
|
-
The runtime loads through `RUBYOPT` before Bundler and requires only
|
|
248
|
-
`coverage`, so it never activates a gem an application's Gemfile pins
|
|
249
|
-
differently. Insertions are checked against Ruby itself by a sweep
|
|
250
|
-
(`scripts/ruby-corpus-sweep.sh`, which drives `scripts/ruby-position-sweep.rb`)
|
|
251
|
-
over Ruby's whole standard library and the Rails, Rack, RSpec, Minitest,
|
|
252
|
-
test-unit and Cucumber gems, about 4,300 files installed once into a stable
|
|
253
|
-
corpus directory: every file is transformed and compiled with its line count
|
|
254
|
-
intact, every branch key Ruby 3.3 reads is compared with what Ruby reports for
|
|
255
|
-
the untouched source, and each file is loaded twice, untouched and
|
|
256
|
-
transformed, so the probes are proven to preserve behaviour and define the
|
|
257
|
-
same methods.
|
|
258
|
-
|
|
259
|
-
A `begin` whose body ends in an expression that can `return` from inside
|
|
260
|
-
itself has its handlers and propagation measured as usual, but its normal
|
|
261
|
-
completion is declared instead of probed unless every branch of that
|
|
262
|
-
expression can carry the probe: Ruby cannot pass such an expression as an
|
|
263
|
-
argument, which is what a probe wrapper does.
|
|
264
|
-
|
|
265
|
-
Measuring never breaks the program being measured. If a file cannot be
|
|
266
|
-
compiled with its probes, it loads unmodified: Ruby's `Coverage` still
|
|
267
|
-
measures its lines, methods and own branches, and only the obligations a
|
|
268
|
-
probe would have proven are declared for that file. Setting
|
|
269
|
-
`SUPERCOV_RUBY_SKIP_PROBES` to a comma-separated list of path fragments puts
|
|
270
|
-
chosen files on that same path deliberately, which is the escape hatch if
|
|
271
|
-
instrumentation ever disagrees with one of yours.
|
|
272
|
-
|
|
273
|
-
Ruby 3.3 does not apply its `Coverage` module to code compiled by a load hook,
|
|
274
|
-
so on 3.3 Supercov measures through `Coverage` alone: lines, methods and the
|
|
275
|
-
branches Ruby reports itself. Everything that needs a probe (multi-condition
|
|
276
|
-
decisions, `||=`, loops, `rescue` flow, a second statement on a line) is
|
|
277
|
-
declared unmeasured on that interpreter rather than shown as a gap. Ruby 3.4
|
|
278
|
-
and newer measure everything.
|
|
279
|
-
|
|
280
|
-
Ruby reads its own coverage as the interpreter exits, and that shapes what a
|
|
281
|
-
stopped process keeps. A process ended by a signal it can catch—`SIGTERM`
|
|
282
|
-
from a test's teardown, `SIGINT`—unwinds through that exit and reports
|
|
283
|
-
everything it measured. A process killed with `SIGKILL`, or one that leaves
|
|
284
|
-
through `exit!`, never gets there and takes with it whatever it observed since
|
|
285
|
-
its last test boundary. Supercov cannot recover that or say which lines it
|
|
286
|
-
would have been, so the run declares that a process did not report, which
|
|
287
|
-
blocks completeness, rather than counting those lines against the code. Stop a
|
|
288
|
-
Ruby server with `SIGTERM`, or wait for it to exit, and it reports.
|
|
177
|
+
Your project runs in place with its own interpreter and bundle. Supercov loads
|
|
178
|
+
through `RUBYOPT`; application files on disk and their backtrace line numbers
|
|
179
|
+
stay unchanged. RSpec, Minitest and test-unit assertions can identify execution
|
|
180
|
+
before a passing assertion. That timing evidence alone does not show which
|
|
181
|
+
values the assertion checks.
|
|
182
|
+
|
|
183
|
+
Ruby 3.4 and newer support statement, method, branch and MC/DC measurement,
|
|
184
|
+
including loops, iterator blocks, short-circuit operators, pattern matching,
|
|
185
|
+
optional calls and exception paths. Ruby 3.3 supplies Ruby's own line, method
|
|
186
|
+
and branch coverage; obligations requiring additional instrumentation are
|
|
187
|
+
reported as measurement limits.
|
|
188
|
+
|
|
189
|
+
Some constructs have narrower coverage. Code in a non-main Ractor keeps line
|
|
190
|
+
coverage but may lack other observations. Certain nested-return expressions
|
|
191
|
+
limit normal-completion measurement. Constant predicates are folded as Ruby
|
|
192
|
+
folds them, so unreachable alternatives do not become obligations.
|
|
193
|
+
|
|
194
|
+
If a file cannot be instrumented safely, Supercov loads it unchanged and reports
|
|
195
|
+
the remaining limits. To apply that fallback to a known incompatible file, set
|
|
196
|
+
`SUPERCOV_RUBY_SKIP_PROBES` to a comma-separated list of path fragments. This
|
|
197
|
+
reduces measurement; it is not a way to claim that skipped obligations are covered.
|
|
198
|
+
|
|
199
|
+
A Spring preloader started before the run has no coverage hook. Restart it
|
|
200
|
+
within the measured command. JRuby and TruffleRuby are not supported.
|
|
201
|
+
|
|
202
|
+
Stop test-owned Ruby servers with `SIGTERM` or wait for normal exit so they can
|
|
203
|
+
report their evidence. `SIGKILL` and `exit!` can lose observations since the last
|
|
204
|
+
test boundary. A process that does not report leaves a measurement limit; its
|
|
205
|
+
missing evidence is not counted as uncovered application code.
|
|
289
206
|
|
|
290
207
|
```sh
|
|
291
208
|
npx supercov -- rspec
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "supercov",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "Coverage for coding agents and software factories
|
|
3
|
+
"version": "0.0.46",
|
|
4
|
+
"description": "Coverage for coding agents and software factories \ud83c\udf19",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -15,22 +15,21 @@
|
|
|
15
15
|
"files": [
|
|
16
16
|
"bin",
|
|
17
17
|
"runtime/javascript",
|
|
18
|
-
"docs",
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"analyzers/typescript/README.md",
|
|
18
|
+
"docs/getting-started.md",
|
|
19
|
+
"docs/agent-loop.md",
|
|
20
|
+
"docs/assertions.md",
|
|
21
|
+
"docs/assertion-evidence.md",
|
|
22
|
+
"docs/assertion-maps.md",
|
|
23
|
+
"docs/assertion-agent.md",
|
|
24
|
+
"docs/troubleshooting.md",
|
|
25
|
+
"docs/cli.md",
|
|
26
|
+
"docs/coverage-model.md",
|
|
27
|
+
"docs/evidence.md",
|
|
28
|
+
"docs/supported-suites.md",
|
|
29
|
+
"docs/verification.md",
|
|
30
|
+
"docs/performance.md",
|
|
31
|
+
"docs/workspace-isolation.md",
|
|
32
|
+
"schemas",
|
|
34
33
|
"README.md"
|
|
35
34
|
],
|
|
36
35
|
"engines": {
|
|
@@ -49,7 +48,6 @@
|
|
|
49
48
|
},
|
|
50
49
|
"scripts": {
|
|
51
50
|
"build": "cargo build -p supercov",
|
|
52
|
-
"build:asserted-typescript": "npm --prefix analyzers/typescript run build",
|
|
53
51
|
"sync:rust-assets": "node scripts/sync-rust-package-assets.mjs",
|
|
54
52
|
"test:rust-assets": "node scripts/sync-rust-package-assets.mjs --check",
|
|
55
53
|
"check:rustc-backend-spike": "(cd spikes/rustc-backend && RUSTC_BOOTSTRAP=1 RUSTUP_TOOLCHAIN=1.95.0 cargo fmt --check && RUSTC_BOOTSTRAP=1 RUSTUP_TOOLCHAIN=1.95.0 cargo clippy --all-targets -- -D warnings)",
|
|
@@ -57,11 +55,8 @@
|
|
|
57
55
|
"test:rust-compiler-spikes": "cargo build -p supercov && node scripts/rust-libtest-companion-spike.mjs && node scripts/rust-async-attribution-spike.mjs && node scripts/rust-subprocess-attribution-spike.mjs && node scripts/rust-custom-harness-spike.mjs && node scripts/rust-libtest-builder-lifecycle-spike.mjs",
|
|
58
56
|
"test": "cargo test --workspace",
|
|
59
57
|
"test:runtime": "node --test tests/runtime/*.test.mjs",
|
|
60
|
-
"test:asserted-typescript": "npm --prefix analyzers/typescript test",
|
|
61
|
-
"test:asserted-integration": "cargo build -p supercov && npm --prefix analyzers/typescript run build && SUPERCOV_ASSERTED_INTEGRATION=1 node --test analyzers/typescript/tests/archive.integration.test.mjs",
|
|
62
|
-
"test:asserted-package": "cargo build -p supercov && npm run build:asserted-typescript && node scripts/asserted-packed-integration.mjs",
|
|
63
58
|
"test:fixture": "cargo build -p supercov && node scripts/rust-fixture-matrix.mjs",
|
|
64
|
-
"test:packed-npx": "cargo build --release -p supercov &&
|
|
59
|
+
"test:packed-npx": "cargo build --release -p supercov && node scripts/packed-npx-integration.mjs",
|
|
65
60
|
"test:isolation": "cargo build -p supercov && node scripts/isolation-integration.mjs",
|
|
66
61
|
"test:filesystem": "cargo test --workspace && cargo build -p supercov && node scripts/workspace-crash-integration.mjs",
|
|
67
62
|
"test:watchdog": "cargo build -p supercov && node scripts/watchdog-integration.mjs",
|
|
@@ -69,7 +64,7 @@
|
|
|
69
64
|
"test:agent": "cargo build -p supercov && node scripts/agent-query-eval.mjs",
|
|
70
65
|
"test:engine": "cargo fmt --all -- --check && cargo clippy --workspace --all-targets -- -D warnings && cargo test --workspace && cargo build -p supercov && npm run test:runtime && npm run test:rust-assets && node scripts/rust-process-supervision.mjs && node scripts/rust-direct-node-integration.mjs && node scripts/rust-public-run-integration.mjs && node scripts/rust-embedded-runtime-integration.mjs && node scripts/rust-direct-vitest-integration.mjs && node scripts/rust-direct-jest-integration.mjs && node scripts/rust-direct-playwright-integration.mjs && node scripts/rust-custom-browser-playwright-integration.mjs && node scripts/rust-generic-esbuild-integration.mjs && node scripts/rust-generic-tsc-integration.mjs && node scripts/rust-generic-build-matrix.mjs && node scripts/rust-vite-playwright-integration.mjs",
|
|
71
66
|
"test:platform": "cargo test --workspace && cargo build -p supercov && node scripts/rust-process-supervision.mjs && node scripts/workspace-crash-integration.mjs",
|
|
72
|
-
"test:native-package": "cargo build --release -p supercov &&
|
|
67
|
+
"test:native-package": "cargo build --release -p supercov && node scripts/native-package-integration.mjs && node scripts/native-release-set-integration.mjs",
|
|
73
68
|
"test:pypi-wheel": "node scripts/pypi-wheel-integration.mjs",
|
|
74
69
|
"test:pypi-registry": "node scripts/pypi-registry-integration.mjs",
|
|
75
70
|
"build:rubygem": "cargo build --release -p supercov && node scripts/build-rubygem.mjs",
|
|
@@ -80,28 +75,33 @@
|
|
|
80
75
|
"test:test262": "cargo build --release -p supercov && node scripts/test262-equivalence.mjs",
|
|
81
76
|
"benchmark:check": "cargo build --release -p supercov && node scripts/rust-transform-benchmark.mjs",
|
|
82
77
|
"benchmark:python-monitoring": "cargo build -p supercov && node scripts/python-monitoring-benchmark.mjs",
|
|
83
|
-
"check": "cargo fmt --all -- --check && cargo clippy --workspace --all-targets -- -D warnings && npm run test && npm run test:runtime && npm run test:rust-assets && npm run test:
|
|
78
|
+
"check": "cargo fmt --all -- --check && cargo clippy --workspace --all-targets -- -D warnings && npm run test && npm run test:runtime && npm run test:rust-assets && npm run test:assertion-maps && node scripts/package-preflight.mjs && node scripts/verify-binstall-metadata.mjs --offline",
|
|
84
79
|
"release:check": "cargo clean && node scripts/sweep-target.mjs && npm run check && npm run test:engine && npm run test:fixture && npm run test:watchdog && npm run test:engine-contract && npm run test:agent && npm run test:child-attribution && npm run test:host-loader && npm run test:python-monitoring && npm run test:ruby-coverage && npm run test:rust-public-cargo && npm run test:packed-npx && npm run test:clang-mcdc && npm run benchmark:check",
|
|
85
80
|
"release:bump": "node scripts/bump-version.mjs",
|
|
86
81
|
"sweep": "node scripts/sweep-target.mjs",
|
|
87
82
|
"oracle:rust": "cargo build --release -p supercov && node scripts/rust-coverage-oracle.mjs",
|
|
88
|
-
"prepack": "
|
|
83
|
+
"prepack": "node scripts/package-preflight.mjs",
|
|
89
84
|
"prepublishOnly": "npm run release:check",
|
|
90
85
|
"test:child-attribution": "cargo build -p supercov && node scripts/rust-child-attribution-integration.mjs",
|
|
91
86
|
"test:host-loader": "cargo build -p supercov && node scripts/rust-host-loader-integration.mjs",
|
|
92
87
|
"test:python-monitoring": "cargo build -p supercov && node scripts/python-monitoring-integration.mjs",
|
|
93
88
|
"test:ruby-coverage": "cargo build -p supercov && node scripts/ruby-coverage-integration.mjs",
|
|
94
|
-
"test:rust-public-cargo": "cargo build -p supercov && node scripts/rust-public-cargo-integration.mjs"
|
|
89
|
+
"test:rust-public-cargo": "cargo build -p supercov && node scripts/rust-public-cargo-integration.mjs",
|
|
90
|
+
"test:assertion-maps": "cargo build -p supercov && node scripts/assertion-map-schema.mjs --check && node scripts/assertion-map-integration.mjs && node scripts/assertion-map-js-integration.mjs && node scripts/assertion-dogfood-integration.mjs",
|
|
91
|
+
"test:assertion-maps:js": "cargo build -p supercov && node scripts/assertion-map-schema.mjs --check && node scripts/assertion-map-js-integration.mjs && node scripts/assertion-dogfood-integration.mjs",
|
|
92
|
+
"sync:assertion-schema": "cargo build -p supercov && node scripts/assertion-map-schema.mjs",
|
|
93
|
+
"docs:sync": "node scripts/sync-docs.mjs",
|
|
94
|
+
"docs:check": "node scripts/sync-docs.mjs --check"
|
|
95
95
|
},
|
|
96
96
|
"optionalDependencies": {
|
|
97
|
-
"@supercov/cli-darwin-arm64": "0.0.
|
|
98
|
-
"@supercov/cli-darwin-x64": "0.0.
|
|
99
|
-
"@supercov/cli-linux-arm64-gnu": "0.0.
|
|
100
|
-
"@supercov/cli-linux-arm64-musl": "0.0.
|
|
101
|
-
"@supercov/cli-linux-x64-gnu": "0.0.
|
|
102
|
-
"@supercov/cli-linux-x64-musl": "0.0.
|
|
103
|
-
"@supercov/cli-win32-arm64": "0.0.
|
|
104
|
-
"@supercov/cli-win32-x64": "0.0.
|
|
97
|
+
"@supercov/cli-darwin-arm64": "0.0.46",
|
|
98
|
+
"@supercov/cli-darwin-x64": "0.0.46",
|
|
99
|
+
"@supercov/cli-linux-arm64-gnu": "0.0.46",
|
|
100
|
+
"@supercov/cli-linux-arm64-musl": "0.0.46",
|
|
101
|
+
"@supercov/cli-linux-x64-gnu": "0.0.46",
|
|
102
|
+
"@supercov/cli-linux-x64-musl": "0.0.46",
|
|
103
|
+
"@supercov/cli-win32-arm64": "0.0.46",
|
|
104
|
+
"@supercov/cli-win32-x64": "0.0.46"
|
|
105
105
|
},
|
|
106
106
|
"peerDependencies": {
|
|
107
107
|
"@playwright/test": ">=1.55.0",
|
|
@@ -125,6 +125,7 @@
|
|
|
125
125
|
"@types/node": "^24.0.0",
|
|
126
126
|
"esbuild": "^0.28.2",
|
|
127
127
|
"expect": "30.4.1",
|
|
128
|
+
"jest": "30.5.1",
|
|
128
129
|
"next": "^16.3.2",
|
|
129
130
|
"react": "^19.2.4",
|
|
130
131
|
"react-dom": "^19.2.4",
|
|
@@ -578,6 +578,11 @@ function injectChildEnvironment(method, args) {
|
|
|
578
578
|
const environment = existingEnvironment
|
|
579
579
|
? { ...existingEnvironment, ...inherited }
|
|
580
580
|
: { ...process.env, ...inherited };
|
|
581
|
+
// The runtime child wrapper has captured the current async test scope in
|
|
582
|
+
// these options. An inherited setup/unscoped carrier from the launcher
|
|
583
|
+
// must not overwrite it when we restore the other coverage variables.
|
|
584
|
+
if (existingEnvironment?.SUPERCOV_CONTEXT !== undefined)
|
|
585
|
+
environment.SUPERCOV_CONTEXT = existingEnvironment.SUPERCOV_CONTEXT;
|
|
581
586
|
// The register path must come from THIS module's own location, never from
|
|
582
587
|
// the environment or the working directory. Monorepo runners both defeat
|
|
583
588
|
// the old derivation at once: turbo's strict env strips SUPERCOV_PROJECT_ROOT
|
|
@@ -87,7 +87,7 @@ function restoreUserError(error, depth = 0) {
|
|
|
87
87
|
return error;
|
|
88
88
|
}
|
|
89
89
|
const registrationCounts = new Map();
|
|
90
|
-
function wrappedRegistration(original, parentTestId) {
|
|
90
|
+
function wrappedRegistration(original, parentTestId, forcedStatus) {
|
|
91
91
|
const wrapped = function supercovNodeTest(...args) {
|
|
92
92
|
const index = callbackIndex(args);
|
|
93
93
|
if (index < 0)
|
|
@@ -115,13 +115,15 @@ function wrappedRegistration(original, parentTestId) {
|
|
|
115
115
|
const scope = runnerExecutionScope(identity);
|
|
116
116
|
const options = testOptions(args, index);
|
|
117
117
|
const evidenceDirectory = process.env["SUPERCOV_EVIDENCE_DIR"];
|
|
118
|
+
if (options?.skip || options?.todo || forcedStatus)
|
|
119
|
+
writeRunnerEvidence(identity, "skipped", scope, evidenceDirectory);
|
|
118
120
|
const next = [...args];
|
|
119
121
|
const execute = (callbackThis, context, done) => {
|
|
120
122
|
// A test or its hooks may intentionally modify Supercov's public
|
|
121
123
|
// environment while testing integrations. Keep this attempt's transport
|
|
122
124
|
// destination fixed to the value present when the test was registered.
|
|
123
125
|
beginBufferedServerEvidence(scope);
|
|
124
|
-
let status = options?.skip || options?.todo
|
|
126
|
+
let status = options?.skip || options?.todo || forcedStatus
|
|
125
127
|
? "skipped"
|
|
126
128
|
: "passed";
|
|
127
129
|
const contextProxy = new Proxy(context, {
|
|
@@ -138,6 +140,8 @@ function wrappedRegistration(original, parentTestId) {
|
|
|
138
140
|
}
|
|
139
141
|
if (property === "test" && typeof value === "function")
|
|
140
142
|
return wrappedRegistration(value.bind(target), scope.testId);
|
|
143
|
+
if (["after", "before", "afterEach", "beforeEach"].includes(property) && typeof value === "function")
|
|
144
|
+
return restoringHook(value.bind(target), scope);
|
|
141
145
|
return typeof value === "function" ? value.bind(target) : value;
|
|
142
146
|
},
|
|
143
147
|
});
|
|
@@ -149,6 +153,11 @@ function wrappedRegistration(original, parentTestId) {
|
|
|
149
153
|
const flushedServerEvidence = flushBufferedServerEvidence(scope);
|
|
150
154
|
writeRunnerEvidence(identity, nextStatus, scope, evidenceDirectory, takeNodeAssertionPhases(scope), flushedServerEvidence);
|
|
151
155
|
};
|
|
156
|
+
const finishBody = () => {
|
|
157
|
+
// User t.after callbacks run after the body. Register last so
|
|
158
|
+
// their assertions and cleanup probes are part of this attempt.
|
|
159
|
+
context.after(() => emit());
|
|
160
|
+
};
|
|
152
161
|
try {
|
|
153
162
|
if (callback.length >= 2) {
|
|
154
163
|
const callbackDone = (error) => {
|
|
@@ -156,7 +165,7 @@ function wrappedRegistration(original, parentTestId) {
|
|
|
156
165
|
status = "failed";
|
|
157
166
|
restoreUserError(error);
|
|
158
167
|
}
|
|
159
|
-
|
|
168
|
+
finishBody();
|
|
160
169
|
done?.(error);
|
|
161
170
|
};
|
|
162
171
|
return withCoverageCarrier({ version: 1, scope }, () => Reflect.apply(callback, callbackThis, [contextProxy, callbackDone]));
|
|
@@ -164,19 +173,19 @@ function wrappedRegistration(original, parentTestId) {
|
|
|
164
173
|
const result = withCoverageCarrier({ version: 1, scope }, () => Reflect.apply(callback, callbackThis, [contextProxy]));
|
|
165
174
|
if (result && typeof result.then === "function")
|
|
166
175
|
return Promise.resolve(result).then((value) => {
|
|
167
|
-
|
|
176
|
+
finishBody();
|
|
168
177
|
return value;
|
|
169
178
|
}, (error) => {
|
|
170
179
|
status = "failed";
|
|
171
|
-
|
|
180
|
+
finishBody();
|
|
172
181
|
throw restoreUserError(error);
|
|
173
182
|
});
|
|
174
|
-
|
|
183
|
+
finishBody();
|
|
175
184
|
return result;
|
|
176
185
|
}
|
|
177
186
|
catch (error) {
|
|
178
187
|
status = "failed";
|
|
179
|
-
|
|
188
|
+
finishBody();
|
|
180
189
|
throw restoreUserError(error);
|
|
181
190
|
}
|
|
182
191
|
};
|
|
@@ -200,45 +209,52 @@ function wrappedRegistration(original, parentTestId) {
|
|
|
200
209
|
Object.defineProperty(wrapped, property, {
|
|
201
210
|
configurable: true,
|
|
202
211
|
enumerable: true,
|
|
203
|
-
value: wrappedRegistration(member, parentTestId),
|
|
212
|
+
value: wrappedRegistration(member, parentTestId, property === "only" ? undefined : "skipped"),
|
|
204
213
|
});
|
|
205
214
|
}
|
|
206
215
|
return wrapped;
|
|
207
216
|
}
|
|
208
|
-
//
|
|
209
|
-
//
|
|
210
|
-
//
|
|
211
|
-
function restoringHook(original) {
|
|
217
|
+
// Shared hooks get their own setup scope. Their execution is visible but is
|
|
218
|
+
// never silently copied into every test. t.after and other per-test hooks keep
|
|
219
|
+
// the exact owning attempt supplied by the TestContext proxy.
|
|
220
|
+
function restoringHook(original, scope, hookName = "hook") {
|
|
212
221
|
return function supercovNodeTestHook(...args) {
|
|
213
222
|
const index = callbackIndex(args);
|
|
214
|
-
if (index < 0)
|
|
215
|
-
return Reflect.apply(original, this, args);
|
|
223
|
+
if (index < 0) return Reflect.apply(original, this, args);
|
|
216
224
|
const callback = args[index];
|
|
225
|
+
const location = callerLocation(supercovNodeTestHook);
|
|
226
|
+
let invocation = 0;
|
|
227
|
+
const execute = (receiver, context, done) => {
|
|
228
|
+
const identity = { runner: "node:test", role: "setup", name: `[${hookName}] ${callback.name || "anonymous"}`,
|
|
229
|
+
...location, registrationOrdinal: invocation++ };
|
|
230
|
+
const owner = scope ?? runnerExecutionScope(identity);
|
|
231
|
+
const evidenceDirectory = process.env["SUPERCOV_EVIDENCE_DIR"];
|
|
232
|
+
if (!scope) beginBufferedServerEvidence(owner);
|
|
233
|
+
let emitted = false;
|
|
234
|
+
const finish = error => {
|
|
235
|
+
if (scope || emitted) return;
|
|
236
|
+
emitted = true;
|
|
237
|
+
writeRunnerEvidence(identity, error ? "failed" : "passed", owner, evidenceDirectory,
|
|
238
|
+
takeNodeAssertionPhases(owner), flushBufferedServerEvidence(owner));
|
|
239
|
+
};
|
|
240
|
+
try {
|
|
241
|
+
const result = withCoverageCarrier({ version: 1, scope: owner }, () =>
|
|
242
|
+
callback.length >= 2 ? callback.call(receiver, context, error => {
|
|
243
|
+
finish(error);
|
|
244
|
+
done?.(error ? restoreUserError(error) : undefined);
|
|
245
|
+
}) : callback.call(receiver, context));
|
|
246
|
+
if (callback.length >= 2) return result;
|
|
247
|
+
if (result && typeof result.then === "function")
|
|
248
|
+
return Promise.resolve(result).then(value => { finish(); return value; },
|
|
249
|
+
error => { finish(error); throw restoreUserError(error); });
|
|
250
|
+
finish();
|
|
251
|
+
return result;
|
|
252
|
+
} catch (error) { finish(error); throw restoreUserError(error); }
|
|
253
|
+
};
|
|
217
254
|
const next = [...args];
|
|
218
|
-
// node:test uses callback arity to distinguish promise/synchronous
|
|
219
|
-
// hooks from the legacy done-callback form. Preserve it exactly.
|
|
220
255
|
next[index] = callback.length >= 2
|
|
221
|
-
? function supercovNodeTestHookDoneCallback(context, done) {
|
|
222
|
-
|
|
223
|
-
if (error)
|
|
224
|
-
restoreUserError(error);
|
|
225
|
-
done?.(error);
|
|
226
|
-
};
|
|
227
|
-
return callback.call(this, context, restoringDone);
|
|
228
|
-
}
|
|
229
|
-
: function supercovNodeTestHookCallback(context) {
|
|
230
|
-
try {
|
|
231
|
-
const result = callback.call(this, context);
|
|
232
|
-
if (result && typeof result.then === "function")
|
|
233
|
-
return Promise.resolve(result).then(undefined, (error) => {
|
|
234
|
-
throw restoreUserError(error);
|
|
235
|
-
});
|
|
236
|
-
return result;
|
|
237
|
-
}
|
|
238
|
-
catch (error) {
|
|
239
|
-
throw restoreUserError(error);
|
|
240
|
-
}
|
|
241
|
-
};
|
|
256
|
+
? function supercovNodeTestHookDoneCallback(context, done) { return execute(this, context, done); }
|
|
257
|
+
: function supercovNodeTestHookCallback(context) { return execute(this, context); };
|
|
242
258
|
return Reflect.apply(original, this, next);
|
|
243
259
|
};
|
|
244
260
|
}
|
|
@@ -246,10 +262,10 @@ export const test = wrappedRegistration(native.test);
|
|
|
246
262
|
export const it = wrappedRegistration(native.it);
|
|
247
263
|
export const suite = native.suite;
|
|
248
264
|
export const describe = native.describe;
|
|
249
|
-
export const before = restoringHook(native.before);
|
|
250
|
-
export const after = restoringHook(native.after);
|
|
251
|
-
export const beforeEach = restoringHook(native.beforeEach);
|
|
252
|
-
export const afterEach = restoringHook(native.afterEach);
|
|
265
|
+
export const before = restoringHook(native.before, undefined, "before");
|
|
266
|
+
export const after = restoringHook(native.after, undefined, "after");
|
|
267
|
+
export const beforeEach = restoringHook(native.beforeEach, undefined, "beforeEach");
|
|
268
|
+
export const afterEach = restoringHook(native.afterEach, undefined, "afterEach");
|
|
253
269
|
export const mock = native.mock;
|
|
254
270
|
export const snapshot = native.snapshot;
|
|
255
271
|
export const run = native.run;
|
|
@@ -7,7 +7,10 @@ const NORMALIZED_KINDS = [
|
|
|
7
7
|
function classifiedKind(value) {
|
|
8
8
|
if (!value)
|
|
9
9
|
return undefined;
|
|
10
|
-
|
|
10
|
+
// gatewayE2e.test.ts and responseIntegration.test.ts are conventional
|
|
11
|
+
// camel-case paths too. Do not infer kinds from test titles or API usage.
|
|
12
|
+
const words = value.replace(/([a-z0-9])([A-Z])/g, "$1-$2");
|
|
13
|
+
return NORMALIZED_KINDS.find(([, pattern]) => pattern.test(words))?.[0];
|
|
11
14
|
}
|
|
12
15
|
export function inferTestProvenance({ runner, file, project, explicitKind, }) {
|
|
13
16
|
if (explicitKind?.trim()) {
|
|
@@ -69,17 +69,21 @@ if (verboseDiagnostics && !process.__SUPERCOV_DIAGNOSTIC_REPORTER__) {
|
|
|
69
69
|
});
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
//
|
|
75
|
-
|
|
76
|
-
|
|
72
|
+
// Direct instrumentation must initialize the collector before script files
|
|
73
|
+
// with no import boundary evaluate. Other modes let the runner adapter or an
|
|
74
|
+
// instrumented module load it, except when durable remote evidence requires it.
|
|
75
|
+
if (process.env.SUPERCOV_DURABLE_EVIDENCE_EACH_TEST === "1" ||
|
|
76
|
+
process.env.SUPERCOV_DIRECT_INSTRUMENTATION === "1") {
|
|
77
77
|
// A translated remote/VM command can execute an ahead-of-run transformed
|
|
78
78
|
// test through an opaque runner that bypasses the ordinary Playwright or
|
|
79
79
|
// node:test import boundary. The remote-launch adapter marks that process;
|
|
80
80
|
// initialize the runtime before its transformed module can evaluate.
|
|
81
81
|
globalThis.__SUPERCOV_DIRECT_RUNTIME__ ??= await import("./runtime.mjs");
|
|
82
82
|
process.__SUPERCOV_DIRECT_RUNTIME__ ??= globalThis.__SUPERCOV_DIRECT_RUNTIME__;
|
|
83
|
+
// Generic builds can contain script files with no import/export syntax.
|
|
84
|
+
// They cannot import the collector without changing their module semantics,
|
|
85
|
+
// and may evaluate before any ESM instrumented file imports it.
|
|
86
|
+
globalThis.__supercovRuntime ??= globalThis.__SUPERCOV_DIRECT_RUNTIME__;
|
|
83
87
|
}
|
|
84
88
|
// Workers are independent Node processes and an explicit `execArgv: []`
|
|
85
89
|
// otherwise strips the preload that supplies the isolated runtime. Preserve
|