import { renderToStaticMarkup } from "react-dom/server"; import { describe, expect, test } from "vitest"; import { AgentConversation, AgentMessage, AgentPromptInput, type AgentChatMessage, } from "./AgentChat"; import { buildSourcesFromToolTrace, buildReasoningSteps, getToolTraceSummary, scrollConversationToBottom, } from "./agentChatModel"; const assistantMessage: AgentChatMessage = { id: "assistant-1", role: "assistant", content: "Deine groesste Ausgabe war Miete.", toolTrace: [ { name: "summarize_transactions", inputSummary: "Mai 2026", resultSummary: "12 Umsaetze zusammengefasst", }, { name: "list_transactions", inputSummary: "Miete", resultSummary: "1 Treffer", }, ], }; describe("AgentChat phase 1 components", () => { test("scrolls the conversation container directly to the bottom", () => { const container = { scrollTop: 0, scrollHeight: 1200, }; scrollConversationToBottom(container); expect(container.scrollTop).toBe(1200); }); test("summarizes tool traces for compact agent transparency", () => { expect(getToolTraceSummary(undefined)).toBe("Keine Werkzeuge"); expect(getToolTraceSummary([])).toBe("Keine Werkzeuge"); expect(getToolTraceSummary(assistantMessage.toolTrace)).toBe("2 Werkzeuge verwendet"); }); test("renders conversation messages with assistant tool trace details", () => { const markup = renderToStaticMarkup( , ); expect(markup).toContain("Was war teuer?"); expect(markup).toContain("Deine groesste Ausgabe war Miete."); expect(markup).toContain("2 Werkzeuge verwendet"); expect(markup).toContain("summarize_transactions"); expect(markup).toContain("12 Umsaetze zusammengefasst"); }); test("renders the prompt input with ready and busy states", () => { const readyMarkup = renderToStaticMarkup( undefined} onSubmit={() => undefined} />, ); const busyMarkup = renderToStaticMarkup( undefined} onSubmit={() => undefined} />, ); expect(readyMarkup).toContain("Welche Auswertung soll ich machen?"); expect(readyMarkup).toContain("Senden"); expect(busyMarkup).toContain("Antwort laeuft"); expect(busyMarkup).toContain("disabled"); }); test("disables prompt submit for whitespace-only input", () => { const markup = renderToStaticMarkup( undefined} onSubmit={() => undefined} />, ); expect(markup).toContain("disabled"); }); test("renders a thinking indicator while the agent is submitting", () => { const markup = renderToStaticMarkup( , ); expect(markup).toContain("Denk mit der KI nach..."); }); test("renders a single message without a tool section when no trace exists", () => { const markup = renderToStaticMarkup( , ); expect(markup).toContain("Assistant"); expect(markup).toContain("Hallo"); expect(markup).not.toContain("Werkzeuge verwendet"); }); }); describe("AgentChat phase 2 reasoning disclosure", () => { test("builds safe reasoning steps from tool traces without exposing raw inputs", () => { const steps = buildReasoningSteps(assistantMessage.toolTrace); expect(steps).toEqual([ { label: "summarize_transactions", description: "12 Umsaetze zusammengefasst", status: "complete", }, { label: "list_transactions", description: "1 Treffer", status: "complete", }, ]); expect(JSON.stringify(steps)).not.toContain("Mai 2026"); }); test("renders an assistant work-progress disclosure from tool traces", () => { const markup = renderToStaticMarkup(); expect(markup).toContain("So wurde gearbeitet"); expect(markup).toContain("summarize_transactions"); expect(markup).toContain("12 Umsaetze zusammengefasst"); }); test("marks the current agent step as active while submitting", () => { const markup = renderToStaticMarkup( , ); expect(markup).toContain("Antwort wird vorbereitet"); expect(markup).toContain("data-status=\"active\""); }); }); describe("AgentChat phase 3 sources and inline citations", () => { test("builds private finance sources from tool traces", () => { expect(buildSourcesFromToolTrace(assistantMessage.toolTrace)).toEqual([ { id: "tool-1", title: "summarize_transactions", description: "12 Umsaetze zusammengefasst", }, { id: "tool-2", title: "list_transactions", description: "1 Treffer", }, ]); }); test("renders source list and inline citation markers for assistant messages", () => { const markup = renderToStaticMarkup( , ); expect(markup).toContain("Quellen"); expect(markup).toContain("list_transactions"); expect(markup).toContain("1 Mietumsatz gefunden"); expect(markup).toContain("[1]"); expect(markup).toContain("data-source-id=\"tool-1\""); }); });