import { createElement as h } from "react"; import { afterEach, describe, expect, it } from "vitest"; import { cleanup, render, screen, within } from "@testing-library/react"; import { ClassificationStrip, CornerBrackets, LedgerRow, NoticeState, PageShell, ProvenanceChip, StatusReadout, StrategicSummary, STATUS_TONE_CLASSES, type StatusTone, } from "@/components/frontend/operations"; // Vitest globals are off, so @testing-library auto-cleanup never registers; // without this, rendered DOM accumulates across tests and role queries match // stale elements. afterEach(cleanup); /** * Component tests documenting every operations-primitive variant: * classification strip, corner brackets, status readout tones, ledger row, * provenance chip (plain + link), notice states (empty/loading/error), * the strategic summary composition, and the page shell. * * The file is .ts (the plan QA command names this exact path), so elements are * built with createElement instead of JSX syntax. * * Accessibility contract: semantic roles, aria-hidden decoration, keyboard * focus rings on interactive chips, contrast-compliant status text, and * reduced-motion variants on every transition. */ describe("ClassificationStrip", () => { it("renders both classification labels", () => { render(h(ClassificationStrip, { left: "Operations // Unit Command", right: "REF 001" })); expect(screen.getByText("Operations // Unit Command")).toBeDefined(); expect(screen.getByText("REF 001")).toBeDefined(); }); }); describe("CornerBrackets", () => { it("renders four decorative corner marks with reduced-motion variants", () => { const { container } = render(h(CornerBrackets)); const slot = container.querySelector('[data-slot="corner-brackets"]'); expect(slot?.getAttribute("aria-hidden")).toBe("true"); expect(slot?.querySelectorAll("span").length).toBe(4); expect(slot?.innerHTML).toContain("motion-reduce:transition-none"); }); }); describe("StatusReadout", () => { const tones: StatusTone[] = ["neutral", "info", "success", "warning", "danger"]; it.each(tones)("renders the %s tone with contrast-compliant status text", (tone) => { const { container } = render(h(StatusReadout, { label: `${tone} status`, tone })); const pill = screen.getByRole("status"); expect(pill.textContent).toBe(`${tone} status`); expect(pill.getAttribute("data-tone")).toBe(tone); // Squared corners (rounded-sm), token-driven contrast classes present. expect(pill.className).toContain("rounded-sm"); for (const cls of STATUS_TONE_CLASSES[tone].split(" ")) { expect(pill.className).toContain(cls); } expect(container.firstElementChild).toBe(pill); }); }); describe("LedgerRow", () => { it("renders permanent readout cells with mono values and hairline separators", () => { const cells = [ { label: "Msns", value: "3", mono: true }, { label: "Duration", value: "4h 0m", mono: true }, { label: "State", value: "Contested" }, ] as const; const { container } = render(h(LedgerRow, { cells })); const row = container.querySelector('[data-slot="ledger-row"]') as HTMLElement; expect(row.tagName).toBe("FOOTER"); expect(row.className).toContain("border-t"); expect(row.className).toContain("bg-black/60"); const rendered = Array.from(row.querySelectorAll("span")).map((v) => v.textContent); expect(rendered).toContain("3"); expect(rendered).toContain("4h 0m"); expect(rendered).toContain("Contested"); const hairlines = row.querySelectorAll(".border-r"); expect(hairlines.length).toBe(cells.length); }); it("renders nothing when empty", () => { const { container } = render(h(LedgerRow, { cells: [] })); const row = container.querySelector('[data-slot="ledger-row"]') as HTMLElement; expect(row.className).toContain("hidden"); }); }); describe("ProvenanceChip", () => { it("renders a plain marker without href", () => { const { container } = render(h(ProvenanceChip, { label: "OP 42" })); const chip = container.querySelector('[data-slot="provenance-chip"]') as HTMLElement; expect(chip.tagName).toBe("SPAN"); expect(chip.textContent).toBe("OP 42"); expect(chip.className).toContain("font-mono"); }); it("renders a keyboard-focusable link with href", () => { const { container } = render(h(ProvenanceChip, { label: "OP 42", href: "/logistics/structures/1" })); const chip = container.querySelector('[data-slot="provenance-chip"]') as HTMLElement; expect(chip.tagName).toBe("A"); expect(chip.getAttribute("href")).toBe("/logistics/structures/1"); expect(chip.className).toContain("focus-visible:ring-2"); }); }); describe("NoticeState", () => { it("renders empty and loading variants as polite status with aria-busy on loading", () => { const { container } = render( h("div", null, h(NoticeState, { variant: "empty", message: "No operations yet", hint: "Run an op to populate the ledger." }), h(NoticeState, { variant: "loading", message: "Loading operation ledger" }), ), ); const notices = container.querySelectorAll('[data-slot="notice-state"]'); expect(notices.length).toBe(2); const empty = notices[0] as HTMLElement; const loading = notices[1] as HTMLElement; expect(empty.getAttribute("data-variant")).toBe("empty"); expect(empty.getAttribute("role")).toBe("status"); expect(empty.className).not.toContain("rose"); expect(empty.textContent).toContain("No operations yet"); expect(loading.getAttribute("data-variant")).toBe("loading"); expect(loading.getAttribute("role")).toBe("status"); expect(loading.getAttribute("aria-busy")).toBe("true"); }); it("renders the error variant as an assertive alert", () => { render(h(NoticeState, { variant: "error", message: "Failed effect", hint: "Replay from reconciliation." })); const alert = screen.getByRole("alert"); expect(alert.getAttribute("data-variant")).toBe("error"); expect(alert.className).toContain("border-rose-500/30"); }); }); describe("StrategicSummary", () => { it("composes strip, brackets, grid texture, content, and readout footer", () => { const { container } = render( h(StrategicSummary, { classificationLeft: "Official // Unit Command", classificationRight: "REF 007", readoutCells: [{ label: "Msns", value: "2", mono: true }], children: h("p", null, "Summary body"), }, ), ); const surface = container.querySelector('[data-slot="strategic-summary"]') as HTMLElement; expect(surface.className).toContain("rounded-none"); within(surface).getByText("Official // Unit Command"); within(surface).getByText("REF 007"); expect(surface.querySelector('[data-slot="corner-brackets"]')).not.toBeNull(); expect(surface.querySelector('[data-slot="ledger-row"]')).not.toBeNull(); expect(surface.textContent).toContain("Summary body"); const texture = surface.querySelector('div[style*="linear-gradient"]') as HTMLElement; expect(texture?.getAttribute("aria-hidden")).toBe("true"); expect(texture?.style.backgroundSize).toBe("28px 28px"); }); }); describe("PageShell", () => { it("renders the title, meta strip, and content responsively", () => { render( h(PageShell, { title: "Operation Ledger", meta: "Command // Weekly", children: h("p", null, "Shell content") }), ); const heading = screen.getByRole("heading", { level: 1 }); expect(heading.textContent).toContain("Operation Ledger"); expect(screen.getByText("Command // Weekly")).toBeDefined(); expect(screen.getByText("Shell content")).toBeDefined(); }); });