import { describe, expect, it } from "vitest"; import { defineToolcraft } from "./define-toolcraft"; import { createSliderControls, getProductSections } from "./define-toolcraft-test-utils"; describe("defineToolcraft runtime setup settings transfer", () => { it("uses canonical identity for settings transfer independently of controls title", () => { const createApp = (controlsTitle: string) => defineToolcraft({ canvas: { enabled: true }, identity: { id: " My Visual Tool ", title: "My Visual Tool", }, panels: { controls: { sections: [], title: controlsTitle, }, }, persistence: { include: ["values", "panels"], key: "toolcraft:persistence-slug:state:v1", storage: "localStorage", version: 1, }, settingsTransfer: { appId: "legacy-settings-id", }, }); const first = createApp("First Controls Title"); const renamed = createApp("Renamed Controls Title"); expect(first.identity).toEqual({ id: "my-visual-tool", title: "My Visual Tool", }); expect(first.settingsTransfer.appId).toBe(first.identity.id); expect(first.settingsTransfer.appId).not.toBe("persistence-slug"); expect(first.settingsTransfer.appId).not.toBe("first-controls-title"); expect(renamed.identity).toEqual(first.identity); expect(renamed.settingsTransfer.appId).toBe(first.settingsTransfer.appId); }); it("keeps settings transfer visible for small auto schemas", () => { const app = defineToolcraft({ canvas: { enabled: true, size: { height: 320, unit: "px", width: 320 } }, panels: { controls: { sections: [ { controls: { opacity: { defaultValue: 75, label: "Opacity", target: "style.opacity", type: "slider", }, }, title: "Style", }, ], title: "Mini App", }, }, }); expect(app.settingsTransfer).toMatchObject({ appId: "mini-app", enabled: true, fileName: "mini-app-settings.json", mode: "auto", }); expect(app.panels.controls?.sections[0]?.title).toBe("Setup"); expect(app.panels.controls?.sections[0]?.controls.settingsTransfer).toMatchObject({ target: "runtime.settingsTransfer", type: "settingsTransfer", }); expect(app.panels.controls?.sections[0]?.controls.canvasAspectRatio).toMatchObject({ target: "canvas.aspectRatio", type: "aspectRatio", }); expect(app.panels.controls?.sections[0]?.controls.canvasWidth).toBeTruthy(); }); it("keeps runtime setup controls outside product sections", () => { const app = defineToolcraft({ canvas: { enabled: true, size: { height: 720, unit: "px", width: 1280 } }, panels: { controls: { sections: [ { controls: createSliderControls(10), title: "Product Controls", }, ], title: "Runtime Size App", }, }, settingsTransfer: false, }); expect(app.settingsTransfer.enabled).toBe(true); expect(app.panels.controls?.sections[0]?.controls.settingsTransfer).toMatchObject({ target: "runtime.settingsTransfer", type: "settingsTransfer", }); expect(app.panels.controls?.sections[0]?.controls.canvasAspectRatio).toBeTruthy(); expect(app.panels.controls?.sections[0]?.controls.canvasWidth).toBeTruthy(); expect(app.panels.controls?.sections[0]?.controls.canvasHeight).toBeTruthy(); expect(getProductSections(app)).toHaveLength(1); expect(getProductSections(app)[0]?.title).toBe("Product Controls"); }); it("injects settings transfer as the first section for complex auto schemas", () => { const app = defineToolcraft({ canvas: { enabled: true, size: { height: 720, unit: "px", width: 1280 } }, panels: { controls: { sections: [ { controls: { prompt: { defaultValue: "Prompt", label: "Prompt", target: "generation.prompt", type: "text", }, mask: { defaultValue: "Mask", label: "Mask", target: "generation.mask", type: "code", }, font: { defaultValue: { fontId: "inter" }, label: "Font", target: "typography.font", type: "fontPicker", }, gradient: { label: "Gradient", target: "style.gradient", type: "gradient", }, }, title: "Text", }, { controls: { opacity: { defaultValue: 80, target: "style.opacity", type: "slider" }, blur: { defaultValue: 4, target: "style.blur", type: "slider" }, threshold: { defaultValue: 50, target: "style.threshold", type: "slider" }, seed: { defaultValue: 123, target: "style.seed", type: "text" }, spacing: { defaultValue: 8, target: "style.spacing", type: "slider" }, density: { defaultValue: 16, target: "style.density", type: "slider" }, speed: { defaultValue: 1, target: "style.speed", type: "slider" }, }, title: "Style", }, { controls: { anchor: { defaultValue: "center", target: "layout.anchor", type: "anchorGrid" }, }, layout: "standalone", title: "Layout", }, ], title: "Complex App", }, timeline: { mode: "playback" }, }, }); const [runtimeSettingsSection, firstProductSection] = app.panels.controls?.sections ?? []; expect(app.settingsTransfer.enabled).toBe(true); expect(runtimeSettingsSection?.title).toBe("Setup"); expect(Object.keys(runtimeSettingsSection?.controls ?? {})).toEqual([ "settingsTransfer", "infinityCanvas", "canvasAspectRatio", "canvasWidth", "canvasHeight", "timelineExtended", ]); expect(runtimeSettingsSection?.controls.canvasAspectRatio).toMatchObject({ defaultValue: { height: 9, mode: "preset", value: "16:9", width: 16, }, target: "canvas.aspectRatio", type: "aspectRatio", }); expect(runtimeSettingsSection?.controls.canvasWidth).toBeTruthy(); expect(runtimeSettingsSection?.controls.canvasHeight).toBeTruthy(); expect(runtimeSettingsSection?.controls.settingsTransfer?.type).toBe( "settingsTransfer", ); expect(runtimeSettingsSection?.layout).toBe("standalone"); expect(runtimeSettingsSection?.layoutGroups).toEqual([ { columns: 2, controls: ["canvasWidth", "canvasHeight"], layout: "inline", }, ]); expect(firstProductSection?.title).toBe("Text"); }); it("uses legacy settings transfer naming as an identity seed while keeping setup mandatory", () => { const forced = defineToolcraft({ canvas: { enabled: false }, panels: { controls: { sections: [], title: "Tiny Tool", }, }, settingsTransfer: { additionalValueTargets: [ " composition.layout ", "composition.layout", "", "composition.selection", ], appId: "Tiny Tool Presets", enabled: true, fileName: "tiny-presets", }, }); const disabled = defineToolcraft({ canvas: { enabled: true, size: { height: 720, unit: "px", width: 1280 } }, panels: { controls: { sections: [ { controls: Object.fromEntries( Array.from({ length: 12 }, (_, index) => [ `control${index}`, { defaultValue: index, target: `values.control${index}`, type: "slider", }, ]), ), title: "Many Controls", }, ], title: "Heavy Tool", }, }, settingsTransfer: false, }); expect(forced.settingsTransfer).toMatchObject({ additionalValueTargets: [ "composition.layout", "composition.selection", ], appId: "tiny-tool-presets", enabled: true, fileName: "tiny-presets.json", }); expect(Object.isFrozen(forced.settingsTransfer.additionalValueTargets)).toBe( true, ); expect(forced.panels.controls?.sections[0]?.controls.settingsTransfer?.type).toBe( "settingsTransfer", ); expect(disabled.settingsTransfer).toMatchObject({ additionalValueTargets: [], enabled: true, mode: false, }); expect(disabled.panels.controls?.sections[0]?.controls.settingsTransfer?.type).toBe( "settingsTransfer", ); }); it("does not let app-authored runtime targets suppress mandatory setup controls", () => { const app = defineToolcraft({ canvas: { enabled: true, renderScale: true, size: { height: 1080, unit: "px", width: 1920 }, sizing: { mode: "editable-output" }, }, panels: { controls: { sections: [ { controls: { manualWidth: { defaultValue: 1280, label: "Width", target: "canvas.size.width", type: "text", }, manualRenderScale: { defaultValue: 1, label: "Scale", max: 2, min: 1, target: "canvas.renderScale", type: "slider", }, manualTimeline: { defaultValue: true, label: "Timeline", target: "panels.timeline.extended", type: "switch", }, }, title: "Manual Runtime Duplicates", }, ], title: "Controls", }, timeline: { mode: "playback" }, }, }); const [setupSection, duplicateSection] = app.panels.controls?.sections ?? []; expect(Object.keys(setupSection?.controls ?? {})).toEqual([ "settingsTransfer", "infinityCanvas", "canvasAspectRatio", "canvasWidth", "canvasHeight", "canvasRenderScale", "timelineExtended", ]); expect(setupSection?.layoutGroups?.[0]).toEqual({ columns: 2, controls: ["canvasWidth", "canvasHeight"], layout: "inline", }); expect(duplicateSection?.controls.manualWidth?.target).toBe("canvas.size.width"); expect(duplicateSection?.controls.manualRenderScale?.target).toBe("canvas.renderScale"); expect(duplicateSection?.controls.manualTimeline?.target).toBe( "panels.timeline.extended", ); }); });