import { describe, expect, it } from "vitest"; import * as publicRuntime from "../index"; import { svgExportModule } from "../modules/built-ins/svg-export/svg-export-module"; import { defineToolcraft } from "./define-toolcraft"; import { createToolcraftArtifactExportActions, getToolcraftArtifactExportActions, isToolcraftArtifactExportActionRole, TOOLCRAFT_ARTIFACT_EXPORT_ACTION_ROLES, type ToolcraftArtifactExportActionRole, } from "./artifact-export-actions"; type PublicArtifactExportActionRole = import("../index").ToolcraftArtifactExportActionRole; const publicArtifactExportActionRole: PublicArtifactExportActionRole = "export-image"; void publicArtifactExportActionRole; const standardActionByRole = { "export-image": { icon: "upload-simple", label: "Export PNG", role: "export-image", value: "export.png", }, "export-svg": { icon: "upload-simple", label: "Export SVG", role: "export-svg", value: "export.svg", }, "export-video": { icon: "upload-simple", label: "Export Video", role: "export-video", value: "export.video", }, } as const; const actionRoleCombinations = [ { roles: [] }, { roles: ["export-image"] }, { roles: ["export-svg"] }, { roles: ["export-video"] }, { roles: ["export-image", "export-svg"] }, { roles: ["export-image", "export-video"] }, { roles: ["export-svg", "export-video"] }, { roles: ["export-image", "export-svg", "export-video"] }, ] as const satisfies readonly { readonly roles: readonly ToolcraftArtifactExportActionRole[]; }[]; function expectedActions(roles: readonly ToolcraftArtifactExportActionRole[]) { const primaryRole = roles.includes("export-video") ? "export-video" : roles.includes("export-image") ? "export-image" : roles.includes("export-svg") ? "export-svg" : undefined; return (["export-image", "export-svg", "export-video"] as const) .filter((role) => roles.includes(role)) .map((role) => role === primaryRole ? standardActionByRole[role] : { ...standardActionByRole[role], variant: "outline" }, ); } describe("artifact export actions", () => { it("recognizes the closed runtime-owned role set", () => { expect(isToolcraftArtifactExportActionRole("export-image")).toBe(true); expect(isToolcraftArtifactExportActionRole("export-svg")).toBe(true); expect(isToolcraftArtifactExportActionRole("export-video")).toBe(true); expect(isToolcraftArtifactExportActionRole("download-output")).toBe(false); }); it("keeps the canonical role rank frozen and mutation isolated", () => { expect(Object.isFrozen(TOOLCRAFT_ARTIFACT_EXPORT_ACTION_ROLES)).toBe(true); expect( Reflect.set(TOOLCRAFT_ARTIFACT_EXPORT_ACTION_ROLES, 0, "export-video"), ).toBe(false); expect(TOOLCRAFT_ARTIFACT_EXPORT_ACTION_ROLES).toEqual([ "export-image", "export-svg", "export-video", ]); expect( createToolcraftArtifactExportActions([ "export-video", "export-svg", "export-image", ]).map(({ role }) => role), ).toEqual(["export-image", "export-svg", "export-video"]); }); it("keeps internal action construction outside the package root", () => { expect(publicRuntime.TOOLCRAFT_ARTIFACT_EXPORT_ACTION_ROLES).toBe( TOOLCRAFT_ARTIFACT_EXPORT_ACTION_ROLES, ); expect(publicRuntime.isToolcraftArtifactExportActionRole).toBe( isToolcraftArtifactExportActionRole, ); expect(publicRuntime.getToolcraftArtifactExportActions).toBe( getToolcraftArtifactExportActions, ); expect(publicRuntime.isToolcraftArtifactExportAction).toBeTypeOf( "function", ); expect("createToolcraftArtifactExportActions" in publicRuntime).toBe(false); expect("compareToolcraftArtifactExportActionRoles" in publicRuntime).toBe( false, ); }); it.each(actionRoleCombinations)( "constructs the canonical frozen action set for $roles", ({ roles }) => { const actions = createToolcraftArtifactExportActions( [...roles].reverse(), ); expect(actions).toEqual(expectedActions(roles)); expect(Object.isFrozen(actions)).toBe(true); expect(actions.every(Object.isFrozen)).toBe(true); }, ); it("rejects duplicate roles deterministically", () => { expect(() => createToolcraftArtifactExportActions([ "export-video", "export-image", "export-video", "export-image", ]), ).toThrowError( "Toolcraft artifact export action roles must be unique; duplicates: export-image, export-video.", ); }); it("collects typed export actions only from sticky panelActions", () => { const schema = defineToolcraft({ base: { identity: { id: "runtime-test", title: "Toolcraft App" }, canvas: { enabled: true }, panels: { controls: { sections: [], title: "Controls" } }, }, modules: [svgExportModule()], }); expect( getToolcraftArtifactExportActions(schema).map(({ value }) => value), ).toEqual(["export.svg"]); }); });