test(coverage): forgejo-api + cleanup tests; migrate cleanup consumers off mock.module #103
No reviewers
Labels
No labels
area:agents
area:dashboard
area:database
area:design
area:design-review
area:flows
area:infra
area:meta
area:security
area:sessions
area:webhook
area:workdir
security
type:bug
type:chore
type:meta
type:user-story
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
charles/claude-hooks!103
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "test/coverage-cleanup-forgejo-api"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Audit follow-up (from PR #102). Two untested modules flagged —
forgejo-api.ts(226 lines) andcleanup.ts(40 lines). Writingcleanup.test.tsrequired solving a Bun-specific issue first:mock.moduleis process-global, and four webhook test files mocked./cleanupto record calls, which blocked any isolated test for cleanup itself.This PR adds tests for both modules and migrates the four consumers onto a tiny test seam on
cleanup.tssomock.module("./cleanup")disappears from the codebase.Changes
src/forgejo-api.test.ts(new, 28 tests)Covers auth header / content-type / URL construction / AbortSignal timeout; happy paths for all 9 exported helpers; 404 / 403 / 500 / network error / malformed JSON / non-array response all map to documented defaults. Uses the existing fetch-spy harness — no
mock.module.src/cleanup.ts+src/cleanup.test.ts(new, 9 tests)cleanup.tsgains animplobject holding its three external dependencies (deriveIssueBranch,releaseWorktree,dropAllForIssue) plus two optional observation hooks (onCleanupIssue,onCleanupBranch,undefinedin prod). The two public functions now call throughimpl.*and fire the hooks on entry. Zero runtime cost in prod (nullish check + indirect call); no behavior change.cleanup.test.tscovers both public functions: empty-agent no-op, per-agent release + one session drop, single-agent release failure is swallowed without skipping the rest, session-drop failure doesn't throw.Consumer migration — four webhook test files
webhook.test.ts/webhook-handlers.test.ts/webhook-assign-dedup.test.ts/webhook-post-merge.test.ts— replacemock.module("./cleanup", …)with:impl.onCleanupIssue/impl.onCleanupBranchimpl.releaseWorktree/impl.dropAllForIssueto no-opsimplinafterAllso the seam stays clean for files that run afterNet result:
mock.module("./cleanup")appears zero times in the repo.Why the seam
Bun's
mock.moduleregisters in a process-global registry. Once a test file callsmock.module("./cleanup", …), every other test file that runs after sees that stub — even ones that had nothing to do with cleanup. Writing an isolatedcleanup.test.tswhile four consumers were globally replacing the module was structurally impossible without this change.The
implpattern:Test plan
just qa— 313 pass, 0 fail (+37 net new tests: 28 forgejo-api, 9 cleanup)grep -r 'mock.module("./cleanup"' src/returns no matches🤖 Generated with Claude Code
Bun's `mock.module` registers process-globally and leaks stubs to every test file that runs after. The four webhook tests all mocked ./cleanup just to record calls — which blocked any cleanup.test.ts from working at all (either no impl export, or a replaced cleanupIssue that ignored the test stubs). Fix: add a tiny test seam to cleanup.ts and move every ./cleanup test consumer onto it. - `src/cleanup.ts` adds an `impl` object holding the three external dependencies (deriveIssueBranch, releaseWorktree, dropAllForIssue) plus two optional observation hooks (onCleanupIssue, onCleanupBranch, `undefined` by default). `cleanupIssue` / `cleanupBranch` now go through `impl.*` and fire the hooks on entry. Zero runtime cost in prod (nullish-check plus indirect call); no behavior change. - `src/cleanup.test.ts` (new, 9 tests) covers both exported functions: no-op on empty agent list, per-agent release + one session drop, a single agent's release failure is swallowed without skipping the others, session-drop failure doesn't throw. - webhook.test.ts / webhook-handlers.test.ts / webhook-assign-dedup.test.ts / webhook-post-merge.test.ts: drop `mock.module("./cleanup", …)`. Observe calls via `impl.onCleanup{Issue,Branch}` and suppress the internal side-effects by swapping `impl.releaseWorktree` / `impl.dropAllForIssue` to no-ops. Each file restores `impl` in `afterAll` so the seam stays clean for subsequent files. Results: 313 pass, 0 fail (was 304 pre-refactor; +9 net new). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>test(forgejo-api): add unit tests for auth, happy paths, and error swallowingto test(coverage): forgejo-api + cleanup tests; migrate cleanup consumers off mock.module