fix: unify chat process and reply presentation
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
import { expect, test, type Locator } from "@playwright/test";
|
||||
import { createServer } from "node:http";
|
||||
import type { AddressInfo } from "node:net";
|
||||
import { mockAgentApi } from "./support/mock-agent-api";
|
||||
import { mockWorkbenchContext } from "./support/mock-workbench-context";
|
||||
import { responseFixtureWriter } from "./support/responses-fixture";
|
||||
|
||||
async function readRowStyle(row: Locator) {
|
||||
return row.evaluate((element) => {
|
||||
const style = getComputedStyle(element);
|
||||
const text = element.querySelector("span.min-w-0 > span")!;
|
||||
const icon = element.querySelector('[role="img"]')!;
|
||||
return {
|
||||
columns: style.gridTemplateColumns.split(" ")[0],
|
||||
gap: style.columnGap,
|
||||
fontSize: style.fontSize,
|
||||
titleWeight: getComputedStyle(text).fontWeight,
|
||||
titleLineHeight: getComputedStyle(text).lineHeight,
|
||||
iconWidth: icon.getBoundingClientRect().width,
|
||||
iconHeight: icon.getBoundingClientRect().height
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
for (const width of [1440, 320]) {
|
||||
test(`live progress matches archived rows and retains folding at ${width}px`, async ({ page }, testInfo) => {
|
||||
await page.setViewportSize({ width, height: 900 });
|
||||
await page.emulateMedia({ reducedMotion: "reduce" });
|
||||
await mockWorkbenchContext(page);
|
||||
await mockAgentApi(page);
|
||||
const steps = [
|
||||
{ id: "start", title: "已收到请求", status: "completed", detail: "正在核对当前项目。" },
|
||||
{ id: "context", title: "Agent 正在处理请求", status: "running", detail: "Agent 正在执行推理、工具调用或结果整理。" },
|
||||
{ id: "data", title: "获取业务数据", status: "running", detail: "正在核对附近阀门、关联管道与隔离范围。" },
|
||||
{ id: "isolation", phase: "tool", title: "阀门隔离分析", status: "running", tool: {
|
||||
name: "mcp_tjwater_analyze_valve_isolation", call_id: "isolation-call", input: { link_ids: [533793, 486121, 523616] }
|
||||
} }
|
||||
];
|
||||
let finish!: () => void;
|
||||
const server = createServer((_request, response) => {
|
||||
response.writeHead(200, { "Access-Control-Allow-Origin": "*", "Content-Type": "text/event-stream" });
|
||||
const write = responseFixtureWriter();
|
||||
const send = (chunk: Record<string, unknown>) => response.write(write(chunk));
|
||||
send({ type: "start", messageId: "consistent-progress" });
|
||||
for (const step of steps) send({ type: "data-progress", data: step });
|
||||
finish = () => {
|
||||
for (const step of steps) send({ type: "data-progress", data: { ...step, status: "completed" } });
|
||||
send({ type: "data-final_answer", data: { content: "已核对附近可用于隔离的阀门。" } });
|
||||
send({ type: "finish", finishReason: "stop" });
|
||||
response.end();
|
||||
};
|
||||
});
|
||||
await new Promise<void>((resolve) => server.listen(0, "127.0.0.1", resolve));
|
||||
try {
|
||||
await page.route("**/api/v1/responses", (route) => route.continue({ url: `http://127.0.0.1:${(server.address() as AddressInfo).port}` }));
|
||||
await page.goto("/", { waitUntil: "domcontentloaded" });
|
||||
await page.getByRole("button", { name: width < 1024 ? "打开 Agent 面板" : /展开 Agent 助手面板/ }).click();
|
||||
const panel = page.getByRole("complementary", { name: "Agent 命令面板" });
|
||||
await panel.getByRole("textbox", { name: "询问供水问题,或描述需要处理的任务" }).fill("找下附近可用的阀门,用于隔离");
|
||||
await panel.getByRole("button", { name: "发送 Agent 指令", exact: true }).click();
|
||||
const message = panel.locator('[data-agent-message-id="consistent-progress"]');
|
||||
const progress = message.locator("[data-agent-progress]");
|
||||
const recent = progress.getByRole("list", { name: "最近执行进度" });
|
||||
await expect(recent.locator("li")).toHaveCount(3);
|
||||
const container = message.locator("details[data-agent-live-process]");
|
||||
await expect(container).toHaveCSS("background-color", "rgb(255, 255, 255)");
|
||||
await expect(container).toHaveCSS("border-radius", "12px");
|
||||
await expect(container).toHaveCSS("border-top-width", "1px");
|
||||
await expect(progress).toHaveCSS("border-top-width", "0px");
|
||||
const containerStyle = await container.evaluate((element) => {
|
||||
const style = getComputedStyle(element);
|
||||
return [style.borderColor, style.borderRadius, style.backgroundColor];
|
||||
});
|
||||
const liveRow = recent.locator("li").filter({ hasText: "Agent 正在处理请求" });
|
||||
const liveStyle = await readRowStyle(liveRow);
|
||||
expect(liveStyle).toMatchObject({ columns: "24px", gap: "8px", fontSize: "14px", titleWeight: "500", iconWidth: 24, iconHeight: 24 });
|
||||
await expect(liveRow.getByRole("img", { name: "进行中", exact: true })).toBeVisible();
|
||||
await progress.getByRole("button", { name: "展开执行进度", exact: true }).click();
|
||||
await expect(progress.getByRole("list", { name: "全部执行进度" }).locator("li")).toHaveCount(4);
|
||||
await progress.getByRole("button", { name: "收起执行进度", exact: true }).click();
|
||||
await expect(recent.locator("li")).toHaveCount(3);
|
||||
const tool = progress.locator("details[data-agent-tool]");
|
||||
await expect(tool).not.toHaveAttribute("open");
|
||||
await tool.locator("summary").click();
|
||||
await expect(tool.locator("pre")).toContainText("533793");
|
||||
await message.screenshot({ path: testInfo.outputPath(`live-progress-${width}.png`) });
|
||||
finish();
|
||||
const archived = message.locator("details[data-agent-process]");
|
||||
await expect(archived).not.toHaveAttribute("open");
|
||||
await message.getByRole("button", { name: "查看处理过程", exact: true }).click();
|
||||
await expect(archived).toHaveAttribute("open", "");
|
||||
await expect(archived).toHaveCSS("background-color", "rgb(255, 255, 255)");
|
||||
expect(await archived.evaluate((element) => {
|
||||
const style = getComputedStyle(element);
|
||||
return [style.borderColor, style.borderRadius, style.backgroundColor];
|
||||
})).toEqual(containerStyle);
|
||||
const archivedRow = archived.getByRole("list", { name: "全部执行进度" }).locator("li").filter({ hasText: "Agent 正在处理请求" });
|
||||
expect(await readRowStyle(archivedRow)).toEqual(liveStyle);
|
||||
await expect(archivedRow.getByRole("img", { name: "已完成", exact: true })).toBeVisible();
|
||||
await expect(tool).toHaveAttribute("open", "");
|
||||
await message.getByRole("button", { name: "查看处理过程", exact: true }).click();
|
||||
await expect(progress).toBeHidden();
|
||||
await message.getByRole("button", { name: "查看处理过程", exact: true }).click();
|
||||
await expect(progress).toBeVisible();
|
||||
await message.screenshot({ path: testInfo.outputPath(`archived-progress-${width}.png`) });
|
||||
expect(await progress.evaluate((element) => element.scrollWidth - element.clientWidth)).toBeLessThanOrEqual(1);
|
||||
} finally {
|
||||
server.closeAllConnections();
|
||||
await new Promise<void>((resolve) => server.close(() => resolve()));
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user