fix(tests): migrate forks config to vitest-4 top-level + restore NODE_OPTIONS

Two issues in PR #200 became obvious from the next CI run:

1. **`poolOptions.forks.execArgv` had no effect.** Vitest 4 removed
   `test.poolOptions` entirely — every key under it moved to
   top-level `test.*`. The runner emits this banner on every run:

       DEPRECATED `test.poolOptions` was removed in Vitest 4.
       All previous poolOptions are now top-level options.

   So `test.poolOptions.forks.execArgv: ['--max-old-space-size=8192']`
   was silently ignored. Move it to `test.forks.execArgv` (and
   `test.forks.singleFork`).

2. **NODE_OPTIONS got dropped when the shard step was rewritten.**
   PR #199 added `env: NODE_OPTIONS: --max-old-space-size=8192` to
   the `npm test` step; PR #200 replaced the step with `npx vitest
   run --shard X/2` but did not carry the env-var across. Combined
   with #1, the workers reverted to Node's 4 GB default and shard 2
   (58 files) still OOMs at exactly 4128 MB heap.

Restore NODE_OPTIONS on the workflow step as belt-and-braces — it
gets honored by the parent vitest process, and the migrated config
covers the forked children.

With 8 GB heap × 2 shards × 58 files each, the cumulative state
from ngspice WASM + singletons fits comfortably and the suite
should exit cleanly.
This commit is contained in:
davidmonterocrespo24 2026-05-19 18:09:34 +02:00
parent fd6f1a43f7
commit 1f23066f47
2 changed files with 23 additions and 19 deletions

View File

@ -77,11 +77,16 @@ jobs:
- name: Run tests (shard ${{ matrix.shard }}/2)
run: cd frontend && npx vitest run --shard ${{ matrix.shard }}/2
# Heap is also raised inside the vitest config via
# poolOptions.forks.execArgv — forks pool ignores
# NODE_OPTIONS. With sharding each runner only carries
# ~60 test files' worth of leaked WASM/singleton state
# so the heap stays well under the ceiling.
env:
# Belt-and-braces heap raise. The same flag is also set in
# vitest.config.ts under `forks.execArgv`, but that path was
# under the now-removed `poolOptions.forks` until the latest
# commit, and we want the workflow not to depend on the
# exact vitest config shape to keep CI green during the
# vitest 4 migration. NODE_OPTIONS gets picked up by the
# parent vitest process; the forks themselves rely on the
# config.
NODE_OPTIONS: --max-old-space-size=8192
# Production build smoke — catches Vite/Rollup-only failures that
# vitest doesn't see (chunk wiring, dynamic imports, manualChunks

View File

@ -23,21 +23,20 @@ export default defineConfig({
include: ['src/__tests__/**/*.test.ts'],
testTimeout: 30_000,
hookTimeout: 30_000,
poolOptions: {
// Vitest 4 removed `test.poolOptions` — config moved to top-level
// `forks` / `threads` / etc. See the deprecation banner the runner
// emits: "DEPRECATED test.poolOptions was removed in Vitest 4. All
// previous poolOptions are now top-level options."
//
// Each forked worker also needs its heap cap raised because the
// suite leaks state across the 117 test files (ngspice WASM ~30 MB
// per init, MixedModeScheduler singleton, zustand stores). Even
// sharded (60 files / shard) the leak overflows Node's 4 GB
// default; 8 GB plus sharding fits the runner's 16 GB budget.
forks: {
singleFork: false,
// Vitest 4's forks pool spawns workers with its own execArgv
// and does NOT inherit NODE_OPTIONS from the parent shell, so
// raising `--max-old-space-size` via the GHA env-var has no
// effect on the actual worker process. The full suite leaks
// ngspice WASM modules + singleton state across 117 files and
// hits Node's 4 GB default at the end of the run ("Worker
// exited unexpectedly / Ineffective mark-compacts near heap
// limit"). Bump to 8 GB at the pool level so it actually
// takes effect.
execArgv: ['--max-old-space-size=8192'],
},
},
coverage: {
provider: 'v8',
include: [