From 24d511e29c699ac7cf7a812310a2d16fb39f30dc Mon Sep 17 00:00:00 2001 From: Sebastien Melki Date: Sat, 25 Apr 2026 16:09:32 +0300 Subject: [PATCH] test(usage): make recorder.settled robust to nested waitUntil Promise.all(pending) snapshotted the array at call time, missing the inner ctx.waitUntil(sendToAxiom(...)) that emitUsageEvents pushes after the outer drain begins. Tests passed only because the fetch spy resolved in an earlier microtask tick. Replace with a quiescence loop so the helper survives any future async in the emit path. Co-Authored-By: Claude Opus 4.7 (1M context) --- tests/usage-telemetry-emission.test.mts | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/tests/usage-telemetry-emission.test.mts b/tests/usage-telemetry-emission.test.mts index 9370125f4..11093a750 100644 --- a/tests/usage-telemetry-emission.test.mts +++ b/tests/usage-telemetry-emission.test.mts @@ -31,15 +31,25 @@ interface CapturedEvent { tier: number; } -function makeRecordingCtx(): { ctx: GatewayCtx; settled: Promise } { +function makeRecordingCtx(): { ctx: GatewayCtx; settled: Promise } { const pending: Promise[] = []; const ctx: GatewayCtx = { waitUntil: (p) => { pending.push(p); }, }; + // Quiescence loop: emitUsageEvents calls ctx.waitUntil from inside an + // already-pending waitUntil promise, so the array grows during drain. + // Keep awaiting until no new entries appear between iterations. + async function settled(): Promise { + let prev = -1; + while (pending.length !== prev) { + prev = pending.length; + await Promise.allSettled(pending.slice(0, prev)); + } + } return { ctx, - get settled() { return Promise.all(pending) as Promise; }, - } as { ctx: GatewayCtx; settled: Promise }; + get settled() { return settled(); }, + } as { ctx: GatewayCtx; settled: Promise }; } function installAxiomFetchSpy(