fix: stabilize Sudoku workspace layout

This commit is contained in:
2026-08-31 16:14:46 +02:00
parent 0a1bdc1a8c
commit ca7a6270d0
17 changed files with 194 additions and 32 deletions
+89
View File
@@ -65,6 +65,95 @@ test("loads standalone and keeps the core play workflow local", async ({
expect(runtimeErrors).toEqual([]);
});
test("keeps the board, keypad and solver controls within their layouts", async ({
page,
}) => {
await page.setViewportSize({ width: 1440, height: 1000 });
await page.goto("/deep/nested/sudoku/");
const frame = page.locator(".sudoku-board-frame");
const sidebar = page.locator(".side-panel");
const boardColumn = page.locator(".board-column");
const scroller = page.locator(".board-viewport__scroller");
await expect(frame).toBeVisible();
const fittedWidth = (await frame.boundingBox())?.width ?? 0;
expect(fittedWidth).toBeGreaterThan(0);
expect(
await scroller.evaluate(
(element) => element.scrollHeight <= element.clientHeight + 1,
),
).toBe(true);
const digits = page.getByRole("group", { name: "Digits" });
const digitBoxes = await Promise.all(
["1", "2", "3", "4", "7", "9"].map(async (digit) =>
digits.getByRole("button", { name: digit, exact: true }).boundingBox(),
),
);
const [one, two, three, four, seven, nine] = digitBoxes;
const erase = await digits
.getByRole("button", { name: "Erase" })
.boundingBox();
for (const box of [...digitBoxes, erase]) expect(box).not.toBeNull();
expect(Math.abs(one!.y - two!.y)).toBeLessThan(1);
expect(Math.abs(two!.y - three!.y)).toBeLessThan(1);
expect(Math.abs(one!.x - four!.x)).toBeLessThan(1);
expect(Math.abs(four!.x - seven!.x)).toBeLessThan(1);
expect(four!.y).toBeGreaterThan(one!.y + one!.height);
expect(seven!.y).toBeGreaterThan(four!.y + four!.height);
expect(Math.abs(erase!.x - one!.x)).toBeLessThan(1);
expect(
Math.abs(erase!.x + erase!.width - (three!.x + three!.width)),
).toBeLessThan(1);
expect(erase!.y).toBeGreaterThan(nine!.y + nine!.height);
await page.getByRole("button", { name: "Zoom board out" }).click();
await expect(page.getByLabel("Board zoom level")).toHaveText("75%");
const reducedWidth = (await frame.boundingBox())?.width ?? 0;
expect(reducedWidth / fittedWidth).toBeCloseTo(0.75, 2);
await page.getByRole("button", { name: "Fit board" }).click();
const baselineSidebarWidth = (await sidebar.boundingBox())?.width ?? 0;
const baselineBoardWidth = (await boardColumn.boundingBox())?.width ?? 0;
for (const workspace of ["Set", "Generate", "Solve", "Helpers"]) {
await page.getByRole("button", { name: workspace, exact: true }).click();
expect((await sidebar.boundingBox())?.width ?? 0).toBeCloseTo(
baselineSidebarWidth,
1,
);
expect((await boardColumn.boundingBox())?.width ?? 0).toBeCloseTo(
baselineBoardWidth,
1,
);
}
await page.getByRole("tab", { name: "Candidate links" }).click();
await expect(
page.getByRole("heading", { name: "Links and houses" }),
).toBeVisible();
expect(
await sidebar.evaluate(
(element) => element.scrollWidth <= element.clientWidth + 1,
),
).toBe(true);
await page.getByRole("button", { name: "Solve", exact: true }).click();
await page.getByRole("button", { name: "Build logical solve path" }).click();
const solveSteps = page.locator(".solve-step");
await expect(solveSteps.first()).toBeVisible({ timeout: 60_000 });
expect(await solveSteps.count()).toBeGreaterThan(0);
expect(
await solveSteps.evaluateAll((steps) =>
steps.every(
(step) =>
step.scrollHeight <= step.clientHeight + 1 &&
step.scrollWidth <= step.clientWidth + 1,
),
),
).toBe(true);
});
test("replaces setter cages and generates a rated variant", async ({
page,
}) => {