import { render, screen, waitFor, within } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { describe, expect, it, vi } from "vitest"; import { CandidateLab } from "../../src/components/CandidateLab"; import { createEmptyPuzzle, normalizePuzzle } from "../../src/domain"; import type { CandidateOverlay } from "../../src/helpers"; function mask(...values: number[]): number { return values.reduce((result, value) => result | (1 << (value - 1)), 0); } const puzzle = normalizePuzzle(createEmptyPuzzle(4)); describe("candidate lab", () => { it("inspects selected cells, filters digits and focuses a link overlay", async () => { const user = userEvent.setup(); const overlays: (CandidateOverlay | undefined)[] = []; const candidateMasks = new Array(16).fill(0); candidateMasks[0] = mask(1, 2); candidateMasks[1] = mask(1, 2); render( overlays.push(overlay)} />, ); const selected = screen.getByRole("heading", { name: "Selected cells", }).parentElement!; expect(within(selected).getByText("r1c1")).toBeInTheDocument(); expect(within(selected).getByText("1 2")).toBeInTheDocument(); await user.click( screen.getByRole("button", { name: "Filter candidate 1" }), ); await waitFor(() => { expect(overlays.at(-1)?.activeValues).toEqual([1]); expect(overlays.at(-1)?.candidateCells).toEqual([0, 1]); }); const link = screen.getByRole("button", { name: /r1c1\(1\).*r1c2\(1\)/u }); await user.click(link); await waitFor(() => expect(overlays.at(-1)?.links).toHaveLength(1)); expect(link).toHaveAttribute("aria-pressed", "true"); await user.click(screen.getByRole("button", { name: "Show all" })); expect(link).toHaveAttribute("aria-pressed", "false"); }); it("reveals weak links on demand within a chosen house", async () => { const user = userEvent.setup(); const candidateMasks = new Array(16).fill(0); candidateMasks[0] = mask(3); candidateMasks[1] = mask(3); candidateMasks[2] = mask(3); render( , ); await user.selectOptions( screen.getByLabelText("Candidate house scope"), "unit:0", ); await user.click( screen.getByRole("button", { name: "Filter candidate 3" }), ); expect(screen.getByText(/No links match this scope/u)).toBeInTheDocument(); await user.click(screen.getByRole("checkbox", { name: "Weak links" })); expect( screen.getAllByRole("button", { name: /weak ยท Row 1/u }), ).toHaveLength(3); }); it("clears the board overlay when it unmounts", async () => { const onOverlayChange = vi.fn(); const { unmount } = render( (16).fill(0)} selectedCells={[0]} onOverlayChange={onOverlayChange} />, ); await waitFor(() => expect(onOverlayChange).toHaveBeenCalled()); unmount(); expect(onOverlayChange).toHaveBeenLastCalledWith(undefined); }); });