import { describe, expect, it } from "vitest"; import { timelineModule } from "./built-ins/timeline/timeline-module"; import type { ToolcraftProductModuleDefinition } from "./contract/module-definition"; function assertTimelineModeIsRequired(): void { // @ts-expect-error Timeline module selection requires an explicit mode. timelineModule(); } void assertTimelineModeIsRequired; function expectModuleBoundaryFrozen( definition: ToolcraftProductModuleDefinition, ): void { expect(Object.isFrozen(definition)).toBe(true); expect(Object.isFrozen(definition.provides)).toBe(true); expect(Object.isFrozen(definition.requires)).toBe(true); expect(Object.isFrozen(definition.defaultProviders)).toBe(true); expect(definition.defaultProviders.every(Object.isFrozen)).toBe(true); expect(Object.isFrozen(definition.portRequirements)).toBe(true); expect(definition.portRequirements.every(Object.isFrozen)).toBe(true); expect(Object.isFrozen(definition.contributions)).toBe(true); expect(definition.contributions.every(Object.isFrozen)).toBe(true); } function expectPublicDefinition( definition: ToolcraftProductModuleDefinition, expected: Record, ): void { expect(Object.fromEntries(Object.entries(definition))).toEqual(expected); } describe("Toolcraft timeline module", () => { it("defines one stable timeline module per required mode", () => { const playback = timelineModule({ mode: "playback" }); const keyframes = timelineModule({ mode: "keyframes" }); expect(timelineModule({ mode: "playback" })).toBe(playback); expect(timelineModule({ mode: "keyframes" })).toBe(keyframes); expect(playback).not.toBe(keyframes); expectPublicDefinition(playback, { contractVersion: 2, contributions: [ { id: "timeline.surface", kind: "panel-surface", moduleId: "timeline", surface: "timeline", configuration: { enabled: true, mode: "playback" }, }, { id: "timeline.persistence", kind: "persistence-requirement", moduleId: "timeline", slice: "timeline", }, ], defaultProviders: [], id: "timeline", portRequirements: [], provides: ["timeline.playback"], requires: [], }); expectPublicDefinition(keyframes, { contractVersion: 2, contributions: [ { id: "timeline.surface", kind: "panel-surface", moduleId: "timeline", surface: "timeline", configuration: { enabled: true, mode: "keyframes" }, }, { id: "timeline.persistence", kind: "persistence-requirement", moduleId: "timeline", slice: "timeline", }, ], defaultProviders: [], id: "timeline", portRequirements: [], provides: ["timeline.keyframes", "timeline.playback"], requires: [], }); for (const definition of [playback, keyframes]) { expectModuleBoundaryFrozen(definition); const surface = definition.contributions[0]; expect(surface?.kind).toBe("panel-surface"); if (surface?.kind === "panel-surface" && surface.surface === "timeline") { expect(Object.isFrozen(surface.configuration)).toBe(true); expect(Object.hasOwn(surface.configuration, "defaultDurationSeconds")).toBe( false, ); } } }); it("owns an explicit canonical timeline duration without changing the default provider", () => { const oneSecondPlayback = timelineModule({ defaultDurationSeconds: 1, mode: "playback", }); const sixtySecondPlayback = timelineModule({ defaultDurationSeconds: 60, mode: "playback", }); expect( timelineModule({ defaultDurationSeconds: 1, mode: "playback" }), ).toBe(oneSecondPlayback); expect(oneSecondPlayback).not.toBe(sixtySecondPlayback); expect(oneSecondPlayback.contributions[0]).toEqual({ id: "timeline.surface", kind: "panel-surface", moduleId: "timeline", surface: "timeline", configuration: { defaultDurationSeconds: 1, enabled: true, mode: "playback", }, }); expect(Object.isFrozen(oneSecondPlayback.contributions[0])).toBe(true); const surface = oneSecondPlayback.contributions[0]; expect( surface?.kind === "panel-surface" && surface.surface === "timeline" && Object.isFrozen(surface.configuration), ).toBe(true); expect(timelineModule({ mode: "playback" })).not.toBe(oneSecondPlayback); const defaultSurface = timelineModule({ mode: "playback" }) .contributions[0]; expect( defaultSurface?.kind === "panel-surface" && defaultSurface.surface === "timeline" && Object.hasOwn(defaultSurface.configuration, "defaultDurationSeconds"), ).toBe(false); }); it.each([0, 61, Number.NaN, Number.POSITIVE_INFINITY])( "rejects the invalid timeline duration %s before creating a definition", (defaultDurationSeconds) => { expect(() => timelineModule({ defaultDurationSeconds, mode: "playback" }), ).toThrowError( `Toolcraft timeline defaultDurationSeconds must be a finite number from 1 through 60; received ${String(defaultDurationSeconds)}.`, ); }, ); it("rejects an unknown runtime timeline mode", () => { expect(() => Reflect.apply(timelineModule, undefined, [{ mode: "autonomous" }]), ).toThrowError( 'Toolcraft timeline mode must be exactly "keyframes" or "playback"; received autonomous.', ); }); it("captures mode and duration exactly once before validation and materialization", () => { let modeReads = 0; let durationReads = 0; const options = Object.defineProperties({}, { defaultDurationSeconds: { get() { durationReads += 1; return durationReads === 1 ? 12 : 61; }, }, mode: { get() { modeReads += 1; return modeReads === 1 ? "playback" : "keyframes"; }, }, }); const definition = Reflect.apply(timelineModule, undefined, [options]); expect(modeReads).toBe(1); expect(durationReads).toBe(1); expect(definition.provides).toEqual(["timeline.playback"]); expect(definition.contributions[0]).toMatchObject({ configuration: { defaultDurationSeconds: 12, mode: "playback" }, }); }); });