fix(test): abort leaked watch_action_run pollers between tests #23
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/watch-leak-tests"
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
watch_action_runpollers between tests via a module-level watchers registry and a file-levelafterEachinplugin.test.ts.resetAllWatchersForTests()toruntime.tsthat aborts everyWatchersinstance's controllers; the existingsignal.abortedcheck inwatchActionRun.tshalts the loop with no further fetches."running"watcher, resets, swaps to a strict fetch mock, and asserts it is never called.beforeEach(() => {})with the realafterEachcleanup; drop the now-unusedbeforeEachimport.Why
plugin.test.ts(all located after thewatch_action_rundescribe, all asserting onfetchMock.mock.calls[0]) failed intermittently and consistently under the full suite. Every failure showed the same signature — the "Received" URL was…/actions/runs/1(the watcher's poll URL), not the failing test's own URL.watch_action_run'sexecuteis fire-and-forget (void runWatcher(...)). Two of the three watch tests never drive the run to a terminal status, and nothing aborted the resulting immortalsetTimeout(0)poll loop when the test ended. EachloadPluginmakes a freshcreateRuntime→ freshWatchers, so the leaked controller was unreachable from later tests. The leaked poller readglobalThis.fetchlive at call time (runtime.ts), so it landed in the next test's fetch mock and corruptedcalls[0]/ call counts.afterEach.Watchers.reset()already aborts every controller;watchActionRun.tscheckssignal.abortedbefore each fetch, so abort cleanly halts the loop. A file-level hook catches leaks from any test and needs no threading ofruntimeintoafterEachscope. No change to the production plugin return contract ({ tool }unchanged).runtimeon the plugin return — changes the production return contract; (b) bindingruntime.fetchatcreateRuntimecreation — defense in depth but more invasive, deferred per YAGNI since abort already stops fetches; (c) asserting on the last matching call — treats the symptom, hides real bugs.Verification
bun run typecheck: clean.bun run lint(biome check): clean (92 files).--test-name-pattern '^(?!.*watch_action_run).*$'): 492 pass, 0 fail (baseline unaffected).Out of scope
runtime.fetchat creation time (report fix #3) — deferred per YAGNI; abort isolation is sufficient.