import { defineToolcraftCustomControlType } from "../schema/custom-control-type"; import { describe, expect, it } from "vitest"; import { mediaSourceModule } from "../modules/built-ins/media-source/media-source-module"; import { defineToolcraft } from "../schema/define-toolcraft"; import { createToolcraftState } from "./create-template-state"; describe("createToolcraftState", () => { it("requires a canonical Color default and rejects seeded live UI payloads", () => { const app = defineToolcraft({ base: { identity: { id: "runtime-test", title: "Toolcraft App" }, canvas: { enabled: false }, panels: { controls: { sections: [ { id: "test-section-1", controls: { fill: { applicability: { mode: "always" as const }, defaultValue: "#AABBCC", target: "shape.fill", type: "color", }, }, title: "Appearance", }, ], title: "Controls", }, }, }, modules: [], }); const state = createToolcraftState(app, { values: { "shape.fill": { hex: "#223344" } }, }); expect(state.defaults["shape.fill"]).toBe("#AABBCC"); expect(state.values["shape.fill"]).toBe("#AABBCC"); }); it("normalizes restored Infinity canvas to finite when Background is off", () => { const app = defineToolcraft({ base: { identity: { id: "runtime-test", title: "Toolcraft App" }, canvas: { enabled: true, sizing: { mode: "editable-output" }, }, panels: { controls: { sections: [ { id: "test-section-2", controls: { includeBackground: { applicability: { mode: "always" as const }, defaultValue: true, target: "export.includeBackground", type: "switch", }, background: { applicability: { mode: "always" as const }, defaultValue: "#D4CECA", target: "appearance.background", type: "color", }, }, title: "Background", }, ], title: "Controls", }, }, }, modules: [], }); const state = createToolcraftState(app, { canvas: { mode: "infinite" }, values: { "export.includeBackground": false }, }); expect(state.values["export.includeBackground"]).toBe(false); expect(state.canvas.mode).toBe("finite"); }); it("initializes values from control defaults by target", () => { const app = defineToolcraft({ base: { identity: { id: "runtime-test", title: "Toolcraft App" }, canvas: { enabled: true }, panels: { controls: { sections: [ { id: "test-section-3", controls: { opacity: { applicability: { mode: "always" as const }, defaultValue: 75, target: "selectedLayer.opacity", type: "slider", }, prompt: { applicability: { mode: "always" as const }, defaultValue: "", target: "generation.prompt", type: defineToolcraftCustomControlType("textarea"), }, }, }, ], title: "Controls", }, }, }, modules: [], }); const state = createToolcraftState(app); expect(state.values).toEqual({ "generation.prompt": "", "selectedLayer.opacity": 75, }); expect(state.defaults).toEqual(state.values); expect(state.values).not.toBe(state.defaults); }); it("initializes editable canvas size control defaults only for editable output apps", () => { const app = defineToolcraft({ base: { identity: { id: "runtime-test", title: "Toolcraft App" }, canvas: { enabled: true, sizing: { mode: "editable-output" } }, panels: { controls: { sections: [], title: "Controls", }, }, }, modules: [], }); const state = createToolcraftState(app); expect(state.values).toMatchObject({ "canvas.aspectRatio": { height: 9, mode: "preset", value: "16:9", width: 16, }, "canvas.size.height": 1080, "canvas.size.width": 1920, }); }); it("initializes canvas state from resolved canvas size", () => { const size = { width: 1200, height: 900, unit: "px" } as const; const app = defineToolcraft({ base: { identity: { id: "runtime-test", title: "Toolcraft App" }, canvas: { enabled: true, size }, panels: {}, }, modules: [], }); const state = createToolcraftState(app); expect(state.canvas.size).toEqual(size); expect(state.canvas.zoom).toBe(100); }); it("preserves seeded canvas width", () => { const app = defineToolcraft({ base: { identity: { id: "runtime-test", title: "Toolcraft App" }, canvas: { enabled: true }, panels: {}, }, modules: [], }); const state = createToolcraftState(app, { canvas: { size: { width: 640, height: 900, unit: "px" }, }, }); expect(state.canvas.size).toEqual({ width: 640, height: 900, unit: "px" }); }); it("initializes default panel offsets", () => { const app = defineToolcraft({ base: { identity: { id: "runtime-test", title: "Toolcraft App" }, canvas: { enabled: true }, panels: {}, }, modules: [], }); const state = createToolcraftState(app); expect(state.panels).toEqual({ controls: { collapsedSections: {}, offset: { x: 0, y: 0 } }, layers: { offset: { x: 0, y: 0 } }, timeline: { offset: { x: 0, y: 0 } }, toolbar: { offset: { x: 0, y: 0 } }, }); }); it("initializes media and layer state as empty", () => { const app = defineToolcraft({ base: { identity: { id: "runtime-test", title: "Toolcraft App" }, canvas: { enabled: true }, panels: {}, }, modules: [], }); const state = createToolcraftState(app); expect(state.layers).toEqual([]); expect(state.mediaAssets).toEqual([]); expect(state.selectedLayerId).toBeNull(); }); it("initializes predefined media files as runtime attachments", () => { const app = defineToolcraft({ base: { identity: { id: "runtime-test", title: "Toolcraft App" }, canvas: { enabled: true, upload: true }, media: { defaultAssets: [ { ingressPolicy: "prepared-source", position: { x: 0, y: 0 }, sourceSize: { height: 1080, unit: "px", width: 1920 }, dataUrl: "data:image/png;base64,AAAA", fileName: "background.png", id: "default-background", layerId: "default-background-layer", mimeType: "image/png", sourceTarget: "media.background", }, ], }, panels: { controls: { sections: [ { id: "test-section-4", controls: { background: { applicability: { mode: "always" as const }, defaultValue: null, target: "media.background", type: "fileDrop", }, }, }, ], title: "Controls", }, }, }, modules: [mediaSourceModule()], }); const state = createToolcraftState(app); expect(state.mediaAssets).toEqual([ expect.objectContaining({ fileName: "background.png", id: "default-background", layerId: "default-background-layer", mimeType: "image/png", lifecycle: "restoring", resourceRef: expect.stringMatching(/^media:image:sha256:/u), sourceTarget: "media.background", }), ]); expect(state.mediaAssets[0]).not.toHaveProperty("dataUrl"); expect(state.layers).toEqual([ expect.objectContaining({ id: "default-background-layer", name: "background", visible: true, }), ]); expect(state.selectedLayerId).toBe("default-background-layer"); }); it("lets persisted media state override schema default media", () => { const app = defineToolcraft({ base: { identity: { id: "runtime-test", title: "Toolcraft App" }, canvas: { enabled: true, upload: true }, media: { defaultAssets: [ { ingressPolicy: "prepared-source", position: { x: 0, y: 0 }, sourceSize: { height: 512, unit: "px", width: 512 }, dataUrl: "data:image/png;base64,AAAA", fileName: "background.png", sourceTarget: "media.background", }, ], }, panels: {}, }, modules: [mediaSourceModule()], }); const state = createToolcraftState(app, { mediaAssets: [] }); expect(state.mediaAssets).toEqual([]); expect(state.layers).toEqual([]); expect(state.selectedLayerId).toBeNull(); }); it("restores default media layer names when persisted media omits layer state", () => { const app = defineToolcraft({ base: { identity: { id: "runtime-test", title: "Toolcraft App" }, canvas: { enabled: true, upload: true }, media: { defaultAssets: [ { ingressPolicy: "prepared-source", position: { x: 0, y: 0 }, sourceSize: { height: 512, unit: "px", width: 512 }, dataUrl: "data:image/png;base64,AAAA", fileName: "background.png", id: "default-background", layerId: "default-background-layer", layerName: "Hero source", sourceTarget: "media.background", }, ], }, panels: {}, }, modules: [mediaSourceModule()], }); const state = createToolcraftState(app, { mediaAssets: [ { assetKind: "image", lifecycle: "ready", resourceRef: "data:image/png;base64,AAAA", fileName: "background.png", id: "default-background", layerId: "default-background-layer", mimeType: "image/png", position: { x: 0, y: 0 }, size: { width: 512, height: 512, unit: "px" }, sourceSize: { width: 512, height: 512, unit: "px" }, sourceTarget: "media.background", }, ], }); expect(state.layers).toEqual([ expect.objectContaining({ displayName: "Hero source", id: "default-background-layer", name: "Hero source", }), ]); expect(state.selectedLayerId).toBe("default-background-layer"); }); it("accepts seeded runtime layer state", () => { const app = defineToolcraft({ base: { identity: { id: "runtime-test", title: "Toolcraft App" }, canvas: { enabled: true }, panels: {}, }, modules: [], }); const state = createToolcraftState(app, { layers: [ { displayName: "Layer 1", id: "layer-1", kind: "layer", name: "layer-1", visible: true, }, ], selectedLayerId: "layer-1", }); expect(state.layers).toHaveLength(1); expect(state.layers[0]?.displayName).toBe("Layer 1"); expect(state.selectedLayerId).toBe("layer-1"); expect(state.history.undo).toEqual([]); }); });