-
-
Notifications
You must be signed in to change notification settings - Fork 269
Expand file tree
/
Copy pathvitest.config.ts
More file actions
255 lines (251 loc) · 14.1 KB
/
Copy pathvitest.config.ts
File metadata and controls
255 lines (251 loc) · 14.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
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
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
import { defineConfig } from 'vitest/config';
import { resolveVitestMaxWorkers } from './scripts/lib/vitest-concurrency.ts';
import slowTestGateReporter from './scripts/vitest-slow-test-reporter.ts';
// Files that spawn a real subprocess per case. They used to run one at a time in
// their own serialized `subprocess-stub` project so broad file parallelism couldn't
// starve a spawn past its internal budget and turn it into a generic timeout.
// #1823 is now running that project's own kill criterion: un-serialized here in
// `unit-core`'s default forks pool, watched for 20 consecutive CI runs with no
// timeout-shaped failure. Revert (restore the project, restore this list to
// unit-core's exclude) the moment one appears. Still excluded from the mutation
// lane via SERIALIZED_TESTS below regardless of this experiment's outcome —
// thousands of mutant reruns times a real spawn per case is timeout noise either way.
const SUBPROCESS_STUB_TESTS: readonly string[] = [
// Stubs npx plus the package managers and spawns a real Metro dev server per case.
'src/__tests__/client-metro.test.ts',
// The SUT is the subprocess watchdog: a node subprocess per case, one hangs on purpose (#1414).
'scripts/fuzz/harness.test.ts',
// The daemon takeover test launches a branch-named daemon per case to prove
// that worktree identity does not strand the predecessor (#1545).
'src/daemon/__tests__/daemon-process-takeover.test.ts',
];
// The fuzz corpus replay, which must not run under V8 coverage instrumentation.
//
// #1824 found two causes behind `Worker exited unexpectedly`. Shape (A) — a test signalling
// a fabricated pid that landed on a sibling fork — was fixed at the source in #1854. Shape
// (B) was left open: one fork dies mid-file, alone, with no test attributed. Scanning every
// failed Coverage job across the 120 CI runs after #1854 merged found the signature five
// times, and the vanished file was this one all five (plus #1866's, so six for six) — 23% of
// Coverage failures in that window. The uninstrumented unit lane has never lost it.
//
// So the coverage run skips this project and a second, uninstrumented Vitest invocation owns
// it — see `test:coverage:ci`. That costs no coverage at all, which is measured rather than
// assumed: the cases execute out of process, which the fork's inspector session never
// instruments, so this file reports the same lines with or without it.
//
// Membership is by demonstrated failure, not by a property of the code. In particular it is
// NOT "constructs a `node:worker_threads` Worker": `session-replay-runtime-maestro.test.ts`
// does exactly that and stays in `unit-core`, instrumented and green. The proximate cause was
// never reproduced — what these entries share is an observed record of vanishing from the
// Coverage lane, and that record is the only thing that admits a file here. A new entry needs
// its own run URLs; a theory about workers is not enough.
//
// #2053: the split did not stop it — the uninstrumented second leg lost the same file six more
// times in three days. Calibrating each mechanism against this project (see the issue) showed
// that every death Node can report is reported, leaving an uncatchable signal; and the only
// thing this file did that no other file does was run adversarial parser cases inside the fork,
// on worker threads it created and terminated. They now run in a worker process
// (`scripts/fuzz/execute.ts`), where such a fault is a `crash` failure named against its input.
// This entry and the second leg it forces are the mitigation: remove both — file back to
// `unit-core`, `test:coverage:ci` back to one invocation — after 30 consecutive Coverage runs
// with no `Worker exited unexpectedly`, and reopen #2053 with the run URL if one appears first.
const FUZZ_WORKER_TESTS: readonly string[] = [
// Replays the fuzz corpus through the worker watchdog, waiting its per-case budget (#1414).
'scripts/fuzz/corpus-replay.test.ts',
];
/**
* Every test the mutation lane must not collect: a real per-case subprocess spawn is
* timeout noise under thousands of mutant reruns, independent of whether Vitest also
* serializes it — `fuzz-worker` still does; `subprocess-stub`'s former members no
* longer do (#1823). The two lists above stay module-local: this union is the whole
* cross-file surface, and the mutation lane wants exactly it.
*/
export const SERIALIZED_TESTS: readonly string[] = [...SUBPROCESS_STUB_TESTS, ...FUZZ_WORKER_TESTS];
// Imported by vitest.mutation.config.ts so the two lanes cannot drift: a guard
// added here must reach the Stryker sandbox too.
export const SETUP_FILES = [
'src/__tests__/hermetic-env-setup.ts',
'src/__tests__/hermetic-signal-setup.ts',
'src/__tests__/process-memo-setup.ts',
];
export default defineConfig({
test: {
// Redirects TMPDIR to one per-run directory for the whole invocation (all
// projects, every worker) and removes it once at the end — see the file
// for why a single global hook beats per-file cleanup here.
globalSetup: ['scripts/vitest-tmpdir-global-setup.ts'],
// Wall-clock discipline: unit tests must not wait real time. Measured
// 2026-07-04: the suite's duration was bounded by files sleeping through
// production timeout budgets. slowTestThreshold surfaces creep in local
// output; the slow-test reporter enforces the ratchet (pinned offenders
// only shrink). Isolation stays ON and pool stays forks: measured
// --no-isolate = 205s wall vs 48s (module state thrashes across files),
// threads = no change.
slowTestThreshold: 500,
// Four workers gave a worthwhile solo-run speedup without approaching
// Vitest's 11-worker default on a 12-core host. CI stays uncapped so Vitest
// derives the runner-appropriate worker count from its available CPU pool.
maxWorkers: resolveVitestMaxWorkers(),
// hermetic-env-setup clears worker-scoped device claims after every case.
// Capping explicit `test.concurrent` work at one enforces that teardown
// assumption without reducing ordinary file-level parallelism.
maxConcurrency: 1,
// Gate reporters for every lane; a `--reporter` flag would replace them, so no lane passes one.
reporters: ['default', slowTestGateReporter()],
projects: [
{
test: {
name: 'unit-core',
// Explicit script entries keep maintained conformance guards in the
// unit suite without waking every ad-hoc *.test.ts under scripts/.
include: [
'src/**/*.test.ts',
'packages/*/src/**/*.test.ts',
// The subprocess watchdog self-check (#1823): spawns a real node subprocess per
// case, one hangs on purpose (#1414). Formerly a `subprocess-stub` member; see
// SUBPROCESS_STUB_TESTS above for the kill-criterion experiment this rides.
'scripts/fuzz/harness.test.ts',
// The validation fuzz generators' expectation gates (#1781 B2): in-process, no
// subprocess or worker, so they ride the fast lane unlike their serialized siblings.
'scripts/fuzz/validation-arbitraries.test.ts',
'scripts/fuzz/validation-arbitraries-cli.test.ts',
'scripts/fuzz/validation-arbitraries-maestro.test.ts',
'scripts/fuzz/validation-case.test.ts',
'scripts/fuzz/envelope.test.ts',
'scripts/__tests__/help-conformance-bench.test.ts',
'scripts/__tests__/help-conformance-error-recovery-coverage.test.ts',
'scripts/__tests__/help-conformance-expectation-falsification.test.ts',
'scripts/__tests__/help-conformance-sample-outputs.test.ts',
'scripts/__tests__/help-conformance-topic-coverage.test.ts',
// Lives here rather than under src/ on purpose: it measures the repository's own
// files and git history, which Stryker's sandbox copy cannot answer (the copies are
// rewritten, and there is no origin/main). The mutation lane admits only root/package
// `src` tests, so this address makes it unreachable there by construction instead of
// by a classifier that has to recognise it — see KERNEL_TEST_FILE_RE in
// scripts/mutation/modules.ts.
'scripts/__tests__/test-file-size-ratchet.test.ts',
'scripts/__tests__/eager-closure-budgets.test.ts',
'scripts/__tests__/agent-setup-startup-contract.test.ts',
'scripts/__tests__/npm-skills-exclusion.test.ts',
'scripts/__tests__/simulator-skills-contract.test.ts',
// Parses ios.yml and the runner's Swift sources: no Xcode, no simulator, and
// the check it guards is what keeps the PR lane's `-only-testing:` list honest.
'scripts/__tests__/xctest-selection.test.ts',
// The nightly XCTest lane's reporter/liveness check, which otherwise only ever
// executes on a macOS runner at 04:30.
'scripts/__tests__/xctest-run-summary.test.ts',
// The Fallow fixture policy is executable configuration: unused exports are exempt,
// but fixture modules remain visible to the other analysis families.
'scripts/__tests__/fallow-fixture-policy.test.ts',
// The publishing gate's closure audit against fixture packages: parse-only, and the
// only place the gate's failure direction is exercised at all (the gate itself needs a
// real `npm pack`, so CI can only watch a healthy package pass).
'scripts/__tests__/package-closure-audit.test.ts',
// The Bundle Size lane's PR-comment path: spawns the real script against a
// stubbed fetch, so it needs no network; pins retry/reconcile/fatal outcomes.
'scripts/__tests__/size-report-post-comment.test.ts',
// Package attribution models npm-pack output. Keep it in the fast lane so every new
// package path remains accounted for.
'scripts/__tests__/size-report-package.test.ts',
// Publish preparation spawns only fixture-owned scripts and proves both Android
// helper families are rebuilt through the shared release/size-report owner.
'scripts/__tests__/prepare-publish-assets.test.ts',
'scripts/ios-snapshot-benchmark/*.test.ts',
// Parses CI configuration only, so this action guard needs no device or subprocess lane.
'test/ci/upload-agent-device-artifacts.test.ts',
'test/ci/upload-artifact-hidden-paths.test.ts',
'scripts/__tests__/diagnose-1874-iteration.test.ts',
// The size reporter is preserved across a base checkout; its entrypoint and imported
// modules must move as one directory or the Bundle Size lane fails before measuring.
'test/ci/size-workflow.test.ts',
// #1781 A9: pins the root-doc paths-ignore entries directly against the
// real workflow YAML, parse-only like its sibling above.
'test/ci/root-docs-paths-ignore.test.ts',
// The daemon leak oracle's lifecycle/residue rules (#1781 B1): pure
// decisions over fixture state-dir listings, so they need no daemon,
// device, or subprocess.
'test/integration/support/daemon-leak-model.test.ts',
// The frozen replay-compat corpus (#1417): parse-only, no device or
// subprocess work, so it belongs in the fast lane next to the
// grammar it guards.
'test/replay-compat/corpus.test.ts',
// The daemon RPC wire ledger (#1432): parses source and hashes
// declarations, so it needs no history, network, or device — the
// released-tag half runs in its own full-history job.
'test/wire-compat/wire-compat.test.ts',
'test/wire-compat/wire-mutations.test.ts',
// The Maestro conformance oracle runs via `node --test` in its own CI
// job (scripts/maestro-conformance), like the layering guard.
],
exclude: [...FUZZ_WORKER_TESTS, 'packages/platform-apple/src/runner/**/*.test.ts'],
setupFiles: SETUP_FILES,
},
},
{
test: {
// The apple-runner package's own suites: same lane semantics as
// unit-core, plus a setup that installs the real root host
// capabilities behind the package's test-host seam (R11 keeps the
// package from importing root utilities directly).
name: 'apple-runner',
include: ['packages/platform-apple/src/runner/**/*.test.ts'],
setupFiles: [...SETUP_FILES, 'scripts/vitest-apple-runner-host-setup.ts'],
},
},
{
test: {
// Serialized for the same contention reason `subprocess-stub` used to be (#1823):
// the per-case watchdog budget is real wall clock. The project exists so the
// coverage run can leave it out (see the comment above), not to run it differently.
name: 'fuzz-worker',
include: [...FUZZ_WORKER_TESTS],
setupFiles: SETUP_FILES,
fileParallelism: false,
isolate: true,
maxWorkers: 1,
},
},
{
test: {
name: 'provider-integration',
include: ['test/integration/provider-scenarios/**/*.test.ts'],
setupFiles: SETUP_FILES,
},
},
{
test: {
name: 'interaction-contract',
include: ['test/integration/interaction-contract/**/*.test.ts'],
setupFiles: SETUP_FILES,
},
},
{
test: {
name: 'output-economy',
include: ['test/output-economy/**/*.test.ts'],
setupFiles: SETUP_FILES,
},
},
],
coverage: {
provider: 'v8',
reporter: ['text', 'html', 'lcov', 'json-summary'],
thresholds: {
statements: 78,
lines: 80,
},
include: ['src/**/*.ts', 'packages/*/src/**/*.ts'],
exclude: [
'src/**/*.test.ts',
'src/**/__tests__/**',
'src/**/*-types.ts',
'src/**/types.ts',
'src/sdk/**',
'src/bin.ts',
'src/client/client-types.ts',
'src/core/interactor-types.ts',
'src/remote/remote-config.ts',
],
},
},
});