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 { model3dModule } from "./built-ins/model-3d/model-3d-module"; import { spatialViewModule } from "./built-ins/spatial-view/spatial-view-module"; import { resolveToolcraftProductModules } from "./testing/module-resolution-test-support"; import { permutations } from "./testing/module-contribution-test-fixtures"; const expectedProjectBPortRequirements = [ { applicability: "always", consumers: ["model-3d"], id: "modelPresentation", }, { applicability: "always", consumers: ["canvas-editing", "spatial-view"], id: "scene.canvasContent", }, ] as const; function expectRecursivelyFrozen(value: unknown): void { if (value === null || typeof value !== "object") { return; } expect(Object.isFrozen(value)).toBe(true); for (const nestedValue of Object.values(value)) { expectRecursivelyFrozen(nestedValue); } } describe("Project B product module planning", () => { it("resolves all five modules into the exact compact lexical product plan", () => { const definitions = [ spatialViewModule(), model3dModule({ presentation: "custom" }), mediaSourceModule(), layersModule(), canvasEditingModule(), ]; const resolution = resolveToolcraftProductModules(definitions); expect(resolution).toEqual({ contributionResolution: { canvasBehaviors: [ { behavior: "editing", operations: ["drag", "handles", "resize", "selection"], }, { behavior: "spatial-view", operations: ["gizmo", "orbit", "paused-live-sync", "pose"], }, ], controlSections: [], layers: true, mediaPolicy: { policy: "source-workflow", sourceKinds: ["file", "image", "model"], }, ownership: [ { contributionId: "canvas-editing.behavior", kind: "canvas-behavior", moduleId: "canvas-editing", ownershipKeys: ["canvas-behavior:editing"], }, { contributionId: "layers.persistence", kind: "persistence-requirement", moduleId: "layers", ownershipKeys: ["persistence-slice:layers"], }, { contributionId: "layers.surface", kind: "panel-surface", moduleId: "layers", ownershipKeys: ["panel-surface:layers"], }, { contributionId: "media-source.persistence", kind: "persistence-requirement", moduleId: "media-source", ownershipKeys: ["persistence-slice:media"], }, { contributionId: "media-source.policy", kind: "media-policy", moduleId: "media-source", ownershipKeys: ["media-policy:source-workflow"], }, { contributionId: "spatial-view.behavior", kind: "canvas-behavior", moduleId: "spatial-view", ownershipKeys: ["canvas-behavior:spatial-view"], }, ], persistenceRequirements: ["layers", "media"], }, plan: { capabilities: [ { capabilityId: "canvas.editing", moduleId: "canvas-editing" }, { capabilityId: "layers.management", moduleId: "layers" }, { capabilityId: "media.source", moduleId: "media-source" }, { capabilityId: "model.3d", moduleId: "model-3d" }, { capabilityId: "spatial.view", moduleId: "spatial-view" }, ], modules: [ { id: "canvas-editing", origin: "explicit", provides: ["canvas.editing"], requestedBy: [], requires: [], }, { id: "layers", origin: "explicit", provides: ["layers.management"], requestedBy: [], requires: [], }, { id: "media-source", origin: "explicit", provides: ["media.source"], requestedBy: [], requires: [], }, { id: "model-3d", origin: "explicit", provides: ["model.3d"], requestedBy: [], requires: ["media.source"], }, { id: "spatial-view", origin: "explicit", provides: ["spatial.view"], requestedBy: [], requires: [], }, ], ownership: [ { contributionId: "canvas-editing.behavior", kind: "canvas-behavior", moduleId: "canvas-editing", ownershipKeys: ["canvas-behavior:editing"], }, { contributionId: "layers.persistence", kind: "persistence-requirement", moduleId: "layers", ownershipKeys: ["persistence-slice:layers"], }, { contributionId: "layers.surface", kind: "panel-surface", moduleId: "layers", ownershipKeys: ["panel-surface:layers"], }, { contributionId: "media-source.persistence", kind: "persistence-requirement", moduleId: "media-source", ownershipKeys: ["persistence-slice:media"], }, { contributionId: "media-source.policy", kind: "media-policy", moduleId: "media-source", ownershipKeys: ["media-policy:source-workflow"], }, { contributionId: "spatial-view.behavior", kind: "canvas-behavior", moduleId: "spatial-view", ownershipKeys: ["canvas-behavior:spatial-view"], }, ], portRequirements: expectedProjectBPortRequirements, }, }); const compactPlanJson = JSON.stringify(resolution.plan); expect(Object.keys(resolution.plan).sort()).toEqual([ "capabilities", "modules", "ownership", "portRequirements", ]); expect(compactPlanJson).not.toContain('"definitions":'); expect(compactPlanJson).not.toContain('"contributions":'); expect(compactPlanJson).not.toContain('"operations":'); expect(compactPlanJson).not.toContain('"policy":'); expect(compactPlanJson).not.toContain('"sourceKinds":'); expectRecursivelyFrozen(resolution); }); it("returns byte-identical recursively frozen output for every declaration order", () => { const definitions = [ canvasEditingModule(), layersModule(), mediaSourceModule(), model3dModule({ presentation: "custom" }), spatialViewModule(), ]; const expectedJson = JSON.stringify( resolveToolcraftProductModules(definitions), ); for (const declarationOrder of permutations(definitions)) { const resolution = resolveToolcraftProductModules(declarationOrder); expect(JSON.stringify(resolution)).toBe(expectedJson); expectRecursivelyFrozen(resolution); } }); it.each([ { definitions: [ layersModule(), model3dModule({ presentation: "custom" }), canvasEditingModule(), spatialViewModule(), ], label: "injected Media Source", }, { definitions: [ layersModule(), model3dModule({ presentation: "custom" }), canvasEditingModule(), spatialViewModule(), mediaSourceModule(), ], label: "explicit Media Source", }, ])("aggregates the exact Project B ports with $label", ({ definitions }) => { const portRequirements = resolveToolcraftProductModules(definitions).plan.portRequirements; expect(portRequirements).toEqual(expectedProjectBPortRequirements); expectRecursivelyFrozen(portRequirements); }); it("omits modelPresentation for runtime Model 3D and gives Media Source no port", () => { expect( resolveToolcraftProductModules([ layersModule(), model3dModule(), canvasEditingModule(), spatialViewModule(), ]).plan.portRequirements, ).toEqual([ { applicability: "always", consumers: ["canvas-editing", "spatial-view"], id: "scene.canvasContent", }, ]); expect( resolveToolcraftProductModules([mediaSourceModule()]).plan .portRequirements, ).toEqual([]); }); });