refactor: replace mock.module test-isolation workaround with spyOn#375
Merged
Conversation
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>
Deploying archgate-cli with
|
| 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 |
Contributor
Code Coverage
Full HTML report available in workflow artifacts. Per-directory breakdown
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 bymock.restore(). To get the real implementations back, the suite had split production code intoauth-poll.tsandcredential-store-impl.ts, withauth.ts/credential-store.tsreduced 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:
auth-poll.tsback intosrc/helpers/auth.ts; delete the wrapper.credential-store-impl.tsback intosrc/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.tsnow useimport * as mod+spyOn(mod, "fn")inbeforeEach, restored viamock.restore()inafterEach.spyOnis per-test and auto-restored, and it reaches both static named-import and dynamicawait import()consumers because it mutates the single shared module instance (same pattern already used forspyOn(pathsMod, "findProjectRoot")).inquirer,node:readline) keep usingmock.module— they have no first-party real-impl tests.Test consolidation:
auth-poll.test.tsintoauth.test.ts.credential-storere-export test and move the real implementation tests intocredential-store.test.ts.Governance:
Net: 2 production files deleted, no wrapper indirection, flakiness fixed at the source.
Reviewer notes
auth.ts/credential-store.tsexport the same public API; only the file layout changed.clearCredentialssmoke test was made explicit (await expect(...).resolves.toBeUndefined()) to satisfy the newbun-test/expect-expectlint rule from main.Test plan
bun run lint(incl. newexpect-expectplugin) — cleanbun run typecheck— cleanbun run format:check— cleanbun test— 1218 pass, 0 failarchgate check— 31/31 pass