import { describe, expect, test } from "bun:test"; import { createInitialAppState } from "@editor/initial-state"; import { toolEnterMaskEditCommand, toolEnterTemporaryPanCommand, toolExitMaskEditCommand, toolExitTemporaryPanCommand, toolSetActiveCommand, toolSetBrushPreviewCommand, toolSetBrushSettingsCommand, toolSetBrushStrokePreviewCommand, toolSetChromaKeySettingsCommand, toolSetGenerateSettingsCommand, toolSetMaskViewModeCommand } from "./tool"; const defaultBrush = { color: "#111827", size: 8, hardness: 100 }; const defaultChromaKey = { color: "#00ff00", tolerance: 32, softness: 24, feather: 0, choke: 0, despeckle: 0, spill: 50 }; const defaultMagicWand = { tolerance: 32, feather: 0, choke: 0, despeckle: 0, contiguous: true, mode: "replace" as const }; const defaultGenerate = { architecture: "sdxl" as const, mode: "text-to-image" as const, model: "auto" as const, textEncoder: "auto", vae: "auto", prompt: "", negativePrompt: "", strength: 75, steps: 30, cfg: 7, seed: -1, sampler: "euler", scheduler: "normal", width: 1024, height: 1024, outpaint: { left: 128, top: 128, right: 128, bottom: 128, feathering: 32 }, inpaint: { maskedAreaOnly: true, cropPadding: 96, maskPolarity: "hidden" as const, maskedContent: "neutral" as const, growMaskBy: 6, maskExpand: 0, maskFeather: 0, maskBlur: 0, maskDespeckle: 0 } }; describe("tool commands", () => { test("sets active tool", () => { const next = toolSetActiveCommand.execute({ state: createInitialAppState("Test") }, { tool: "brush" }); expect(next.editor.tools).toEqual({ activeTool: "brush", interactionMode: { type: "tool", tool: "brush" }, brush: defaultBrush, generate: defaultGenerate, chromaKey: defaultChromaKey, magicWand: defaultMagicWand }); }); test("selecting a persistent tool closes an open operation", () => { const state = createInitialAppState("Test"); state.editor.workspace = { panel: "chromaKey" }; const next = toolSetActiveCommand.execute({ state }, { tool: "brush" }); expect(next.editor.tools.activeTool).toBe("brush"); expect(next.editor.workspace.panel).toBe("none"); }); test("sets brush settings", () => { const next = toolSetBrushSettingsCommand.execute({ state: createInitialAppState("Test") }, { color: "#ff0000", size: 24, hardness: 50 }); expect(next.editor.tools.brush).toEqual({ color: "#ff0000", size: 24, hardness: 50 }); }); test("sets chroma key settings", () => { const next = toolSetChromaKeySettingsCommand.execute({ state: createInitialAppState("Test") }, { color: "#123456", tolerance: 300 }); expect(next.editor.tools.chromaKey).toEqual({ color: "#123456", tolerance: 255, softness: 24, feather: 0, choke: 0, despeckle: 0, spill: 50 }); }); test("sets inpaint generation settings", () => { const next = toolSetGenerateSettingsCommand.execute( { state: createInitialAppState("Test") }, { mode: "inpaint", inpaint: { ...defaultGenerate.inpaint, cropPadding: 5000, growMaskBy: -4, maskExpand: -500, maskBlur: 300, maskPolarity: "revealed", maskedContent: "original" } }, ); expect(next.editor.tools.generate.mode).toBe("inpaint"); expect(next.editor.tools.generate.inpaint).toEqual({ ...defaultGenerate.inpaint, cropPadding: 2048, growMaskBy: 0, maskExpand: -256, maskBlur: 256, maskPolarity: "revealed", maskedContent: "original" }); }); test("applies architecture defaults and filters unsupported modes", () => { const initial = toolSetGenerateSettingsCommand.execute({ state: createInitialAppState("Test") }, { mode: "inpaint" }); const next = toolSetGenerateSettingsCommand.execute({ state: initial }, { architecture: "z-image-turbo" }); expect(next.editor.tools.generate).toMatchObject({ architecture: "z-image-turbo", mode: "text-to-image", model: "auto", textEncoder: "qwen_3_4b.safetensors", vae: "ae.safetensors", steps: 8, cfg: 1, sampler: "res_multistep", scheduler: "simple", }); }); test("sets and clears brush preview", () => { const showing = toolSetBrushPreviewCommand.execute({ state: createInitialAppState("Test") }, { position: { x: 10, y: 20 } }); const cleared = toolSetBrushPreviewCommand.execute({ state: showing }, undefined); expect(showing.editor.brushPreview).toEqual({ position: { x: 10, y: 20 } }); expect(cleared.editor.brushPreview).toBeUndefined(); }); test("sets and clears brush stroke preview", () => { const showing = toolSetBrushStrokePreviewCommand.execute({ state: createInitialAppState("Test") }, { layerId: "layer", assetId: "asset", source: "preview" }); const cleared = toolSetBrushStrokePreviewCommand.execute({ state: showing }, undefined); expect(showing.editor.brushStrokePreview).toEqual({ layerId: "layer", assetId: "asset", source: "preview" }); expect(cleared.editor.brushStrokePreview).toBeUndefined(); }); test("enters and exits mask edit", () => { const editing = toolEnterMaskEditCommand.execute({ state: stateWithMask() }, { targetLayerId: "target", maskLayerId: "mask" }); const exited = toolExitMaskEditCommand.execute({ state: editing }, undefined); expect(editing.editor.maskEdit).toEqual({ targetLayerId: "target", maskLayerId: "mask" }); expect(editing.editor.selection).toEqual({ artboardId: "a1", layerIds: ["target"] }); expect(editing.editor.tools.activeTool).toBe("brush"); expect(exited.editor.maskEdit).toBeUndefined(); }); test("sets mask view mode while editing a mask", () => { const editing = toolEnterMaskEditCommand.execute({ state: stateWithMask() }, { targetLayerId: "target", maskLayerId: "mask" }); const alpha = toolSetMaskViewModeCommand.execute({ state: editing }, { mode: "alpha" }); const ignored = toolSetMaskViewModeCommand.execute({ state: createInitialAppState("Test") }, { mode: "blackWhite" }); expect(alpha.editor.maskEdit).toEqual({ targetLayerId: "target", maskLayerId: "mask", viewMode: "alpha" }); expect(ignored.editor.maskEdit).toBeUndefined(); }); test("enters and exits temporary pan", () => { const initial = createInitialAppState("Test"); const panning = toolEnterTemporaryPanCommand.execute({ state: initial }, undefined); const restored = toolExitTemporaryPanCommand.execute({ state: panning }, undefined); expect(panning.editor.tools).toEqual({ activeTool: "select", interactionMode: { type: "temporary-pan", previousTool: "select" }, brush: defaultBrush, generate: defaultGenerate, chromaKey: defaultChromaKey, magicWand: defaultMagicWand }); expect(restored.editor.tools).toEqual(initial.editor.tools); }); }); function stateWithMask() { return { ...createInitialAppState("Test"), document: { ...createInitialAppState("Test").document, artboards: [ { id: "a1", name: "Artboard 1", bounds: { x: 0, y: 0, w: 320, h: 240 }, backgroundColor: "transparent" as const, visible: true, locked: false, layers: [ raster("mask", "Mask"), { ...raster("target", "Target"), clippingMask: { maskLayerId: "mask" } }, ], }, ], }, }; } function raster(id: string, name: string) { return { id, type: "raster" as const, name, visible: true, locked: false, opacity: 1, assetId: `${id}-asset`, transform: { position: { x: 0, y: 0 }, scale: { x: 1, y: 1 }, rotation: 0 }, }; }