- CentralStatus: replace the red pulsing dot at the start of the "working" line with the rotating WorkingSpinner, now a button that opens the model-activity panel (onOpenActivity). WorkingSpinner is extracted to its own module (was local to AppShell). - ModelActivityPanel: show the last 5 lines of the model-stream tail (refreshing as the stream grows) with an expand toggle to the full stream, replacing the unbounded full transcript. - AppShell: drop the separate spinner button (the inline icon is now the single trigger) and the local WorkingSpinner def. - Remove the now-orphaned Transcript.tsx (its only consumer was the panel). TDD: CentralStatus + ModelActivityPanel tests RED->GREEN; frontend suite 87/87; tsc clean. Live visual verification pending (to do with the B/C frontend pass). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
39 lines
1.7 KiB
TypeScript
39 lines
1.7 KiB
TypeScript
import { render, screen } from "@testing-library/react";
|
|
import userEvent from "@testing-library/user-event";
|
|
import { beforeEach, vi } from "vitest";
|
|
import { useSessionStore } from "../store/sessionStore";
|
|
import { ModelActivityPanel } from "./ModelActivityPanel";
|
|
|
|
beforeEach(() => useSessionStore.getState().resetSession());
|
|
|
|
test("renders the streamed model transcript", () => {
|
|
useSessionStore.getState().applyEvent({ type: "text_delta", text: "Promoting table dim_patient." });
|
|
render(<ModelActivityPanel onClose={vi.fn()} />);
|
|
expect(screen.getByText(/Promoting table dim_patient/)).toBeInTheDocument();
|
|
});
|
|
|
|
test("close button calls onClose", async () => {
|
|
const onClose = vi.fn();
|
|
render(<ModelActivityPanel onClose={onClose} />);
|
|
await userEvent.click(screen.getByRole("button", { name: /close/i }));
|
|
expect(onClose).toHaveBeenCalled();
|
|
});
|
|
|
|
const EIGHT = ["line-01", "line-02", "line-03", "line-04", "line-05", "line-06", "line-07", "line-08"].join("\n");
|
|
|
|
test("collapsed shows only the last 5 lines of the model-stream tail", () => {
|
|
useSessionStore.getState().applyEvent({ type: "text_delta", text: EIGHT });
|
|
render(<ModelActivityPanel onClose={vi.fn()} />);
|
|
expect(screen.getByText("line-08")).toBeInTheDocument();
|
|
expect(screen.getByText("line-04")).toBeInTheDocument();
|
|
expect(screen.queryByText("line-03")).not.toBeInTheDocument();
|
|
expect(screen.queryByText("line-01")).not.toBeInTheDocument();
|
|
});
|
|
|
|
test("expanding reveals the full stream", async () => {
|
|
useSessionStore.getState().applyEvent({ type: "text_delta", text: EIGHT });
|
|
render(<ModelActivityPanel onClose={vi.fn()} />);
|
|
await userEvent.click(screen.getByRole("button", { name: /show more/i }));
|
|
expect(screen.getByText("line-01")).toBeInTheDocument();
|
|
});
|