import { afterEach, describe, expect, it, vi } from "vitest"; import { cleanup, fireEvent, render, screen } from "@testing-library/react"; vi.mock("react-i18next", () => ({ useTranslation: () => ({ t: (key: string) => key }), })); import { Facts, PanelSearch, PanelShell, Segmented, ViewToggle, gridSizeStyle, } from "@/components/panel-layout"; afterEach(cleanup); describe("PanelSearch", () => { it("clears with the button and with Esc", () => { const onChange = vi.fn(); const { rerender } = render( , ); fireEvent.click(screen.getByLabelText("panel.clearSearch")); expect(onChange).toHaveBeenLastCalledWith(""); rerender(); fireEvent.keyDown(screen.getByRole("textbox"), { key: "Escape" }); expect(onChange).toHaveBeenCalledTimes(2); }); it("hides the clear button while empty", () => { render( {}} />); expect(screen.queryByLabelText("panel.clearSearch")).toBeNull(); }); }); describe("Segmented", () => { it("marks the active option and reports a pick", () => { const onChange = vi.fn(); render( , ); const radios = screen.getAllByRole("radio"); expect(radios[0].getAttribute("aria-checked")).toBe("true"); fireEvent.click(radios[1]); expect(onChange).toHaveBeenCalledWith("credentials"); }); }); describe("ViewToggle", () => { it("switches view and density", () => { const onView = vi.fn(); const onDensity = vi.fn(); render( , ); fireEvent.click(screen.getByLabelText("panel.listView")); expect(onView).toHaveBeenCalledWith("list"); fireEvent.click(screen.getByLabelText("panel.compactRows")); expect(onDensity).toHaveBeenCalledWith("compact"); }); it("shows the columns picker only in grid view", () => { const props = { onView: vi.fn(), columns: "auto" as const }; const { rerender } = render( , ); expect(screen.getByLabelText("panel.columns.title")).toBeTruthy(); rerender(); expect(screen.queryByLabelText("panel.columns.title")).toBeNull(); rerender(); expect(screen.queryByLabelText("panel.columns.title")).toBeNull(); }); }); describe("gridSizeStyle", () => { it("fits auto cards to the pane", () => { expect(gridSizeStyle("auto", 280).gridTemplateColumns).toBe( "repeat(auto-fill, minmax(min(100%, 280px), 1fr))", ); }); it("splits the width for a fixed count", () => { expect(gridSizeStyle("4").gridTemplateColumns).toContain( "(100% - 3 * 0.5rem) / 4", ); }); }); describe("Facts", () => { it("puts a rule only between facts", () => { const { container } = render( one {null} two , ); expect(container.querySelectorAll("[aria-hidden]")).toHaveLength(1); }); it("separates facts passed inside a fragment", () => { const { container } = render( <> Termix {false} v1.0.0 Monitoring , ); expect(container.querySelectorAll("[aria-hidden]")).toHaveLength(2); }); }); describe("PanelShell", () => { it("draws the header, toolbar and footer", () => { render( toolbar} footer={footer} > body , ); expect(screen.getByText("Docker")).toBeTruthy(); expect(screen.getByText("2 running")).toBeTruthy(); expect(screen.getByText("toolbar")).toBeTruthy(); expect(screen.getByText("footer")).toBeTruthy(); }); });