149 lines
4.9 KiB
TypeScript
149 lines
4.9 KiB
TypeScript
import { useState } from "react";
|
|
import { fireEvent, render, screen, within } from "@testing-library/react";
|
|
import userEvent from "@testing-library/user-event";
|
|
import { describe, expect, it, vi } from "vitest";
|
|
import { AidMemoire } from "../../src/components/AidMemoire";
|
|
import {
|
|
configureAidMemoire,
|
|
createAidMemoire,
|
|
type AidMemoireState,
|
|
} from "../../src/state/aidMemoire";
|
|
import type { EntryMode } from "../../src/state/session";
|
|
|
|
function Harness({
|
|
initial,
|
|
readOnly = false,
|
|
}: {
|
|
initial?: AidMemoireState;
|
|
readOnly?: boolean;
|
|
}) {
|
|
const [state, setState] = useState(
|
|
initial ?? createAidMemoire(9, { enabled: true }),
|
|
);
|
|
const [selected, setSelected] = useState(0);
|
|
const [active, setActive] = useState(false);
|
|
const [mode, setMode] = useState<EntryMode>("value");
|
|
return (
|
|
<AidMemoire
|
|
size={9}
|
|
state={state}
|
|
selectedCell={selected}
|
|
active={active}
|
|
readOnly={readOnly}
|
|
mode={mode}
|
|
onStateChange={setState}
|
|
onSelect={(cell) => {
|
|
setSelected(cell);
|
|
setActive(true);
|
|
}}
|
|
onMode={setMode}
|
|
/>
|
|
);
|
|
}
|
|
|
|
describe("aid-mémoire component", () => {
|
|
it("renders normal-like cells with keyboard entry and full descriptions", async () => {
|
|
const user = userEvent.setup();
|
|
render(<Harness />);
|
|
|
|
const grid = screen.getByRole("grid", {
|
|
name: "9 aid-mémoire scratch cells",
|
|
});
|
|
expect(within(grid).getAllByRole("row")).toHaveLength(1);
|
|
const first = within(grid).getByRole("gridcell", {
|
|
name: "Aid-mémoire cell 1, label 1, empty",
|
|
});
|
|
expect(first).toHaveAttribute("aria-colindex", "1");
|
|
await user.click(first);
|
|
await user.keyboard("4");
|
|
expect(
|
|
within(grid).getByRole("gridcell", {
|
|
name: "Aid-mémoire cell 1, label 1, value 4",
|
|
}),
|
|
).toHaveAttribute("aria-selected", "true");
|
|
|
|
const second = within(grid).getByRole("gridcell", {
|
|
name: "Aid-mémoire cell 2, label 2, empty",
|
|
});
|
|
second.focus();
|
|
await user.keyboard("c7");
|
|
expect(
|
|
within(grid).getByRole("gridcell", {
|
|
name: "Aid-mémoire cell 2, label 2, empty, centre marks 7",
|
|
}),
|
|
).toBeInTheDocument();
|
|
expect(screen.getByRole("button", { name: "Centre" })).toHaveAttribute(
|
|
"aria-pressed",
|
|
"true",
|
|
);
|
|
});
|
|
|
|
it("uses row-aware WAI grid navigation without horizontal wrapping", () => {
|
|
const initial = configureAidMemoire(
|
|
createAidMemoire(9, { enabled: true }),
|
|
9,
|
|
5,
|
|
2,
|
|
);
|
|
render(<Harness initial={initial} />);
|
|
const cells = screen.getAllByRole("gridcell");
|
|
const rows = screen.getAllByRole("row");
|
|
expect(rows[0]).toHaveAttribute("aria-rowindex", "1");
|
|
expect(rows[2]).toHaveAttribute("aria-rowindex", "3");
|
|
expect(cells[2]).toHaveAttribute("aria-colindex", "1");
|
|
|
|
cells[1]!.focus();
|
|
fireEvent.keyDown(cells[1]!, { key: "ArrowRight" });
|
|
expect(document.activeElement).toBe(cells[1]);
|
|
fireEvent.keyDown(cells[1]!, { key: "Home" });
|
|
expect(document.activeElement).toBe(cells[0]);
|
|
fireEvent.keyDown(cells[0]!, { key: "End", ctrlKey: true });
|
|
expect(document.activeElement).toBe(cells[4]);
|
|
fireEvent.keyDown(cells[4]!, { key: "PageUp" });
|
|
expect(document.activeElement).toBe(cells[0]);
|
|
fireEvent.keyDown(cells[0]!, { key: "PageDown" });
|
|
expect(document.activeElement).toBe(cells[4]);
|
|
});
|
|
|
|
it("keeps read-only replay cells navigable without allowing edits", () => {
|
|
const initial = configureAidMemoire(
|
|
createAidMemoire(9, { enabled: true }),
|
|
9,
|
|
4,
|
|
2,
|
|
);
|
|
render(<Harness initial={initial} readOnly />);
|
|
const cells = screen.getAllByRole("gridcell");
|
|
|
|
cells[0]!.focus();
|
|
fireEvent.keyDown(cells[0]!, { key: "ArrowDown" });
|
|
expect(document.activeElement).toBe(cells[2]);
|
|
fireEvent.keyDown(cells[2]!, { key: "5" });
|
|
expect(cells[2]).toHaveAccessibleName("Aid-mémoire cell 3, label 3, empty");
|
|
});
|
|
|
|
it("edits labels, reflows, clears entries and resets with confirmation", async () => {
|
|
const user = userEvent.setup();
|
|
vi.spyOn(window, "confirm").mockReturnValue(true);
|
|
render(<Harness />);
|
|
|
|
const label = screen.getByLabelText("Selected cell label");
|
|
await user.clear(label);
|
|
await user.type(label, "Pseudo A");
|
|
expect(
|
|
screen.getByRole("gridcell", {
|
|
name: "Aid-mémoire cell 1, label Pseudo A, empty",
|
|
}),
|
|
).toBeInTheDocument();
|
|
|
|
await user.click(screen.getByText("Configure scratch layout"));
|
|
await user.click(screen.getByRole("button", { name: "Compact grid" }));
|
|
expect(screen.getByLabelText("Columns")).toHaveValue(3);
|
|
await user.click(screen.getByRole("button", { name: "Clear entries" }));
|
|
await user.click(screen.getByRole("button", { name: "Reset all" }));
|
|
expect(window.confirm).toHaveBeenCalledTimes(2);
|
|
expect(screen.getByLabelText("Columns")).toHaveValue(9);
|
|
expect(screen.getByLabelText("Selected cell label")).toHaveValue("1");
|
|
});
|
|
});
|