import { expect, test } from "bun:test";
import { renderToStaticMarkup } from "react-dom/server";
import { AgentOperationFeed, type CloudAgentChatMessage } from "@/components/canvas/canvas-cloud-agent-chat-ui";
import { canvasThemes } from "@/lib/canvas-theme";
const step = (id: string, title: string, text: string, detail: unknown = { eventType: "tool_completed" }): CloudAgentChatMessage => ({ id, role: "tool", title, text, detail });
const steps: CloudAgentChatMessage[] = [step("t1", "canvas_get_state", "工具执行成功"), step("t2", "model_list", "工具执行成功")];
const viewed = (id: string, title: string): CloudAgentChatMessage => step(id, "canvas_inspect_image", "工具执行成功", { eventType: "tool_completed", result: { nodeId: id, title } });
test("operations fold into one line that reports only the latest action", () => {
for (const theme of [canvasThemes.light, canvasThemes.dark]) {
const html = renderToStaticMarkup();
expect(html).toContain("agent-operation-feed");
expect(html).toContain('aria-expanded="false"');
expect(html).toContain("已获取可用模型");
expect(html).not.toContain("已读取画布清单");
expect(html).not.toContain("agent-operation-list");
expect(html).toContain("2 步");
expect(html).toContain("读取信息");
}
});
test("the folded line names the tier it is reporting", () => {
const read = renderToStaticMarkup();
expect(read).toContain("读取清单");
expect(read).toContain('data-agent-category="read"');
expect(read).not.toContain("操作画布");
expect(read).toContain('aria-label="展开 1 步读取清单记录,最新一步:已读取画布清单(未查看画面)"');
// 只有一步时不加计数徽标
expect(read).not.toContain('class="agent-operation-count"');
const vision = renderToStaticMarkup();
expect(vision).toContain("查看画面");
expect(vision).toContain('data-agent-category="vision"');
expect(vision).toContain("查看了 2 张画面 · 最新《封面.png》");
expect(vision).not.toContain("操作已完成");
const operate = renderToStaticMarkup();
expect(operate).toContain("修改画布");
expect(operate).toContain('data-agent-category="operate"');
});
test("a failed step is marked and expanded instead of hidden behind the folded line", () => {
const failed = [...steps, step("t3", "canvas_apply_ops", "", { eventType: "tool_failed", result: { taskId: "task-1" } })];
const html = renderToStaticMarkup();
expect(html).toContain("is-failed");
expect(html).toContain('aria-expanded="true"');
expect(html).toContain("更新画布内容失败");
expect(html).toContain("agent-operation-list");
// 展开的完整记录仍然是原样的工具卡(含任务 ID 与历史步骤),失败那步的文字是红的
expect(html).toContain("已读取画布清单(未查看画面)");
expect(html).toContain("任务 ID:task-1");
expect(html).toContain("#dc2626");
});
test("the shimmer only runs while the panel says the segment is live", () => {
const idle = renderToStaticMarkup();
const running = renderToStaticMarkup();
expect(idle).not.toContain("is-live");
expect(running).toContain("is-live");
// 失败的那一段即使是末尾也不流光:红色静态文字承担语义
const failedLive = renderToStaticMarkup();
expect(failedLive).not.toContain("is-live");
});
test("style contract: no per-step status ticks, vision tint and shimmer stay token-driven", async () => {
const css = await Bun.file(new URL("../src/components/canvas/canvas-cloud-agent.css", import.meta.url)).text();
// 展开后的每一步不再渲染状态勾/叉(一列绿勾会把记录读成成绩单)
expect(css).toContain(".agent-operation-list .agent-tool-status {");
// 流光动画只挂在 .is-live 上:任务完成即停
expect(css).toContain(".agent-operation-feed.is-live .agent-operation-latest {");
// 类别取色走面板注入的主题 token,不写字面值
expect(css).toContain("--agent-tool-accent: var(--agent-accent, var(--foreground));");
});