Summary
Every GC-dependent test in this repository silently skips on Deno, and has for as long as the Deno
job has existed. pnpm test:deno passes --v8-flags=--expose-gc to the deno run CLI, but
vitest.config.ts selects the forks pool for Deno and Bun, and a V8 flag on Deno's command
line applies only to the process it was passed to — the forked child processes that actually run the
tests get no globalThis.gc.
Probed directly (deno 2.7.5, node:child_process.fork):
--v8-flags=--expose-gc parent gc: function child gc: undefined
DENO_V8_FLAGS=--expose-gc parent gc: function child gc: function
Node is unaffected: its pool is threads, and worker threads inherit execArgv. Bun exposes
Bun.gc() instead of a flag.
Impact
Tests guarded by it.skipIf(!globalThis.gc) never ran on Deno — they reported as skipped rather
than failed, so nothing surfaced. Affected today:
test/lib/util.ts's dbRunner also has a post-test gc() + settle delay that never ran on Deno.
Fix
Set the flag through the environment, which forked children inherit:
-"test:deno": "cross-env CI=1 deno run --allow-all --sloppy-imports --v8-flags=--expose-gc ./node_modules/vitest/vitest.mjs",
+"test:deno": "cross-env CI=1 DENO_V8_FLAGS=--expose-gc deno run --allow-all --sloppy-imports ./node_modules/vitest/vitest.mjs",
Verified locally (deno 2.7.5): full suite goes from 739 passed / 9 skipped to 748 passed /
5 skipped, with the four previously-dead GC tests running and passing.
Why this is not simply applied
Doing so on deno 2.8.3 (the version CI pins) makes two previously-hidden failures appear, so the
one-line change cannot land on its own:
Sequence: fix the withLock bug, triage the VT failure, then enable DENO_V8_FLAGS and take the
restored coverage.
Filed by KrAIs (Claude Opus 5) while fixing CI on #768.
Summary
Every GC-dependent test in this repository silently skips on Deno, and has for as long as the Deno
job has existed.
pnpm test:denopasses--v8-flags=--expose-gcto thedeno runCLI, butvitest.config.tsselects theforkspool for Deno and Bun, and a V8 flag on Deno's commandline applies only to the process it was passed to — the forked child processes that actually run the
tests get no
globalThis.gc.Probed directly (deno 2.7.5,
node:child_process.fork):Node is unaffected: its pool is
threads, and worker threads inheritexecArgv. Bun exposesBun.gc()instead of a flag.Impact
Tests guarded by
it.skipIf(!globalThis.gc)never ran on Deno — they reported as skipped ratherthan failed, so nothing surfaced. Affected today:
test/transaction-log.test.ts(three cases, including the transaction-log instance GC cleanup)test/user-shared-buffer-notify.test.tstest/transaction-orphan-gc.test.ts(added in Release a transaction dropped without commit or abort, instead of leaking its read snapshot for the life of the process #768; skips on Deno as of this issue's companionchange)
test/lib/util.ts'sdbRunneralso has a post-testgc()+ settle delay that never ran on Deno.Fix
Set the flag through the environment, which forked children inherit:
Verified locally (deno 2.7.5): full suite goes from 739 passed / 9 skipped to 748 passed /
5 skipped, with the four previously-dead GC tests running and passing.
Why this is not simply applied
Doing so on deno 2.8.3 (the version CI pins) makes two previously-hidden failures appear, so the
one-line change cannot land on its own:
test/lock.test.ts— thewithLockstall and double free, filed as withLock(): a pending lock dispatch does not keep the event loop alive — promise never settles on an idle process, double free at teardown #771. This is the blocker.test/verification-table.test.tson macOS only —a version cached before close never leaks into a later incarnation (non-resurrection)fails withexpected 134217728 not to be 134217728, i.e. astale VT slot still reports FRESH after close/reopen. Uninvestigated; may be a second latent bug or
a Deno-specific artifact.
Sequence: fix the
withLockbug, triage the VT failure, then enableDENO_V8_FLAGSand take therestored coverage.
Filed by KrAIs (Claude Opus 5) while fixing CI on #768.