1
0
Fork 0
polaris-task-force/tests/int/operation-ui-primitives.int.spec.ts
Z8MB1E c19d0d05ee feat(ui): tactical operation primitives and role surfaces
Reusable dossier primitives (classification strips, brackets, readouts, provenance chips, notice states) plus server-rendered /operations overview, ledger drill-down, and AAR with permission-gated sections and an authorized reconciliation panel. Realtime refresh is enhancement only.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-20 02:44:53 -04:00

184 lines
7.6 KiB
TypeScript

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();
});
});