import { describe, expect, it } from "vitest"; import { canvasEditingModule } from "./built-ins/canvas-editing/canvas-editing-module"; import { imageExportModule } from "./built-ins/image-export/image-export-module"; import { layersModule } from "./built-ins/layers/layers-module"; import { mediaSourceModule } from "./built-ins/media-source/media-source-module"; import { timelineModule } from "./built-ins/timeline/timeline-module"; import type { ToolcraftProductModuleContribution } from "./contract/contribution"; import { assembleToolcraftModuleContributions, TOOLCRAFT_CONTRIBUTION_PHASE_TABLE, type ResolvedToolcraftModuleContributions, type ToolcraftContributionPhaseTable, } from "./resolution/contribution-phase/assemble-module-contributions"; import { preflightToolcraftModuleContributions } from "./testing/module-resolution-test-support"; import { resolveToolcraftModuleContributions } from "./testing/module-resolution-test-support"; import { getTestModuleContributions } from "./testing/module-contribution-test-fixtures"; const missingPersistencePhaseTable = { actionContributions: TOOLCRAFT_CONTRIBUTION_PHASE_TABLE.actionContributions, canvasBehaviorContributions: TOOLCRAFT_CONTRIBUTION_PHASE_TABLE.canvasBehaviorContributions, mediaPolicyContributions: TOOLCRAFT_CONTRIBUTION_PHASE_TABLE.mediaPolicyContributions, settingsContributions: TOOLCRAFT_CONTRIBUTION_PHASE_TABLE.settingsContributions, surfaceContributions: TOOLCRAFT_CONTRIBUTION_PHASE_TABLE.surfaceContributions, }; // @ts-expect-error Every preflight contribution bucket requires one phase entry. const invalidMissingPhaseTable: ToolcraftContributionPhaseTable = missingPersistencePhaseTable; void invalidMissingPhaseTable; const invalidExtraPhaseTable: ToolcraftContributionPhaseTable = { ...TOOLCRAFT_CONTRIBUTION_PHASE_TABLE, // @ts-expect-error Unknown preflight buckets cannot join the phase table. unknownContributions: Object.freeze({ unknownResult: () => Object.freeze([]), }), }; void invalidExtraPhaseTable; const invalidCrossWiredPhaseTable: ToolcraftContributionPhaseTable = { ...TOOLCRAFT_CONTRIBUTION_PHASE_TABLE, // @ts-expect-error Persistence cannot materialize the canvas result role. canvasBehaviorContributions: Object.freeze({ canvasBehaviors: TOOLCRAFT_CONTRIBUTION_PHASE_TABLE.persistenceContributions .persistenceRequirements, }), }; void invalidCrossWiredPhaseTable; function contributionOfKind< Kind extends ToolcraftProductModuleContribution["kind"], >( contributions: readonly ToolcraftProductModuleContribution[], kind: Kind, ): Extract> { const contribution = contributions.find( ( candidate, ): candidate is Extract< ToolcraftProductModuleContribution, Readonly<{ kind: Kind }> > => candidate.kind === kind, ); if (contribution === undefined) { throw new Error(`Missing ${kind} contribution fixture.`); } return contribution; } const allDomainContributions = getTestModuleContributions([ canvasEditingModule(), imageExportModule(), layersModule(), mediaSourceModule(), timelineModule({ mode: "keyframes" }), ]); type DomainCase = Readonly<{ contribution: ToolcraftProductModuleContribution; expectedKeys: readonly (keyof ResolvedToolcraftModuleContributions)[]; name: string; verify: (resolution: ResolvedToolcraftModuleContributions) => void; }>; const baseResultKeys = [ "canvasBehaviors", "controlSections", "ownership", "persistenceRequirements", ] as const; const domainCases: readonly DomainCase[] = [ { contribution: contributionOfKind( canvasEditingModule().contributions, "canvas-behavior", ), expectedKeys: baseResultKeys, name: "canvas behavior", verify: (resolution) => { expect(resolution.canvasBehaviors).toHaveLength(1); expect(resolution.canvasBehaviors[0]?.behavior).toBe("editing"); }, }, { contribution: contributionOfKind( imageExportModule().contributions, "control-section", ), expectedKeys: baseResultKeys, name: "settings", verify: (resolution) => { expect(resolution.controlSections.map(({ id }) => id)).toEqual([ "runtime.image-export", ]); }, }, { contribution: contributionOfKind( mediaSourceModule().contributions, "media-policy", ), expectedKeys: [...baseResultKeys, "mediaPolicy"], name: "media policy", verify: (resolution) => { expect(resolution.mediaPolicy?.policy).toBe("source-workflow"); }, }, { contribution: contributionOfKind( imageExportModule().contributions, "panel-action", ), expectedKeys: [...baseResultKeys, "panelActionsSection"], name: "panel action", verify: (resolution) => { expect(resolution.panelActionsSection?.id).toBe("runtime.export"); }, }, { contribution: contributionOfKind( layersModule().contributions, "panel-surface", ), expectedKeys: [...baseResultKeys, "layers"], name: "panel surface", verify: (resolution) => { expect(resolution.layers).toBe(true); expect(resolution.timeline).toBeUndefined(); }, }, { contribution: contributionOfKind( mediaSourceModule().contributions, "persistence-requirement", ), expectedKeys: baseResultKeys, name: "persistence", verify: (resolution) => { expect(resolution.persistenceRequirements).toEqual(["media"]); }, }, ]; describe("Toolcraft contribution phase assembly", () => { it("invokes and routes every typed phase exactly once", () => { const preflight = preflightToolcraftModuleContributions( allDomainContributions, ); const expected = Object.freeze({ canvasBehaviors: TOOLCRAFT_CONTRIBUTION_PHASE_TABLE.canvasBehaviorContributions.canvasBehaviors( preflight.canvasBehaviorContributions, ), controlSections: TOOLCRAFT_CONTRIBUTION_PHASE_TABLE.settingsContributions.controlSections( preflight.settingsContributions, ), mediaPolicy: TOOLCRAFT_CONTRIBUTION_PHASE_TABLE.mediaPolicyContributions.mediaPolicy( preflight.mediaPolicyContributions, ), panelActionsSection: TOOLCRAFT_CONTRIBUTION_PHASE_TABLE.actionContributions.panelActionsSection( preflight.actionContributions, ), panelSurfaces: TOOLCRAFT_CONTRIBUTION_PHASE_TABLE.surfaceContributions.panelSurfaces( preflight.surfaceContributions, ), persistenceRequirements: TOOLCRAFT_CONTRIBUTION_PHASE_TABLE.persistenceContributions.persistenceRequirements( preflight.persistenceContributions, ), }); const calls: string[] = []; const phaseTable: ToolcraftContributionPhaseTable = { actionContributions: { panelActionsSection: (contributions) => { expect(contributions).toBe(preflight.actionContributions); calls.push("actionContributions"); return expected.panelActionsSection; }, }, canvasBehaviorContributions: { canvasBehaviors: (contributions) => { expect(contributions).toBe(preflight.canvasBehaviorContributions); calls.push("canvasBehaviorContributions"); return expected.canvasBehaviors; }, }, mediaPolicyContributions: { mediaPolicy: (contributions) => { expect(contributions).toBe(preflight.mediaPolicyContributions); calls.push("mediaPolicyContributions"); return expected.mediaPolicy; }, }, persistenceContributions: { persistenceRequirements: (contributions) => { expect(contributions).toBe(preflight.persistenceContributions); calls.push("persistenceContributions"); return expected.persistenceRequirements; }, }, settingsContributions: { controlSections: (contributions) => { expect(contributions).toBe(preflight.settingsContributions); calls.push("settingsContributions"); return expected.controlSections; }, }, surfaceContributions: { panelSurfaces: (contributions) => { expect(contributions).toBe(preflight.surfaceContributions); calls.push("surfaceContributions"); return expected.panelSurfaces; }, }, }; const resolution = assembleToolcraftModuleContributions( preflight, phaseTable, ); expect(calls).toEqual([ "canvasBehaviorContributions", "settingsContributions", "mediaPolicyContributions", "actionContributions", "surfaceContributions", "persistenceContributions", ]); expect(resolution.canvasBehaviors).toBe(expected.canvasBehaviors); expect(resolution.controlSections).toBe(expected.controlSections); expect(resolution.mediaPolicy).toBe(expected.mediaPolicy); expect(resolution.panelActionsSection).toBe( expected.panelActionsSection, ); expect(resolution.persistenceRequirements).toBe( expected.persistenceRequirements, ); expect(resolution.layers).toBe(expected.panelSurfaces.layers); expect(resolution.timeline).toBe(expected.panelSurfaces.timeline); expect(resolution.ownership).toBe(preflight.ownership); expect("panelSurfaces" in resolution).toBe(false); expect(Object.isFrozen(resolution)).toBe(true); }); it.each(domainCases)( "materializes the $name domain independently", ({ contribution, expectedKeys, verify }) => { const resolution = resolveToolcraftModuleContributions([contribution]); expect(Object.keys(resolution).sort()).toEqual( [...expectedKeys].sort(), ); expect(resolution.ownership).toHaveLength(1); expect(Object.isFrozen(resolution)).toBe(true); verify(resolution); }, ); it("preserves exact empty and complete optional result shapes", () => { const empty = resolveToolcraftModuleContributions([]); expect(Object.keys(empty).sort()).toEqual([...baseResultKeys].sort()); const complete = resolveToolcraftModuleContributions( allDomainContributions, ); expect(Object.keys(complete).sort()).toEqual([ "canvasBehaviors", "controlSections", "layers", "mediaPolicy", "ownership", "panelActionsSection", "persistenceRequirements", "timeline", ]); expect(complete.canvasBehaviors).not.toEqual([]); expect(complete.controlSections).not.toEqual([]); expect(complete.mediaPolicy).toBeDefined(); expect(complete.panelActionsSection).toBeDefined(); expect(complete.layers).toBe(true); expect(complete.timeline).toEqual({ enabled: true, mode: "keyframes" }); expect(complete.persistenceRequirements).toEqual([ "layers", "media", "timeline", ]); expect(Object.isFrozen(complete)).toBe(true); }); it("freezes the canonical exhaustive phase table", () => { expect(Object.isFrozen(TOOLCRAFT_CONTRIBUTION_PHASE_TABLE)).toBe(true); expect( Object.values(TOOLCRAFT_CONTRIBUTION_PHASE_TABLE).every( Object.isFrozen, ), ).toBe(true); }); });