import { describe, expect, it, vi } from "vitest"; import { createToolcraftModelPresentation, type ToolcraftModelRenderBinding, } from "./model-render-binding"; import { createToolcraftModelRenderRegistry } from "./model-render-registry"; function createBinding(name: string): ToolcraftModelRenderBinding<{ name: string }> { return { create: vi.fn(() => ({ name })), dispose: vi.fn(), hitTest: vi.fn(() => true), renderExport: vi.fn(), renderPreview: vi.fn(), update: vi.fn(), }; } const asset = { activeDocumentRef: "toolcraft:model-document:active", id: "model-1", layerId: "layer-1", lifecycle: "clean" as const, sourceTarget: "source.model", }; describe("Toolcraft model render registry", () => { it("uses the standard binding as a fallback and a target binding as an override", () => { const standardBinding = createBinding("standard"); const customBinding = createBinding("custom"); const registry = createToolcraftModelRenderRegistry({ bindings: { "source.custom-model": customBinding }, standardBinding, }); expect(registry.resolve("source.model")).toBe(standardBinding); expect(registry.resolve("source.custom-model")).toBe(customBinding); }); it("derives busy opacity only for analyzing or repairing previews", () => { expect( createToolcraftModelPresentation(asset, { phase: "analyzing", purpose: "preview", }).presentationOpacity, ).toBe(0.4); expect( createToolcraftModelPresentation(asset, { phase: "repairing", purpose: "preview", }).presentationOpacity, ).toBe(0.4); expect( createToolcraftModelPresentation(asset, { phase: "decoding", purpose: "preview", }).presentationOpacity, ).toBe(1); expect( createToolcraftModelPresentation(asset, { phase: "repairing", purpose: "export", }).presentationOpacity, ).toBe(1); }); it("snapshots mutable presentation input", () => { const orientation = { position: [1, 2, 5] as [number, number, number], up: [0, 1, 0] as [number, number, number], }; const presentation = createToolcraftModelPresentation(asset, { orientation, phase: "clean", purpose: "preview", viewport: { height: 200, width: 300 }, }); orientation.position[0] = 99; expect(presentation.orientation.position).toEqual([1, 2, 5]); expect(presentation.displayFit.viewport).toEqual({ height: 200, width: 300 }); expect(Object.isFrozen(presentation)).toBe(true); }); });