Skip to content

Commit 9f1c140

Browse files
ryansolidClaude via Cursor
andcommitted
test(signals): judge UNTRACKED_ASYNC_HANDLER's threshold on a test-owned clock
"stays quiet below the hold threshold, and info between the two" raced the wall clock: a 1ms `await` had to settle under `infoMs: 10`, and on the coverage-instrumented CI job (12× slower than a local run) it did not. The engine reads `performance.now()` at the handler's return and at its promise's settle, so the test now owns that clock (#3598's pattern): it stands still unless the handler advances it — 9ms for the quiet side, 30ms for the info side — and both `continuationMs` values are asserted exactly. Real timers still drive the await; only the stamps are the test's. Co-authored-by: Claude via Cursor <noreply@cursor.com>
1 parent 06745e2 commit 9f1c140

1 file changed

Lines changed: 14 additions & 1 deletion

File tree

‎packages/signals/tests/attribution-interactions.test.ts‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,16 +367,29 @@ describe("a handler that returns a promise", () => {
367367
});
368368

369369
it("stays quiet below the hold threshold, and info between the two", async () => {
370+
// The verdict is cut against `continuationMs`: two `performance.now()`
371+
// reads in the engine, at the handler's return and at its promise's
372+
// settle. On the wall clock a 1ms wait crossed `infoMs: 10` on the
373+
// coverage-instrumented CI job (12× slower than a local run), so the
374+
// clock is the test's here (the #3598 pattern): it stands still unless
375+
// the handler advances it, and each side of the threshold is exercised
376+
// by choice. Real timers still drive the await; only the stamps are ours.
377+
let t = 1000;
378+
vi.spyOn(performance, "now").mockImplementation(() => t);
370379
const { interactions, findings } = armWithFindings({ infoMs: 10, warnMs: 1000 });
371380
OBSERVE!.attribution.withInteraction(CLICK, async () => {
372381
await wait(1);
382+
t += 9; // one short of infoMs
373383
});
374384
await until(() => interactions().length === 1, "the fast handler to settle");
385+
expect(interactions()[0].continuationMs).toBe(9);
375386
expect(findings).toHaveLength(0);
376387
OBSERVE!.attribution.withInteraction(CLICK, async () => {
377-
await wait(30);
388+
await wait(1);
389+
t += 30; // past infoMs, short of warnMs
378390
});
379391
await until(() => interactions().length === 2, "the slow handler to settle");
392+
expect(interactions()[1].continuationMs).toBe(30);
380393
expect(findings).toHaveLength(1);
381394
expect(findings[0].severity).toBe("info");
382395
});

0 commit comments

Comments
 (0)