feat: launch local-first Sudoku workbench
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
import { fireEvent, render, screen, within } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { beforeAll, describe, expect, it, vi } from "vitest";
|
||||
import { Workbench } from "../../src/components/Workbench";
|
||||
|
||||
class WorkerStub {
|
||||
addEventListener() {}
|
||||
postMessage() {}
|
||||
terminate() {}
|
||||
}
|
||||
|
||||
beforeAll(() => {
|
||||
vi.stubGlobal("Worker", WorkerStub);
|
||||
});
|
||||
|
||||
describe("Sudoku workbench", () => {
|
||||
it("opens with the local classic example rendered as an accessible grid", () => {
|
||||
render(<Workbench />);
|
||||
|
||||
expect(
|
||||
screen.getByRole("heading", { name: "A first classic" }),
|
||||
).toBeInTheDocument();
|
||||
const grid = screen.getByRole("grid", { name: "9 by 9 Sudoku grid" });
|
||||
expect(within(grid).getAllByRole("gridcell")).toHaveLength(81);
|
||||
expect(
|
||||
within(grid).getByRole("gridcell", {
|
||||
name: "Row 1, column 1, 4",
|
||||
}),
|
||||
).toHaveClass("is-given");
|
||||
expect(
|
||||
within(grid).getByRole("gridcell", {
|
||||
name: "Row 1, column 3, empty",
|
||||
}),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("enters a digit in an empty cell and restores it with undo", async () => {
|
||||
const user = userEvent.setup();
|
||||
render(<Workbench />);
|
||||
|
||||
const emptyCell = screen.getByRole("gridcell", {
|
||||
name: "Row 1, column 3, empty",
|
||||
});
|
||||
fireEvent.pointerDown(emptyCell, { buttons: 1 });
|
||||
await user.click(
|
||||
within(screen.getByRole("group", { name: "Digits" })).getByRole(
|
||||
"button",
|
||||
{ name: "2" },
|
||||
),
|
||||
);
|
||||
|
||||
expect(
|
||||
screen.getByRole("gridcell", { name: "Row 1, column 3, 2" }),
|
||||
).toBeInTheDocument();
|
||||
const undo = screen.getByRole("button", { name: "Undo" });
|
||||
expect(undo).toBeEnabled();
|
||||
await user.click(undo);
|
||||
expect(
|
||||
screen.getByRole("gridcell", {
|
||||
name: "Row 1, column 3, empty",
|
||||
}),
|
||||
).toBeInTheDocument();
|
||||
expect(undo).toBeDisabled();
|
||||
});
|
||||
|
||||
it("switches between setting, solving, playing and helper workspaces", async () => {
|
||||
const user = userEvent.setup();
|
||||
render(<Workbench />);
|
||||
|
||||
await user.click(screen.getByRole("button", { name: "Set" }));
|
||||
expect(
|
||||
screen.getByRole("heading", { name: "Set a puzzle" }),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole("heading", { name: "Enter givens" }),
|
||||
).toBeInTheDocument();
|
||||
|
||||
await user.click(screen.getByRole("button", { name: "Solve" }));
|
||||
expect(
|
||||
screen.getByRole("heading", { name: "Solve and verify" }),
|
||||
).toBeInTheDocument();
|
||||
|
||||
await user.click(screen.getByRole("button", { name: "Helpers" }));
|
||||
expect(
|
||||
screen.getByRole("heading", { name: "Sudoku helpers" }),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole("tab", { name: "Killer combinations" }),
|
||||
).toHaveAttribute("aria-selected", "true");
|
||||
expect(document.querySelector(".helper-result")).toHaveTextContent(
|
||||
"combinations",
|
||||
);
|
||||
|
||||
await user.click(screen.getByRole("tab", { name: "45-rule residual" }));
|
||||
expect(
|
||||
screen.getByLabelText("Accounted values or cage sums"),
|
||||
).toBeInTheDocument();
|
||||
|
||||
await user.click(screen.getByRole("button", { name: "Play" }));
|
||||
expect(
|
||||
screen.getByRole("heading", { name: "Enter your solve" }),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("makes the import boundary and self-contained local sharing explicit", async () => {
|
||||
const user = userEvent.setup();
|
||||
const fetchSpy = vi.fn();
|
||||
vi.stubGlobal("fetch", fetchSpy);
|
||||
render(<Workbench />);
|
||||
|
||||
await user.click(screen.getByRole("button", { name: "Import / export" }));
|
||||
expect(
|
||||
screen.getByRole("heading", { name: "Import and export" }),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(/Server-only short IDs are never fetched\./u),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(/Share links are self-contained\./u),
|
||||
).toBeInTheDocument();
|
||||
|
||||
await user.click(
|
||||
screen.getByRole("button", { name: "Copy local share URL" }),
|
||||
);
|
||||
expect(
|
||||
await screen.findByText("Local share URL copied."),
|
||||
).toBeInTheDocument();
|
||||
expect(fetchSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user