Skip to content

Give mock.module its own automatic teardown - #584

Merged
TheGreatAxios merged 1 commit into
mainfrom
cl-6967-a-mockmodule-without-teardown-leaks-across-every-later-test
Aug 23, 2026
Merged

Give mock.module its own automatic teardown#584
TheGreatAxios merged 1 commit into
mainfrom
cl-6967-a-mockmodule-without-teardown-leaks-across-every-later-test

Conversation

@TheGreatAxios

Copy link
Copy Markdown
Collaborator

Closes CL-6967.

Summary

  • Adds withMockedModule/withMockedModuleDuring in tests/helpers/mock-module.ts, which capture a module's real exports, install the mock, and register their own restore (afterAll, or immediately after a scoped call) — so a mock can no longer outlive the file that installed it.
  • Migrates every mock.module call site to the helper: tests/unit/config.test.ts, tests/unit/tui/agent-tools.test.ts, src/tools/web-search.test.ts, src/auth/oauth-scope-check.test.ts, src/auth/codex/instructions.test.ts, src/tui/provider-setup-submit.test.ts, src/tui/mouse-reporting-disabled.test.ts, src/session/state.test.ts (8 files call mock.module, not the 6 originally reported; config.test.ts restored correctly via try/finally rather than having no teardown at all, but it still benefited from moving onto the shared helper).
  • Adds an eslint no-restricted-syntax rule scoped to **/*.test.ts that rejects a bare mock.module call outside the helper, with a message pointing at the replacement. noInlineConfig is already on for this repo, so there is no per-line escape hatch.
  • Documents the hazard and the fix in AGENTS.md, next to the existing mock/restore guidance.

Why

Bun runs every test file in one process. A mock.module call with no restore of its own stays installed for the rest of the run and silently replaces the real module for every file that runs after it — producing failures in files the change never touched, invisible to tsc and to a per-file test run. This happened for real landing CL-5710 (5 failures in an untouched file, first misdiagnosed as an import cycle). Routing every mock through a helper that owns its own teardown removes the class of bug instead of relying on remembering to add afterAll.

Proof

Eslint catches a bare mock.module call:

$ bunx eslint src/leak-demo.test.ts
  3:1  error  Use withMockedModule/withMockedModuleDuring from tests/helpers/mock-module.ts instead of bare mock.module — an un-restored mock.module leaks into every test file that runs after this one  no-restricted-syntax

Removing the helper's own afterAll restore (simulating a leak that slipped past the lint rule) turns a clean full-suite run into 23 unrelated failures across files that never touch the mocked modules — confirming the helper's restore is what keeps mock.module from leaking:

5322 pass
23 fail

Restoring the helper brings the suite back to green.

Verification

  • bun run lint, bun run typecheck, and bun run build pass
  • bun run test (bun test ./src ./tests ./evals) passes clean at 5345/5345 when run without contention from other concurrent processes on this machine; under heavy unrelated machine load some timing-sensitive TUI/shell/signal tests flake on timeouts, but every flake is in a file this PR does not touch and none involve mock.module

Bun runs every test file in one process, so a mock.module call without
its own restore stays installed for the rest of the run and silently
replaces the real module for other files. Route every call through a
withMockedModule/withMockedModuleDuring helper that captures the real
module and registers its own restore, and reject bare mock.module in
test files with an eslint rule so the mistake cannot recur.
@linear-code

linear-code Bot commented Aug 23, 2026

Copy link
Copy Markdown

CL-6967

@TheGreatAxios
TheGreatAxios merged commit 319cfa1 into main Aug 23, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant