/** * Plugin-API v2 Tests (Task A1). * Deckt: registerV2 / enableV2 / disableV2 / isV2Enabled, * getToolsV2 (nur aktive Plugins), getPanels, getLibraryProviders, * doppelte IDs verworfen, initDefaults mit V2. */ import { describe, it, expect, afterEach } from 'vitest'; import { pluginRegistry } from '../src/plugins/PluginRegistry'; import type { PluginV2, ToolExtensionV2, } from '../src/plugins/types'; function makeTool(id: string): ToolExtensionV2 { return { manifest: { id, label: id, icon: '□', ribbonTab: 'tools' }, optionsSchema: [], handlers: {}, }; } function makePlugin(id: string, overrides: Partial = {}): PluginV2 { return { manifest: { id, name: id, version: '1.0.0', author: 'test', description: `Testplugin ${id}`, category: 'tools', enabledByDefault: false, }, tools: [makeTool(`${id}-tool`)], ...overrides, }; } describe('pluginRegistry v2', () => { // Testisolierung: Singleton-Registry nach jedem Test vollständig räumen const registered: string[] = []; function track(plugin: PluginV2): void { registered.push(plugin.manifest.id); pluginRegistry.registerV2(plugin); } afterEach(() => { while (registered.length > 0) { pluginRegistry.unregisterV2(registered.pop()!); } }); it('registriert und aktiviert ein V2-Plugin; Tools erscheinen in getToolsV2', () => { track(makePlugin('p1')); expect(pluginRegistry.getToolsV2().length).toBe(0); // noch deaktiviert pluginRegistry.enableV2('p1'); expect(pluginRegistry.isV2Enabled('p1')).toBe(true); const tools = pluginRegistry.getToolsV2(); expect(tools.length).toBe(1); expect(tools[0].manifest.id).toBe('p1-tool'); expect(pluginRegistry.getToolV2('p1-tool')?.manifest.id).toBe('p1-tool'); }); it('deaktivierte Plugins liefern keine Tools/Panels/Provider', () => { track( makePlugin('p2', { panels: [{ id: 'panel-x', title: 'X', slot: 'left', render: () => document.createElement('div') }], libraryProviders: [ { id: 'lib-x', label: 'Lib X', listFolders: async () => [], listBlocks: async () => [], getBlock: async () => ({ id: 'b', folderId: '', name: '' }), }, ], }), ); pluginRegistry.enableV2('p2'); expect(pluginRegistry.getPanels().length).toBe(1); expect(pluginRegistry.getLibraryProviders().length).toBe(1); pluginRegistry.disableV2('p2'); expect(pluginRegistry.isV2Enabled('p2')).toBe(false); expect(pluginRegistry.getPanels().length).toBe(0); expect(pluginRegistry.getLibraryProviders().length).toBe(0); expect(pluginRegistry.getToolsV2().length).toBe(0); }); it('verwirft doppelte Plugin-IDs ohne Fehler und behält das erste', () => { const first = makePlugin('dup'); first.tools = [makeTool('first-tool')]; const second = makePlugin('dup'); second.tools = [makeTool('second-tool')]; track(first); pluginRegistry.registerV2(second); // wird verworfen, muss nicht getrackt werden pluginRegistry.enableV2('dup'); const ids = pluginRegistry.getToolsV2().map((t) => t.manifest.id); expect(ids).toEqual(['first-tool']); }); it('initDefaults aktiviert nur enabledByDefault-Plugins', () => { track({ ...makePlugin('auto-on'), manifest: { ...makePlugin('auto-on').manifest, enabledByDefault: true } }); track(makePlugin('manual-off')); pluginRegistry.initDefaults(); expect(pluginRegistry.isV2Enabled('auto-on')).toBe(true); expect(pluginRegistry.isV2Enabled('manual-off')).toBe(false); }); });