feat: complete advanced Sudoku workbench
This commit is contained in:
@@ -4,7 +4,10 @@ import { describe, expect, it, vi } from "vitest";
|
||||
import { ImportExportDialog } from "../../src/components/ImportExportDialog";
|
||||
import { createEmptyPuzzle } from "../../src/domain";
|
||||
import type { PuzzleDefinition } from "../../src/domain/types";
|
||||
import { fromDomainPuzzle } from "../../src/formats";
|
||||
import {
|
||||
fromDomainPuzzle,
|
||||
type PreservedSudokuDocumentExtras,
|
||||
} from "../../src/formats";
|
||||
import type { PortableAidMemoire } from "../../src/state/aidMemoire";
|
||||
import { createSession } from "../../src/state/session";
|
||||
|
||||
@@ -40,6 +43,7 @@ function renderDialog(
|
||||
options: {
|
||||
readonly puzzle?: PuzzleDefinition;
|
||||
readonly aidMemoire?: PortableAidMemoire;
|
||||
readonly preservedExtras?: PreservedSudokuDocumentExtras;
|
||||
} = {},
|
||||
) {
|
||||
const puzzle = options.puzzle ?? createEmptyPuzzle(4);
|
||||
@@ -51,6 +55,7 @@ function renderDialog(
|
||||
puzzle={puzzle}
|
||||
session={createSession(puzzle.givens)}
|
||||
aidMemoire={options.aidMemoire}
|
||||
preservedExtras={options.preservedExtras}
|
||||
onClose={onClose}
|
||||
onImport={onImport}
|
||||
/>,
|
||||
@@ -79,11 +84,14 @@ describe("ImportExportDialog interoperability", () => {
|
||||
expect(onImport).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ size: 4, givens: expect.any(Array) }),
|
||||
expect.any(Object),
|
||||
expect.objectContaining({
|
||||
source: { format: "sudokupad", id: "synthetic-local-test" },
|
||||
}),
|
||||
);
|
||||
expect(onClose).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it("reports unsupported constructs and never fetches short IDs", async () => {
|
||||
it("previews safe visuals and never fetches short IDs", async () => {
|
||||
const user = userEvent.setup();
|
||||
const fetchSpy = vi.fn();
|
||||
vi.stubGlobal("fetch", fetchSpy);
|
||||
@@ -91,12 +99,35 @@ describe("ImportExportDialog interoperability", () => {
|
||||
const input = screen.getByPlaceholderText(/Paste 81 characters/u);
|
||||
|
||||
fireEvent.change(input, {
|
||||
target: { value: localScl({ overlays: [{ text: "visual only" }] }) },
|
||||
target: {
|
||||
value: localScl({
|
||||
overlays: [
|
||||
{
|
||||
center: [0.5, 0.5],
|
||||
width: 1,
|
||||
height: 1,
|
||||
text: "visual only",
|
||||
},
|
||||
],
|
||||
}),
|
||||
},
|
||||
});
|
||||
await user.click(
|
||||
screen.getByRole("button", { name: "Check compatibility" }),
|
||||
);
|
||||
expect(await screen.findByText(/visual overlays/u)).toBeInTheDocument();
|
||||
expect(
|
||||
await screen.findByRole("region", { name: "Import mapping preview" }),
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByText("Preserved visuals")).toBeInTheDocument();
|
||||
expect(screen.getByText("Text overlay: 1")).toBeInTheDocument();
|
||||
|
||||
fireEvent.change(input, {
|
||||
target: { value: localScl({ overlays: [{ text: "missing center" }] }) },
|
||||
});
|
||||
await user.click(
|
||||
screen.getByRole("button", { name: "Check compatibility" }),
|
||||
);
|
||||
expect(await screen.findByText(/center.*point/u)).toBeInTheDocument();
|
||||
|
||||
fireEvent.change(input, {
|
||||
target: { value: "https://sudokupad.app/serverOnly42" },
|
||||
@@ -164,6 +195,47 @@ describe("ImportExportDialog interoperability", () => {
|
||||
expect(onImport).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ size: 4 }),
|
||||
expect.objectContaining({ aidMemoire: TEST_AID_MEMOIRE }),
|
||||
{ source: { format: "sudoku-tools" } },
|
||||
);
|
||||
});
|
||||
|
||||
it("includes preserved source extras in SudokuPad exports", async () => {
|
||||
const user = userEvent.setup();
|
||||
let downloaded: Blob | undefined;
|
||||
vi.mocked(URL.createObjectURL).mockImplementation((value) => {
|
||||
downloaded = value as Blob;
|
||||
return "blob:scl-export-test";
|
||||
});
|
||||
vi.spyOn(HTMLAnchorElement.prototype, "click").mockImplementation(() => {});
|
||||
renderDialog({
|
||||
preservedExtras: {
|
||||
source: { format: "sudokupad", id: "kept-source" },
|
||||
metadata: { edition: "nightly" },
|
||||
visuals: [
|
||||
{
|
||||
type: "text",
|
||||
layer: "overlay",
|
||||
position: { kind: "cell", cell: 0 },
|
||||
text: "kept visual",
|
||||
style: { fill: "#123456" },
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
await user.click(
|
||||
screen.getByRole("button", { name: "Download SudokuPad JSON" }),
|
||||
);
|
||||
|
||||
const exported = JSON.parse((await downloaded?.text()) ?? "{}") as {
|
||||
metadata?: Record<string, unknown>;
|
||||
overlays?: unknown[];
|
||||
};
|
||||
expect(exported.metadata?.edition).toBe("nightly");
|
||||
expect(exported.overlays).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({ text: "kept visual" }),
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user