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("value"); return ( { 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(); 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(); 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(); 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(); 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"); }); });