import { describe, expect, it } from "vitest"; import { evaluatePluginClientBundle } from "./evaluate"; function bundle(body: string): string { return `(function() { const module = { exports: {} }; module.exports.default = function(plugin) { ${body}; return function() {}; }; return module.exports; })`; } describe("evaluatePluginClientBundle", () => { it("collects a surface and its sidebar placement", () => { const plugin = evaluatePluginClientBundle( "example", bundle(` function Surface() { return null; } plugin.addSurface("main", Surface); plugin.addSidebarItem({ id: "main", title: "Example", icon: "Blocks", surface: "main" }); `), ); expect(plugin.id).toBe("example"); expect(plugin.surfaces.map((surface) => surface.id)).toEqual(["main"]); expect(plugin.sidebarItems).toEqual([ { id: "main", title: "Example", icon: "Blocks", surface: "main" }, ]); }); it("collects a declarative attachment source", () => { const plugin = evaluatePluginClientBundle( "linear", bundle(` plugin.addAttachmentSource({ id: "issues", title: "Linear issue", icon: "CircleDot", pickerTitle: "Attach Linear issue", searchPlaceholder: "Search by identifier or title", search: { name: "issues.search", input: {}, output: {} }, }); `), ); expect(plugin.attachmentSources).toEqual([ { id: "issues", title: "Linear issue", icon: "CircleDot", pickerTitle: "Attach Linear issue", searchPlaceholder: "Search by identifier or title", search: { name: "issues.search", input: {}, output: {} }, }, ]); }); it("collects contextual workspace panels and Command Center items", () => { const plugin = evaluatePluginClientBundle( "review", bundle(` function ReviewPanel() { return null; } plugin.addWorkspacePanel({ id: "review", title: "Review", icon: "Scan", context: "agent", Component: ReviewPanel, }); plugin.addCommandCenterItem({ id: "open-review", title: "Open review", icon: "Scan", context: "agent", onSelect() {}, }); `), ); expect( plugin.workspacePanels.map(({ id, title, icon, context }) => ({ id, title, icon, context, })), ).toEqual([{ id: "review", title: "Review", icon: "Scan", context: "agent" }]); expect( plugin.commandCenterItems.map(({ id, title, icon, context }) => ({ id, title, icon, context, })), ).toEqual([{ id: "open-review", title: "Open review", icon: "Scan", context: "agent" }]); }); it("rejects duplicate workspace panel and Command Center ids", () => { expect(() => evaluatePluginClientBundle( "review", bundle(` function Panel() { return null; } const panel = { id: "review", title: "Review", icon: "Scan", context: "workspace", Component: Panel }; plugin.addWorkspacePanel(panel); plugin.addWorkspacePanel(panel); `), ), ).toThrow("Duplicate workspace panel: review"); expect(() => evaluatePluginClientBundle( "review", bundle(` const item = { id: "review", title: "Review", icon: "Scan", context: "global", onSelect() {} }; plugin.addCommandCenterItem(item); plugin.addCommandCenterItem(item); `), ), ).toThrow("Duplicate Command Center item: review"); }); it("rejects duplicate attachment source ids", () => { expect(() => evaluatePluginClientBundle( "linear", bundle(` const source = { id: "issues", title: "Linear issue", icon: "CircleDot", pickerTitle: "Attach Linear issue", searchPlaceholder: "Search", search: { name: "issues.search", input: {}, output: {} }, }; plugin.addAttachmentSource(source); plugin.addAttachmentSource(source); `), ), ).toThrow("Duplicate attachment source: issues"); }); it("rejects a sidebar placement whose surface does not exist", () => { expect(() => evaluatePluginClientBundle( "example", bundle(` plugin.addSidebarItem({ id: "main", title: "Example", icon: "Blocks", surface: "missing" }); `), ), ).toThrow("references missing surface missing"); }); it("rejects a bundle without a default contribution function", () => { expect(() => evaluatePluginClientBundle("example", `(function() { return {}; })`)).toThrow( "must default export a function", ); }); it("requires a cleanup function", () => { expect(() => evaluatePluginClientBundle("example", `(function() { return { default: function() {} }; })`), ).toThrow("must return a cleanup function"); }); it("does not publish partial contributions when setup fails", () => { expect(() => evaluatePluginClientBundle( "example", `(function() { return { default: function(plugin) { plugin.addSurface("main", function() { return null; }); throw new Error("setup exploded"); } }; })`, ), ).toThrow("setup exploded"); }); });