fix(browser): canceled settled scroll timers

- Replaced the losing Bun.sleep with an unrefed timeout cleared in a finally block.
- Added regression coverage that verifies prompt wheel acknowledgements leave no timer behind.

Fixes #5905
This commit is contained in:
roboomp
2026-07-17 20:10:01 +00:00
parent b8ef46a0c8
commit 4e216a3b98
2 changed files with 22 additions and 2 deletions
@@ -182,7 +182,14 @@ export async function dispatchScroll(
dispatch: () => Promise<void>,
ackTimeoutMs = SCROLL_ACK_TIMEOUT_MS,
): Promise<void> {
await Promise.race([dispatch(), Bun.sleep(ackTimeoutMs)]);
const deadline = Promise.withResolvers<void>();
const timer = setTimeout(() => deadline.resolve(), ackTimeoutMs);
timer.unref();
try {
await Promise.race([dispatch(), deadline.promise]);
} finally {
clearTimeout(timer);
}
}
/**
@@ -1,4 +1,4 @@
import { describe, expect, it } from "bun:test";
import { describe, expect, it, vi } from "bun:test";
import { resolvePredicateTimeout } from "@oh-my-pi/pi-coding-agent/tools/browser/run-cancellation";
import {
dispatchScroll,
@@ -55,6 +55,19 @@ describe("browser scroll acknowledgement", () => {
"target closed",
);
});
it("cancels the acknowledgement deadline after a prompt dispatch", async () => {
vi.useFakeTimers();
try {
const timerCount = vi.getTimerCount();
await dispatchScroll(() => Promise.resolve());
expect(vi.getTimerCount()).toBe(timerCount);
} finally {
vi.useRealTimers();
}
});
});
describe("browser wait-helper timeout resolution", () => {