diff --git a/packages/app/e2e/browser/turn-collapse.spec.ts b/packages/app/e2e/browser/turn-collapse.spec.ts index d990e33009..cd899d1ee8 100644 --- a/packages/app/e2e/browser/turn-collapse.spec.ts +++ b/packages/app/e2e/browser/turn-collapse.spec.ts @@ -2,6 +2,7 @@ import type { DaemonClient } from "@getpaseo/client/internal/daemon-client"; import path from "node:path"; import { holdOlderHistoryPages, + scrollTimelineRowIntoView, userScrollsTimelineToHistoryStart, } from "../support/helpers/timeline-pagination"; import { getActiveTabTestId } from "../support/helpers/launcher"; @@ -529,6 +530,7 @@ async function expectThinkingPresentation(page: Page, autoExpandReasoning: boole .last(); await expect(group).toContainText(/read 1 file/i); await expect(group.getByRole("button").first()).not.toContainText(/thought/i); + await scrollTimelineRowIntoView(page, group); await group.getByRole("button").first().click(); // Expand thinking is off: the group opens its rows, but the thought row stays closed // until the reader opens it. diff --git a/packages/app/e2e/support/helpers/timeline-pagination.ts b/packages/app/e2e/support/helpers/timeline-pagination.ts index e575f4f0d9..f54fd86812 100644 --- a/packages/app/e2e/support/helpers/timeline-pagination.ts +++ b/packages/app/e2e/support/helpers/timeline-pagination.ts @@ -477,18 +477,29 @@ export async function expectStableHistoryStartGutter(page: Page): Promise .toBe(32); } -export async function scrollTimelinePromptIntoView(page: Page, prompt: string): Promise { +/** + * Wheels the timeline until `row` is centered, as a reader does. Playwright's own + * scroll-into-view is programmatic, which the timeline does not treat as the reader leaving + * the bottom: it snaps back to the bottom and can move the row away mid-click. + */ +export async function scrollTimelineRowIntoView(page: Page, row: Locator): Promise { const timeline = page.locator('[data-testid="agent-chat-scroll"]:visible').first(); - const row = timeline.getByTestId("user-message").filter({ hasText: prompt }); const [viewport, target] = await Promise.all([timeline.boundingBox(), row.boundingBox()]); if (!viewport || !target) { - throw new Error(`Expected a rendered timeline prompt for ${prompt}`); + throw new Error("Expected a rendered timeline row"); } - // Programmatic scrolling does not express the user's intent to stop following output. await timeline.hover(); await page.mouse.wheel(0, target.y - viewport.y - (viewport.height - target.height) / 2); await expect(row).toBeInViewport({ ratio: 1 }); await waitForTimelineGeometryToSettle(page); +} + +export async function scrollTimelinePromptIntoView(page: Page, prompt: string): Promise { + const timeline = page.locator('[data-testid="agent-chat-scroll"]:visible').first(); + await scrollTimelineRowIntoView( + page, + timeline.getByTestId("user-message").filter({ hasText: prompt }), + ); await expect .poll(async () => (await readTimelineViewport(page)).scrollTop) .toBeGreaterThan(HISTORY_START_THRESHOLD_PX);