import { describe, expect, it } from "vitest"; import { canvasEditingModule } from "./built-ins/canvas-editing/canvas-editing-module"; import { layersModule } from "./built-ins/layers/layers-module"; import { mediaSourceModule } from "./built-ins/media-source/media-source-module"; import { spatialViewModule } from "./built-ins/spatial-view/spatial-view-module"; import { timelineModule } from "./built-ins/timeline/timeline-module"; import type { ResolvedToolcraftCanvasBehavior } from "./contributions/canvas-behavior-contributions"; import { resolveToolcraftModuleContributions } from "./testing/module-resolution-test-support"; import { getTestModuleContributions, permutations, } from "./testing/module-contribution-test-fixtures"; const invalidEditingBehaviorRecord = { behavior: "editing", operations: ["gizmo", "orbit", "paused-live-sync", "pose"], } as const; // @ts-expect-error Editing behavior cannot carry spatial-view operations. const invalidEditingBehavior: ResolvedToolcraftCanvasBehavior = invalidEditingBehaviorRecord; void invalidEditingBehavior; describe("Project B module contribution materialization", () => { it("materializes Layers and preserves the exact authored Timeline payload", () => { const timeline = timelineModule({ mode: "keyframes" }); const authoredTimeline = timeline.contributions.find( (contribution) => contribution.kind === "panel-surface" && contribution.surface === "timeline" && contribution.id === "timeline.surface", )!.configuration; const resolution = resolveToolcraftModuleContributions( getTestModuleContributions([timeline, layersModule()]), ); expect(resolution.layers).toBe(true); expect(resolution.timeline).toBe(authoredTimeline); expect(resolution.persistenceRequirements).toEqual([ "layers", "timeline", ]); }); it("materializes one exact frozen source-workflow media policy", () => { const definition = mediaSourceModule(); const authoredPolicy = definition.contributions.find( (contribution) => contribution.kind === "media-policy", )!; const resolution = resolveToolcraftModuleContributions( definition.contributions, ); expect(resolution.mediaPolicy).toEqual({ policy: "source-workflow", sourceKinds: ["file", "image", "model"], }); expect(resolution.mediaPolicy?.sourceKinds).toBe(authoredPolicy.sourceKinds); expect(resolution.persistenceRequirements).toEqual(["media"]); expect(Object.isFrozen(resolution.mediaPolicy)).toBe(true); expect(Object.isFrozen(resolution.mediaPolicy?.sourceKinds)).toBe(true); }); it("sorts frozen canvas behaviors independently of declaration order", () => { const editingDefinition = canvasEditingModule(); const spatialDefinition = spatialViewModule(); const authoredEditing = editingDefinition.contributions.find( (contribution) => contribution.id === "canvas-editing.behavior", )!.operations; const authoredSpatial = spatialDefinition.contributions.find( (contribution) => contribution.id === "spatial-view.behavior", )!.operations; const definitions = [spatialDefinition, editingDefinition]; for (const declarationOrder of permutations(definitions)) { const resolution = resolveToolcraftModuleContributions( getTestModuleContributions(declarationOrder), ); expect(resolution.canvasBehaviors).toEqual([ { behavior: "editing", operations: ["drag", "handles", "resize", "selection"], }, { behavior: "spatial-view", operations: ["gizmo", "orbit", "paused-live-sync", "pose"], }, ]); expect( resolution.canvasBehaviors.find( ({ behavior }) => behavior === "editing", )?.operations, ).toBe(authoredEditing); expect( resolution.canvasBehaviors.find( ({ behavior }) => behavior === "spatial-view", )?.operations, ).toBe(authoredSpatial); expect(Object.isFrozen(resolution.canvasBehaviors)).toBe(true); expect(resolution.canvasBehaviors.every(Object.isFrozen)).toBe(true); expect( resolution.canvasBehaviors.every(({ operations }) => Object.isFrozen(operations), ), ).toBe(true); } }); it("returns a frozen complete resolution without raw definitions", () => { const resolution = resolveToolcraftModuleContributions( getTestModuleContributions([ spatialViewModule(), layersModule(), mediaSourceModule(), timelineModule({ mode: "playback" }), canvasEditingModule(), ]), ); expect(Object.keys(resolution).sort()).toEqual([ "canvasBehaviors", "controlSections", "layers", "mediaPolicy", "ownership", "persistenceRequirements", "timeline", ]); expect(JSON.stringify(resolution)).not.toContain('"contributions"'); expect(JSON.stringify(resolution)).not.toContain('"contractVersion"'); expect(Object.isFrozen(resolution)).toBe(true); }); });