feat: add gameplay assists and variant generator
This commit is contained in:
@@ -63,6 +63,102 @@ describe("Sudoku workbench", () => {
|
||||
expect(undo).toBeDisabled();
|
||||
});
|
||||
|
||||
it("shows digit progress and toggles matching-digit highlights separately from selection", async () => {
|
||||
const user = userEvent.setup();
|
||||
render(<Workbench />);
|
||||
|
||||
const completion = screen.getByRole("group", {
|
||||
name: "Highlight matching digits",
|
||||
});
|
||||
expect(within(completion).getAllByRole("button")).toHaveLength(9);
|
||||
|
||||
const grid = screen.getByRole("grid", { name: "9 by 9 Sudoku grid" });
|
||||
const four = within(grid).getByRole("gridcell", {
|
||||
name: "Row 1, column 1, 4",
|
||||
});
|
||||
fireEvent.pointerDown(four, { buttons: 1, ctrlKey: true });
|
||||
|
||||
const highlighted = grid.querySelectorAll(".is-digit-highlighted");
|
||||
expect(highlighted.length).toBeGreaterThan(1);
|
||||
expect(four).toHaveAttribute("aria-selected", "true");
|
||||
|
||||
fireEvent.pointerDown(four, { buttons: 1, ctrlKey: true });
|
||||
expect(grid.querySelectorAll(".is-digit-highlighted")).toHaveLength(0);
|
||||
|
||||
await user.click(screen.getByLabelText("Show digit completion bar"));
|
||||
expect(
|
||||
screen.queryByRole("group", { name: "Highlight matching digits" }),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("replaces and removes setter cages through the selected cells", async () => {
|
||||
const user = userEvent.setup();
|
||||
render(<Workbench />);
|
||||
|
||||
await user.click(screen.getByRole("button", { name: "New blank" }));
|
||||
const grid = screen.getByRole("grid", { name: "9 by 9 Sudoku grid" });
|
||||
fireEvent.pointerDown(
|
||||
within(grid).getByRole("gridcell", {
|
||||
name: "Row 1, column 2, empty",
|
||||
}),
|
||||
{ buttons: 1, shiftKey: true },
|
||||
);
|
||||
|
||||
const cageSum = screen.getByRole("spinbutton", { name: "Cage sum" });
|
||||
await user.clear(cageSum);
|
||||
await user.type(cageSum, "3");
|
||||
await user.click(
|
||||
screen.getByRole("button", { name: "Add / replace cage" }),
|
||||
);
|
||||
expect(screen.getByText("3 cage · 2 cells")).toBeInTheDocument();
|
||||
|
||||
await user.clear(cageSum);
|
||||
await user.type(cageSum, "4");
|
||||
await user.click(
|
||||
screen.getByRole("button", { name: "Add / replace cage" }),
|
||||
);
|
||||
expect(screen.queryByText("3 cage · 2 cells")).not.toBeInTheDocument();
|
||||
expect(screen.getByText("4 cage · 2 cells")).toBeInTheDocument();
|
||||
|
||||
await user.click(
|
||||
screen.getByRole("button", { name: "Remove selected cage" }),
|
||||
);
|
||||
expect(screen.queryByText("4 cage · 2 cells")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("opens the expanded built-in variant examples", async () => {
|
||||
const user = userEvent.setup();
|
||||
const { container } = render(<Workbench />);
|
||||
|
||||
await user.selectOptions(
|
||||
screen.getByLabelText("Open built-in puzzle"),
|
||||
"thermo",
|
||||
);
|
||||
expect(
|
||||
screen.getByRole("heading", { name: "Warm fronts" }),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole("grid", { name: "6 by 6 Sudoku grid" }),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
container.querySelectorAll(".constraint-thermo").length,
|
||||
).toBeGreaterThan(0);
|
||||
|
||||
await user.selectOptions(
|
||||
screen.getByLabelText("Open built-in puzzle"),
|
||||
"xv",
|
||||
);
|
||||
expect(
|
||||
screen.getByRole("heading", { name: "Five or ten" }),
|
||||
).toBeInTheDocument();
|
||||
expect(container.querySelector(".constraint-xv--5 text")).toHaveTextContent(
|
||||
"5",
|
||||
);
|
||||
expect(
|
||||
container.querySelector(".constraint-xv--10 text"),
|
||||
).toHaveTextContent("10");
|
||||
});
|
||||
|
||||
it("switches between setting, solving, playing and helper workspaces", async () => {
|
||||
const user = userEvent.setup();
|
||||
render(<Workbench />);
|
||||
@@ -75,6 +171,14 @@ describe("Sudoku workbench", () => {
|
||||
screen.getByRole("heading", { name: "Enter givens" }),
|
||||
).toBeInTheDocument();
|
||||
|
||||
await user.click(screen.getByRole("button", { name: "Generate" }));
|
||||
expect(
|
||||
screen.getByRole("heading", { name: "Sudoku generator" }),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole("button", { name: "Rate current puzzle" }),
|
||||
).toBeInTheDocument();
|
||||
|
||||
await user.click(screen.getByRole("button", { name: "Solve" }));
|
||||
expect(
|
||||
screen.getByRole("heading", { name: "Solve and verify" }),
|
||||
|
||||
Reference in New Issue
Block a user