Skip to content

refactor: replace mock.module test-isolation workaround with spyOn#375

Merged
rhuanbarreto merged 1 commit into
mainfrom
claude/vigorous-tu-d4f052
May 28, 2026
Merged

refactor: replace mock.module test-isolation workaround with spyOn#375
rhuanbarreto merged 1 commit into
mainfrom
claude/vigorous-tu-d4f052

Conversation

@rhuanbarreto

Copy link
Copy Markdown
Contributor

Summary

Removes an inelegant flakiness workaround introduced in #356 and fixes the root cause instead.

Bun's mock.module() is process-global and retroactive — once a test file mocks a first-party module path, that mock replaces the module for every test file in the same Bun process and is not undone by mock.restore(). To get the real implementations back, the suite had split production code into auth-poll.ts and credential-store-impl.ts, with auth.ts / credential-store.ts reduced to thin delegating wrappers — purely so the "real" tests could import an un-mocked path. That isolation depended on test-file execution order, which was the actual source of the flakiness, and it contorted the production module layout to serve a test-tool quirk.

What changed

Production — undo the test-driven split:

  • Merge auth-poll.ts back into src/helpers/auth.ts; delete the wrapper.
  • Merge credential-store-impl.ts back into src/helpers/credential-store.ts; delete the wrapper.

Tests — convert the three leaky mockers to spyOn:

  • login-flow.test.ts, init-project.test.ts, plugin/install.test.ts now use import * as mod + spyOn(mod, "fn") in beforeEach, restored via mock.restore() in afterEach. spyOn is per-test and auto-restored, and it reaches both static named-import and dynamic await import() consumers because it mutates the single shared module instance (same pattern already used for spyOn(pathsMod, "findProjectRoot")).
  • Third-party mocks (inquirer, node:readline) keep using mock.module — they have no first-party real-impl tests.

Test consolidation:

  • Fold auth-poll.test.ts into auth.test.ts.
  • Drop the stub credential-store re-export test and move the real implementation tests into credential-store.test.ts.

Governance:

  • Document the rule in ARCH-005 (DO/DON'T, good/bad example, compliance checklist item) so the workaround does not reappear.

Net: 2 production files deleted, no wrapper indirection, flakiness fixed at the source.

Reviewer notes

  • No production behavior change — auth.ts / credential-store.ts export the same public API; only the file layout changed.
  • The assertion-less clearCredentials smoke test was made explicit (await expect(...).resolves.toBeUndefined()) to satisfy the new bun-test/expect-expect lint rule from main.

Test plan

  • bun run lint (incl. new expect-expect plugin) — clean
  • bun run typecheck — clean
  • bun run format:check — clean
  • bun test — 1218 pass, 0 fail
  • archgate check — 31/31 pass

Bun's mock.module() is process-global and retroactive: once a test file
mocks a first-party module path, that mock replaces the module for every
test file in the same process and is not undone by mock.restore(). To get
the real implementations, the suite had split production code into
auth-poll.ts and credential-store-impl.ts, with auth.ts/credential-store.ts
reduced to thin delegating wrappers, purely so the "real" tests could import
an un-mocked path. The isolation depended on test-file execution order,
which is the actual source of the flakiness.

Fix the root cause instead of contorting the module layout:

- Merge auth-poll.ts back into auth.ts and credential-store-impl.ts back
  into credential-store.ts; delete the wrapper files.
- Convert the three leaky mockers (login-flow, init-project, plugin/install)
  from mock.module() to `import * as mod` + spyOn in beforeEach, restored via
  mock.restore() in afterEach. spyOn is per-test and auto-restored, and it
  reaches both static named-import and dynamic `await import()` consumers
  because it mutates the single shared module instance (same pattern already
  used for pathsMod.findProjectRoot). Third-party mocks (inquirer,
  node:readline) keep using mock.module.
- Consolidate tests: fold auth-poll.test.ts into auth.test.ts; drop the stub
  credential-store re-export test and move the real impl tests into
  credential-store.test.ts.
- Document the rule in ARCH-005 (DO/DON'T, good/bad example, compliance
  item) so the workaround does not reappear.

Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying archgate-cli with  Cloudflare Pages  Cloudflare Pages

Latest commit: f6d0eb8
Status: ✅  Deploy successful!
Preview URL: https://17228262.archgate-cli.pages.dev
Branch Preview URL: https://claude-vigorous-tu-d4f052.archgate-cli.pages.dev

View logs

@github-actions

Copy link
Copy Markdown
Contributor

Code Coverage

Metric Value
Lines 90.2% (6575 / 7289)
Threshold 90% minimum — met
Platforms Linux + Windows

Full HTML report available in workflow artifacts.

Per-directory breakdown
Directory Coverage Lines
src/commands/ 88.0% 2082 / 2365
src/engine/ 92.9% 1219 / 1312
src/formats/ 100.0% 141 / 141
src/helpers/ 90.3% 3133 / 3471

@rhuanbarreto rhuanbarreto merged commit 6e6564d into main May 28, 2026
18 checks passed
@rhuanbarreto rhuanbarreto deleted the claude/vigorous-tu-d4f052 branch May 28, 2026 23:40
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