diff --git a/features/agent/components/agent-message-details.tsx b/features/agent/components/agent-message-details.tsx index c4a79ab..679d2f1 100644 --- a/features/agent/components/agent-message-details.tsx +++ b/features/agent/components/agent-message-details.tsx @@ -237,7 +237,7 @@ function ProgressList({ progress, running }: { progress: AgentChatProgress[]; ru - + {permissions.slice(-4).map((permission) => ( @@ -496,7 +496,7 @@ function QuestionList({ }) { return ( - + {questions.slice(-3).map((request) => ( diff --git a/tests/browser/agent-streaming-stability.e2e.ts b/tests/browser/agent-streaming-stability.e2e.ts index e641563..8df5fa0 100644 --- a/tests/browser/agent-streaming-stability.e2e.ts +++ b/tests/browser/agent-streaming-stability.e2e.ts @@ -4,6 +4,7 @@ import { expect, test } from "playwright/test"; const STREAM_CHUNK_SIZE = 18; const STREAM_CHUNK_DELAY_MS = 20; +const PROGRESS_GEOMETRY_TOLERANCE_PX = 0.1; let streamServer: Server; let streamServerUrl: string; @@ -267,19 +268,54 @@ test("stream completion and the plan card remain positionally stable", async ({ const liveProgress = page.getByRole("list", { name: "最近执行进度" }); await expect(liveProgress.locator("li")).toHaveCount(3); await expect(liveProgress.getByText("正在分析运行上下文", { exact: true })).toBeVisible(); + await expect(liveProgress).toHaveCSS("height", "156px"); + await expect.poll(() => liveProgress.evaluate((list) => list.style.height)).toBe("auto"); await page.evaluate(() => { const state = window as typeof window & { __agentMinVisibleProgressRows?: number; + __agentProgressGeometry?: { + maxContainerHeight: number; + maxListHeight: number; + minContainerHeight: number; + minListHeight: number; + }; __agentProgressWindowSampleDone?: boolean; }; const startedAt = performance.now(); state.__agentMinVisibleProgressRows = Number.POSITIVE_INFINITY; + state.__agentProgressGeometry = { + maxContainerHeight: Number.NEGATIVE_INFINITY, + maxListHeight: Number.NEGATIVE_INFINITY, + minContainerHeight: Number.POSITIVE_INFINITY, + minListHeight: Number.POSITIVE_INFINITY + }; state.__agentProgressWindowSampleDone = false; const sample = () => { - const rows = document.querySelectorAll('ol[aria-label="最近执行进度"] > li').length; + const list = document.querySelector('ol[aria-label="最近执行进度"]'); + const rows = list?.children.length ?? 0; state.__agentMinVisibleProgressRows = Math.min(state.__agentMinVisibleProgressRows ?? rows, rows); + if (list && state.__agentProgressGeometry) { + const listHeight = list.getBoundingClientRect().height; + const containerHeight = list.parentElement?.getBoundingClientRect().height ?? 0; + state.__agentProgressGeometry.minListHeight = Math.min( + state.__agentProgressGeometry.minListHeight, + listHeight + ); + state.__agentProgressGeometry.maxListHeight = Math.max( + state.__agentProgressGeometry.maxListHeight, + listHeight + ); + state.__agentProgressGeometry.minContainerHeight = Math.min( + state.__agentProgressGeometry.minContainerHeight, + containerHeight + ); + state.__agentProgressGeometry.maxContainerHeight = Math.max( + state.__agentProgressGeometry.maxContainerHeight, + containerHeight + ); + } if (performance.now() - startedAt < 400) { requestAnimationFrame(sample); } else { @@ -303,6 +339,23 @@ test("stream completion and the plan card remain positionally stable", async ({ (window as typeof window & { __agentMinVisibleProgressRows?: number }).__agentMinVisibleProgressRows ) ).toBeGreaterThanOrEqual(3); + const progressGeometry = await page.evaluate(() => + (window as typeof window & { + __agentProgressGeometry?: { + maxContainerHeight: number; + maxListHeight: number; + minContainerHeight: number; + minListHeight: number; + }; + }).__agentProgressGeometry + ); + expect(progressGeometry).toBeDefined(); + expect(progressGeometry!.maxListHeight - progressGeometry!.minListHeight).toBeLessThanOrEqual( + PROGRESS_GEOMETRY_TOLERANCE_PX + ); + expect(progressGeometry!.maxContainerHeight - progressGeometry!.minContainerHeight).toBeLessThanOrEqual( + PROGRESS_GEOMETRY_TOLERANCE_PX + ); const liveProgressRowHeights = await liveProgress.locator("li").evaluateAll((rows) => rows.map((row) => row.getBoundingClientRect().height)