feat: expand sudoku analysis and interoperability
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
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");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user