import { act, fireEvent, render, screen } from "@testing-library/react"; import { beforeEach } from "vitest"; import { useSessionStore } from "../store/sessionStore"; import { CentralStatus } from "./CentralStatus"; beforeEach(() => useSessionStore.getState().resetSession()); function setScrollGeometry( element: HTMLElement, values: { scrollHeight: number; clientHeight: number; scrollTop: number }, ) { Object.defineProperties(element, { scrollHeight: { configurable: true, value: values.scrollHeight }, clientHeight: { configurable: true, value: values.clientHeight }, scrollTop: { configurable: true, writable: true, value: values.scrollTop }, }); } test("renders only the chronological assistant transcript log while working", () => { useSessionStore.setState({ lastUserEntry: { kind: "input", text: "how many patients?" }, stepMessages: [{ level: "warning", text: "Searching the schema…" }], transcript: [ { role: "assistant", text: "First line\n\nSecond line" }, { role: "assistant", text: "Third line" }, ], }); render(); const log = screen.getByRole("log", { name: "Live model activity" }); expect(log).toHaveTextContent("First line"); expect(log).toHaveTextContent("Second line"); expect(log).toHaveTextContent("Third line"); expect(log).toHaveClass("max-h-28", "overflow-y-auto"); expect(screen.queryByText("how many patients?")).not.toBeInTheDocument(); expect(screen.queryByText("Searching the schema…")).not.toBeInTheDocument(); expect(screen.queryByRole("status")).not.toBeInTheDocument(); expect(screen.queryByText(/\d+s/)).not.toBeInTheDocument(); }); test("wraps live log lines instead of truncating them", () => { useSessionStore.setState({ transcript: [{ role: "assistant", text: "a_very_long_model_activity_line" }], }); render(); expect(screen.getByText("a_very_long_model_activity_line")).toHaveClass( "whitespace-pre-wrap", "break-words", ); expect(screen.getByText("a_very_long_model_activity_line")).not.toHaveClass("truncate"); }); test.each([ { working: false, transcript: [{ role: "assistant" as const, text: "hidden" }] }, { working: true, transcript: [] }, { working: true, transcript: [{ role: "assistant" as const, text: " \n " }] }, ])("renders nothing without active non-blank transcript content", ({ working, transcript }) => { useSessionStore.setState({ transcript }); const { container } = render(); expect(container).toBeEmptyDOMElement(); }); test("bottom-follows appended transcript text only while near the bottom", () => { useSessionStore.setState({ transcript: [{ role: "assistant", text: "First" }] }); render(); const log = screen.getByRole("log", { name: "Live model activity" }); setScrollGeometry(log, { scrollHeight: 400, clientHeight: 100, scrollTop: 300 }); act(() => useSessionStore.getState().applyEvent({ type: "text_delta", text: " second" })); expect(log.scrollTop).toBe(400); }); test("preserves manual live-log scroll position away from the bottom", () => { useSessionStore.setState({ transcript: [{ role: "assistant", text: "First" }] }); render(); const log = screen.getByRole("log", { name: "Live model activity" }); setScrollGeometry(log, { scrollHeight: 400, clientHeight: 100, scrollTop: 100 }); fireEvent.scroll(log); act(() => useSessionStore.getState().applyEvent({ type: "text_delta", text: " second" })); expect(log.scrollTop).toBe(100); });