import { describe, expect, expectTypeOf, it } from "vitest"; import * as toolcraftRuntimeRoot from "../index"; import { defineToolcraft } from "../schema/define-toolcraft"; import type { ToolcraftState } from "../state/types"; import type { ToolcraftArtifactSize, ToolcraftExportFrame, ToolcraftProductExportFrameContext, ToolcraftProductExportFrameRenderer, ToolcraftProductExportRenderer, ToolcraftRetinaExportSize, } from "../index"; import { getToolcraftImageExportSize, getToolcraftRetinaExportPixelRatio, getToolcraftRetinaExportSize, getToolcraftVideoExportSize, } from "./export-sizing"; function createState( schema = defineToolcraft({ base: { identity: { id: "runtime-test", title: "Toolcraft App" }, canvas: { enabled: true }, panels: {}, }, modules: [], }), ): ToolcraftState { return { canvas: { mode: "finite", offset: { x: 0, y: 0 }, size: { height: 100, unit: "px", width: 200 }, zoom: 70, }, controlRanges: {}, defaults: {}, history: { redo: [], undo: [], }, layers: [], mediaAssets: [], panels: { 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 } }, }, schema, selectedLayerId: null, timeline: { currentTimeSeconds: 0, durationSeconds: 8, expanded: false, isLooping: true, isPlaying: false, keyframeGroups: [], selectedKeyframeId: null, }, values: {}, }; } describe("Toolcraft export helpers", () => { it("keeps the runtime root limited to product-safe export primitives", () => { expect(toolcraftRuntimeRoot).toMatchObject({ getToolcraftImageExportSize: expect.any(Function), getToolcraftRetinaExportPixelRatio: expect.any(Function), getToolcraftRetinaExportSize: expect.any(Function), getToolcraftVideoExportSize: expect.any(Function), TOOLCRAFT_MAX_EXPORT_EDGE_PX: 8192, TOOLCRAFT_MAX_EXPORT_PIXELS: 8192 * 8192, toolcraftImageExportFormatTarget: "export.image.format", toolcraftImageExportResolutionTarget: "export.image.resolution", toolcraftVideoExportFormatTarget: "export.video.format", toolcraftVideoExportResolutionTarget: "export.video.resolution", validateToolcraftArtifactSize: expect.any(Function), }); expect(toolcraftRuntimeRoot).not.toHaveProperty( "exportToolcraftImageArtifact", ); expect(toolcraftRuntimeRoot).not.toHaveProperty( "exportToolcraftVideoArtifact", ); expect(toolcraftRuntimeRoot).not.toHaveProperty( "createToolcraftVideoEncoderBackend", ); expect(toolcraftRuntimeRoot).not.toHaveProperty( "createToolcraftVideoFrameSchedule", ); expectTypeOf().toMatchTypeOf< Readonly<{ height: number; width: number }> >(); expectTypeOf().toMatchTypeOf< Readonly<{ height: number; width: number; x: number; y: number }> >(); expectTypeOf().toHaveProperty("frame"); expectTypeOf().toBeFunction(); expectTypeOf().toHaveProperty( "renderFrame", ); expectTypeOf().toHaveProperty("pixelRatio"); }); it("does not publish a product-owned live-preview background helper", () => { expect(toolcraftRuntimeRoot).not.toHaveProperty( "shouldIncludeToolcraftPreviewBackground", ); }); it("uses at least 2x pixel ratio for retina export", () => { expect(getToolcraftRetinaExportPixelRatio(1)).toBe(2); expect(getToolcraftRetinaExportPixelRatio(1.5)).toBe(2); expect(getToolcraftRetinaExportPixelRatio(3)).toBe(3); }); it("resolves retina export size from canvas size rather than viewport zoom", () => { const state = createState(); state.canvas.zoom = 35; expect( getToolcraftRetinaExportSize({ devicePixelRatio: 2, state }), ).toEqual({ height: 200, pixelRatio: 2, width: 400, }); }); it("resolves image export resolution presets from canvas aspect ratio", () => { const state = createState(); expect(getToolcraftImageExportSize({ resolution: "2k", state })).toEqual({ height: 1024, pixelRatio: 10.24, width: 2048, }); expect(getToolcraftImageExportSize({ resolution: "4k", state })).toEqual({ height: 2048, pixelRatio: 20.48, width: 4096, }); expect(getToolcraftImageExportSize({ resolution: "8k", state })).toEqual({ height: 4096, pixelRatio: 40.96, width: 8192, }); }); it("preserves portrait aspect ratio for image export resolution presets", () => { const state = createState(); state.canvas.size = { height: 200, unit: "px", width: 100 }; expect(getToolcraftImageExportSize({ resolution: "4k", state })).toEqual({ height: 4096, pixelRatio: 20.48, width: 2048, }); }); it("falls back to retina sizing for current or unknown image export resolution", () => { const state = createState(); expect( getToolcraftImageExportSize({ devicePixelRatio: 2, resolution: "current", state, }), ).toEqual({ height: 200, pixelRatio: 2, width: 400, }); expect( getToolcraftImageExportSize({ devicePixelRatio: 2, resolution: "source", state, }), ).toEqual({ height: 200, pixelRatio: 2, width: 400, }); }); it("resolves current video export to even current output dimensions", () => { const state = createState(); state.canvas.size = { height: 101, unit: "px", width: 201 }; expect( getToolcraftVideoExportSize({ devicePixelRatio: 2, resolution: "current", state, }), ).toEqual({ height: 102, pixelRatio: 102 / 101, width: 202, }); }); it("keeps current video export distinct from 4k export at default canvas size", () => { const state = createState(); state.canvas.size = { height: 1080, unit: "px", width: 1920 }; expect( getToolcraftVideoExportSize({ devicePixelRatio: 2, resolution: "current", state, }), ).toEqual({ height: 1080, pixelRatio: 1, width: 1920, }); expect(getToolcraftVideoExportSize({ resolution: "4k", state })).toEqual({ height: 2160, pixelRatio: 2, width: 3840, }); }); it("fits 4k video export inside an encoder-safe UHD box", () => { const state = createState(); state.canvas.size = { height: 900, unit: "px", width: 1440 }; expect(getToolcraftVideoExportSize({ resolution: "4k", state })).toEqual({ height: 2160, pixelRatio: 2.4, width: 3456, }); }); it("preserves 16:9 at UHD dimensions for 4k video export", () => { const state = createState(); state.canvas.size = { height: 1080, unit: "px", width: 1920 }; expect(getToolcraftVideoExportSize({ resolution: "4k", state })).toEqual({ height: 2160, pixelRatio: 2, width: 3840, }); }); it("reports the actual rounded pixel ratio for 4k video export", () => { const state = createState(); state.canvas.size = { height: 201, unit: "px", width: 333 }; expect(getToolcraftVideoExportSize({ resolution: "4k", state })).toEqual({ height: 2160, pixelRatio: 2160 / 201, width: 3578, }); }); });