import { render, screen, within } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import type { HarnessEvent } from "@agent-studio/shared"; import { describe, expect, it, vi } from "vitest"; import { App } from "../src/App.js"; import { createInitialHarnessState, reduceHarnessEvent, type HarnessClientState, } from "../src/store/reducer.js"; const base = { sessionId: "ses_full_flow", timestamp: "2026-09-08T08:00:00.000Z", }; function event(value: Omit): T { return { ...base, ...value, eventId: `evt_${value.sequence}`, } as T; } function fullFlowSnapshot(): HarnessClientState { const events: HarnessEvent[] = [ event({ type: "user.message", sequence: 1, payload: { messageId: "msg_user", text: "分析最近 7 天素材并生成报告", attachmentIds: ["att_1"] }, }), event({ type: "run.started", sequence: 2, runId: "run_1", payload: { modelId: "gpt-test" } }), event({ type: "skill.requested", sequence: 3, runId: "run_1", payload: { name: "ads-analysis", source: "project" }, }), event({ type: "skill.loaded", sequence: 4, runId: "run_1", payload: { name: "ads-analysis", source: "project" }, }), event({ type: "assistant.delta", sequence: 5, runId: "run_1", payload: { messageId: "msg_assistant", delta: "已读取分析方法。" }, }), event({ type: "tool.requested", sequence: 6, runId: "run_1", payload: { toolCallId: "tool_metrics", toolName: "mock_ads_metrics", arguments: { accountId: "demo-account", days: 7 }, }, }), event({ type: "tool.completed", sequence: 7, runId: "run_1", payload: { toolCallId: "tool_metrics", toolName: "mock_ads_metrics", result: { spend: 1024.5, revenue: 3088.2, roas: 3.01, conversions: 44 }, }, }), event({ type: "tool.requested", sequence: 8, runId: "run_1", payload: { toolCallId: "tool_report", toolName: "save_report_draft", arguments: { title: "广告素材分析报告", body: "近 7 天投放表现与下一步建议。" }, }, }), event({ type: "approval.required", sequence: 9, runId: "run_1", payload: { approvalId: "ap_full_flow", toolCallId: "tool_report", toolName: "save_report_draft", arguments: { title: "广告素材分析报告", body: "近 7 天投放表现与下一步建议。" }, riskLevel: "medium", expiresAt: "2099-09-08T08:05:00.000Z", }, }), ]; const state = events.reduce(reduceHarnessEvent, createInitialHarnessState({ sessionId: base.sessionId, skills: [{ name: "ads-analysis", description: "分析广告素材表现", source: "project", filePath: ".agents/skills/ads-analysis/SKILL.md", diagnostics: [], }], })); return { ...state, connection: "open" }; } describe("complete training flow", () => { it("renders the message, skill, tools, timeline, and server-owned approval as one flow", async () => { const user = userEvent.setup(); const approve = vi.fn().mockResolvedValue({ approvalId: "ap_full_flow", status: "approved" }); const snapshot = fullFlowSnapshot(); const store = { getSnapshot: () => snapshot, subscribe: () => () => undefined, sendMessage: vi.fn(), cancel: vi.fn(), start: vi.fn().mockResolvedValue(undefined), getModelConfig: vi.fn().mockResolvedValue({ modelConfig: { configured: true, source: "session", modelId: "gpt-test", supportsImages: true }, }), approve, deny: vi.fn(), }; render(); expect(screen.getByText("分析最近 7 天素材并生成报告")).toBeVisible(); expect(screen.getByText("已读取分析方法。")).toBeVisible(); expect(screen.getByText("分析广告素材表现")).toBeVisible(); const metrics = screen.getByRole("region", { name: "广告指标工具" }); expect(within(metrics).getByText("3.01")).toBeVisible(); const report = screen.getByRole("region", { name: "保存报告草稿工具" }); expect(within(report).getByText("等待审批")).toBeVisible(); expect(screen.getByRole("dialog", { name: "允许写入报告草稿吗?" })).toBeVisible(); expect(screen.getByText("approval.required")).toBeVisible(); await user.click(screen.getByRole("button", { name: "批准并保存" })); expect(approve).toHaveBeenCalledTimes(1); expect(approve).toHaveBeenCalledWith("ap_full_flow"); }); });