Files
image-studio/commands/history.test.ts
2026-07-04 15:49:13 +02:00

108 lines
4.6 KiB
TypeScript

import { describe, expect, test } from "bun:test";
import { createInitialAppState } from "@editor/initial-state";
import { createAppStore } from "@editor/store";
import { documentAddArtboardCommand } from "./document";
import { historyCommands } from "./history";
import { commandIds } from "./ids";
import { createCommandRegistry } from "./registry";
import { transformCommands } from "./transform";
const registry = createCommandRegistry([documentAddArtboardCommand, ...historyCommands, ...transformCommands]);
describe("history commands", () => {
test("records document changes and undoes/redoes them", () => {
const store = createAppStore(createInitialAppState("Test"), registry);
store.dispatch(commandIds.documentAddArtboard, { id: "a1", name: "Artboard", bounds: { x: 0, y: 0, w: 100, h: 100 } });
expect(store.getState().document.artboards.map((artboard) => artboard.id)).toEqual(["a1"]);
expect(store.getState().history.past).toHaveLength(1);
store.dispatch(commandIds.historyUndo, undefined);
expect(store.getState().document.artboards).toEqual([]);
expect(store.getState().history.future).toHaveLength(1);
store.dispatch(commandIds.historyRedo, undefined);
expect(store.getState().document.artboards.map((artboard) => artboard.id)).toEqual(["a1"]);
});
test("records one history entry for a transform drag", () => {
const store = createAppStore(artboardState(), registry);
store.dispatch(commandIds.transformBegin, {
target: { type: "artboard", id: "a1" },
handle: "body",
point: { x: 0, y: 0 },
initialBounds: { x: 0, y: 0, w: 100, h: 80 },
});
store.dispatch(commandIds.transformUpdate, { point: { x: 5, y: 10 } });
store.dispatch(commandIds.transformUpdate, { point: { x: 10, y: 20 } });
store.dispatch(commandIds.transformUpdate, { point: { x: 15, y: 25 } });
expect(store.getState().document.artboards[0]?.bounds).toEqual({ x: 15, y: 25, w: 100, h: 80 });
expect(store.getState().history.past).toHaveLength(0);
store.dispatch(commandIds.transformEnd, undefined);
expect(store.getState().editor.transformSession).toBeUndefined();
expect(store.getState().history.past).toHaveLength(1);
expect(store.getState().history.past[0]?.document.artboards[0]?.bounds).toEqual({ x: 0, y: 0, w: 100, h: 80 });
expect(store.getState().history.past[0]?.editor.transformSession).toBeUndefined();
store.dispatch(commandIds.historyUndo, undefined);
expect(store.getState().document.artboards[0]?.bounds).toEqual({ x: 0, y: 0, w: 100, h: 80 });
expect(store.getState().editor.transformSession).toBeUndefined();
expect(store.getState().history.future).toHaveLength(1);
});
test("keeps direct transform bounds edits normally undoable", () => {
const store = createAppStore(artboardState(), registry);
store.dispatch(commandIds.transformSetBounds, { target: { type: "artboard", id: "a1" }, bounds: { x: 12, y: 24, w: 120, h: 90 } });
expect(store.getState().document.artboards[0]?.bounds).toEqual({ x: 12, y: 24, w: 120, h: 90 });
expect(store.getState().history.past).toHaveLength(1);
store.dispatch(commandIds.historyUndo, undefined);
expect(store.getState().document.artboards[0]?.bounds).toEqual({ x: 0, y: 0, w: 100, h: 80 });
});
test("does not record history for transform update or end without a session", () => {
const store = createAppStore(artboardState(), registry);
store.dispatch(commandIds.transformUpdate, { point: { x: 10, y: 20 } });
store.dispatch(commandIds.transformEnd, undefined);
expect(store.getState().document.artboards[0]?.bounds).toEqual({ x: 0, y: 0, w: 100, h: 80 });
expect(store.getState().history.past).toHaveLength(0);
expect(store.getState().history.future).toHaveLength(0);
});
test("does not record history for a transform session with no document update", () => {
const store = createAppStore(artboardState(), registry);
store.dispatch(commandIds.transformBegin, {
target: { type: "artboard", id: "a1" },
handle: "body",
point: { x: 0, y: 0 },
initialBounds: { x: 0, y: 0, w: 100, h: 80 },
});
store.dispatch(commandIds.transformEnd, undefined);
expect(store.getState().editor.transformSession).toBeUndefined();
expect(store.getState().document.artboards[0]?.bounds).toEqual({ x: 0, y: 0, w: 100, h: 80 });
expect(store.getState().history.past).toHaveLength(0);
});
});
function artboardState() {
return documentAddArtboardCommand.execute(
{ state: createInitialAppState("Test") },
{ id: "a1", name: "Artboard", bounds: { x: 0, y: 0, w: 100, h: 80 } },
);
}