diff --git a/src/browser/features/RightSidebar/StatsContainer.diagnostics.test.tsx b/src/browser/features/RightSidebar/StatsContainer.diagnostics.test.tsx new file mode 100644 index 0000000000..ba696bcc87 --- /dev/null +++ b/src/browser/features/RightSidebar/StatsContainer.diagnostics.test.tsx @@ -0,0 +1,47 @@ +import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test"; +import { GlobalWindow } from "happy-dom"; +import { cleanup, fireEvent, render } from "@testing-library/react"; + +void mock.module("./CostsTab", () => ({ + CostsTab: () =>
Costs panel
, +})); + +describe("StatsContainer diagnostics", () => { + let originalWindow: typeof globalThis.window; + let originalDocument: typeof globalThis.document; + + beforeEach(() => { + originalWindow = globalThis.window; + originalDocument = globalThis.document; + + globalThis.window = new GlobalWindow() as unknown as Window & typeof globalThis; + globalThis.document = globalThis.window.document; + globalThis.window.localStorage.clear(); + }); + + afterEach(() => { + cleanup(); + globalThis.window = originalWindow; + globalThis.document = originalDocument; + }); + + test("switches to the Diagnostics sub-tab and exposes button pressed state", async () => { + // eslint-disable-next-line no-restricted-syntax -- The test must import after mock.module() so StatsContainer sees the stubbed CostsTab instead of loading Mermaid-heavy dependencies. + const { StatsContainer } = await import("./StatsContainer"); + const view = render(); + + const costButton = view.getByRole("button", { name: "Cost" }); + const diagnosticsButton = view.getByRole("button", { name: "Diagnostics" }); + + expect(view.getByText("Costs panel")).toBeTruthy(); + expect(costButton.getAttribute("aria-pressed")).toBe("true"); + expect(diagnosticsButton.getAttribute("aria-pressed")).toBe("false"); + + fireEvent.click(diagnosticsButton); + + expect(view.queryByText("Costs panel")).toBeNull(); + expect(view.getByText("Loading diagnostics...")).toBeTruthy(); + expect(costButton.getAttribute("aria-pressed")).toBe("false"); + expect(diagnosticsButton.getAttribute("aria-pressed")).toBe("true"); + }); +}); diff --git a/src/browser/features/RightSidebar/StatsContainer.tsx b/src/browser/features/RightSidebar/StatsContainer.tsx index 8613e4f8f8..56cddb5d1c 100644 --- a/src/browser/features/RightSidebar/StatsContainer.tsx +++ b/src/browser/features/RightSidebar/StatsContainer.tsx @@ -5,13 +5,14 @@ * - "Cost" — renders CostsTab * - "Timing" — renders TimingPanel from StatsTab * - "Models" — renders ModelBreakdownPanel from StatsTab + * - "Diagnostics" — renders DiagnosticsPanel from StatsTab */ import { usePersistedState } from "@/browser/hooks/usePersistedState"; import { CostsTab } from "./CostsTab"; -import { TimingPanel, ModelBreakdownPanel } from "./StatsTab"; +import { TimingPanel, ModelBreakdownPanel, DiagnosticsPanel } from "./StatsTab"; -type StatsSubTab = "cost" | "timing" | "models"; +type StatsSubTab = "cost" | "timing" | "models" | "diagnostics"; interface StatsOption { value: StatsSubTab; @@ -22,6 +23,7 @@ const OPTIONS: StatsOption[] = [ { value: "cost", label: "Cost" }, { value: "timing", label: "Timing" }, { value: "models", label: "Models" }, + { value: "diagnostics", label: "Diagnostics" }, ]; interface StatsContainerProps { @@ -43,6 +45,7 @@ export function StatsContainer(props: StatsContainerProps) {