From 9186e8b58cc25f5672d7871fdd89d6307a150b3e Mon Sep 17 00:00:00 2001 From: Matthew Robert Wesney <157447210+dovvnloading@users.noreply.github.com> Date: Sat, 17 Oct 2026 09:23:56 -0400 Subject: [PATCH] test(chat): wait for each throttled delivery in the jump-to-latest test The test failed intermittently under load ("expected to be called 1 times, but got 2"), on a loaded local machine and in CI on #325. The streaming bubble delivers text through useThrottledText's timer. The test clicked "Jump to latest" while the delivery of "more " could still be pending; when that delivery landed in the same act as the click, it ran after jumpToLatest had marked the reader as back at the end, so followStreamedOutput correctly followed it with an instant scroll, and the test counted two scrolls. Each step now waits until its text is in the bubble, so nothing is pending at the click. The test also checks one more thing than before: no scroll at all happens while the reader is scrolled away. The assertions on what it protects are unchanged: following is instant and only the reader's jump is smooth. Co-Authored-By: Claude Opus 5.5 --- .../src/features/chat/ChatPage.renderCost.test.tsx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/frontend/src/features/chat/ChatPage.renderCost.test.tsx b/frontend/src/features/chat/ChatPage.renderCost.test.tsx index d7870d7..840ad62 100644 --- a/frontend/src/features/chat/ChatPage.renderCost.test.tsx +++ b/frontend/src/features/chat/ChatPage.renderCost.test.tsx @@ -178,16 +178,26 @@ describe("ChatPage while a reply streams", () => { // "instant" restarts an animation on every streamed frame. const scrollTo = vi.fn(); Object.defineProperty(HTMLElement.prototype, "scrollTo", { configurable: true, value: scrollTo }); + // The bubble shows streamed text through a timer-driven throttle, so each + // step waits until its text is on screen. Clicking while a delivery is + // still pending let that delivery land in the same act as the click, after + // the jump had put the reader back at the end, and follow it with a second + // (correct) instant scroll: the test failed under load, not the product. + const bubble = () => screen.getByLabelText("Cortex response in progress"); try { await openChatAndStartStreaming(); stream("tok "); - await waitFor(() => expect(scrollTo).toHaveBeenCalled()); + await waitFor(() => expect(bubble()).toHaveTextContent("tok")); + expect(scrollTo).toHaveBeenCalled(); for (const [options] of scrollTo.mock.calls) expect(options).toEqual({ top: 1000, behavior: "instant" }); // Scrolled away: the next frame offers the jump instead of following. fireEvent.scroll(document.querySelector(".transcript")!); - stream("more "); scrollTo.mockClear(); + stream("more "); + await waitFor(() => expect(bubble()).toHaveTextContent("tok more")); + expect(scrollTo).not.toHaveBeenCalled(); + fireEvent.click(await screen.findByRole("button", { name: "Jump to latest" })); expect(scrollTo).toHaveBeenCalledTimes(1);