From 175c0b7d54bc824d05dbe93560c7fe99241fb6b9 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Tue, 22 Sep 2026 03:27:26 -0700 Subject: [PATCH] test(heartbeat): await wake registration before advancing coalescing time Vitest waitFor advances fake timers while real SQLite-backed cron admission is still pending. Observe the second synchronous wake registration through a deferred signal before advancing the existing 250ms coalescing window. Preserve request counts, exact payloads, and both parent settlement assertions. The original failure is captured in CI; one local baseline passed. All 76 focused cases, targeted lint, and independent review pass after the fixture repair (41.32s wrapper). --- src/cron/service.heartbeat-busy-poll.test.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/cron/service.heartbeat-busy-poll.test.ts b/src/cron/service.heartbeat-busy-poll.test.ts index 5713956918ed..03d0bcc6a767 100644 --- a/src/cron/service.heartbeat-busy-poll.test.ts +++ b/src/cron/service.heartbeat-busy-poll.test.ts @@ -415,8 +415,18 @@ describe("native heartbeat busy poll settlement", () => { ); const task = "job" in added ? added.job : added; const releaseMain = await holdLane(CommandLane.Main); + const bothRequested = createDeferred(); + request.mockImplementation((opts, lifecycle) => { + const pending = requestHeartbeatAndWait({ ...opts, coalesceMs: 250 }, lifecycle); + if (request.mock.calls.length === 2) { + bothRequested.resolve(); + } + return pending; + }); const parents = [cron.run(monitor.id, "force"), cron.run(task.id, "force")]; - await vi.waitFor(() => expect(request).toHaveBeenCalledTimes(2)); + // Polling with vi.waitFor advances the coalescer while SQLite admission is still pending. + await bothRequested.promise; + expect(request).toHaveBeenCalledTimes(2); await vi.advanceTimersByTimeAsync(250); expect(runOnce).toHaveBeenCalledOnce(); expect(runOnce.mock.calls[0]?.[0]).toMatchObject({