import '../fixtures/window'; import { Editor } from '@ali/lowcode-editor-core'; import { LowCodePluginManager } from '../../src/plugin/plugin-manager'; import { ILowCodePluginContext, ILowCodePluginManager } from '../../src/plugin/plugin-types'; const editor = new Editor(); describe('plugin 测试', () => { let pluginManager: ILowCodePluginManager; beforeEach(() => { pluginManager = new LowCodePluginManager(editor).toProxy(); }); afterEach(() => { pluginManager.dispose(); }); it('注册插件,插件参数生成函数能被调用,且能拿到正确的 ctx / options', () => { const mockFn = jest.fn(); pluginManager.register((ctx: ILowCodePluginContext, options: any) => { mockFn(ctx, options); return { name: 'demo1', }; }, { test: 1 }); const [expectedCtx, expectedOptions] = mockFn.mock.calls[0]; expect(expectedCtx).toHaveProperty('designer'); expect(expectedCtx).toHaveProperty('designerCabin'); expect(expectedCtx).toHaveProperty('editor'); expect(expectedCtx).toHaveProperty('hotkey'); expect(expectedCtx).toHaveProperty('plugins'); expect(expectedCtx).toHaveProperty('skeleton'); expect(expectedCtx).toHaveProperty('logger'); expect(expectedOptions).toEqual({ test: 1 }); }); it('注册插件,调用插件 init 方法', async () => { const mockFn = jest.fn(); pluginManager.register((ctx: ILowCodePluginContext, options: any) => { return { name: 'demo1', init: mockFn, exports() { return { x: 1, y: 2, }; }, }; }, { test: 1 }); await pluginManager.init(); expect(pluginManager.size).toBe(1); expect(pluginManager.has('demo1')).toBeTruthy(); expect(pluginManager.get('demo1')!.isInited()).toBeTruthy(); expect(pluginManager.demo1).toBeTruthy(); expect(pluginManager.demo1.x).toBe(1); expect(pluginManager.demo1.y).toBe(2); expect(mockFn).toHaveBeenCalled(); }); it('注册插件,调用 setDisabled 方法', async () => { const mockFn = jest.fn(); pluginManager.register((ctx: ILowCodePluginContext, options: any) => { return { name: 'demo1', init: mockFn, }; }, { test: 1 }); await pluginManager.init(); expect(pluginManager.demo1).toBeTruthy(); pluginManager.setDisabled('demo1', true); expect(pluginManager.demo1).toBeUndefined(); }); it('删除插件,调用插件 destory 方法', async () => { const mockFn = jest.fn(); pluginManager.register((ctx: ILowCodePluginContext, options: any) => { return { name: 'demo1', destroy: mockFn, }; }, { test: 1 }); await pluginManager.init(); await pluginManager.delete('demo1'); expect(mockFn).toHaveBeenCalled(); await pluginManager.delete('non-existing'); }); it('dep 依赖', async () => { const mockFn = jest.fn(); pluginManager.register((ctx: ILowCodePluginContext, options: any) => { return { name: 'demo1', dep: ['demo2'], init: () => mockFn('demo1'), }; }); pluginManager.register((ctx: ILowCodePluginContext, options: any) => { return { name: 'demo2', init: () => mockFn('demo2'), }; }); await pluginManager.init(); expect(mockFn).toHaveBeenNthCalledWith(1, 'demo2'); expect(mockFn).toHaveBeenNthCalledWith(2, 'demo1'); }); it('autoInit 功能', async () => { const mockFn = jest.fn(); await pluginManager.register((ctx: ILowCodePluginContext, options: any) => { return { name: 'demo1', init: mockFn, }; }, { test: 1 }, { autoInit: true }); expect(mockFn).toHaveBeenCalled(); }); it('插件不会重复 init,除非强制重新 init', async () => { const mockFn = jest.fn(); pluginManager.register((ctx: ILowCodePluginContext, options: any) => { return { name: 'demo1', init: mockFn, }; }, { test: 1 }); await pluginManager.init(); expect(mockFn).toHaveBeenCalledTimes(1); pluginManager.get('demo1')!.init(); expect(mockFn).toHaveBeenCalledTimes(1); pluginManager.get('demo1')!.init(true); expect(mockFn).toHaveBeenCalledTimes(2); }); it('默认情况不允许重复注册', async () => { const mockFn = jest.fn(); const mockPlugin = (ctx: ILowCodePluginContext, options: any) => { return { name: 'demoDuplicated', init: mockFn, }; }; pluginManager.register(mockPlugin, { test: 1 }); pluginManager.register(mockPlugin, { test: 1 }).catch(e => { expect(e).toEqual(new Error('Plugin with name demoDuplicated exists')); }); await pluginManager.init(); }); it('插件增加 override 参数时可以重复注册', async () => { const mockFn = jest.fn(); const mockPlugin = (ctx: ILowCodePluginContext, options: any) => { return { name: 'demoOverride', init: mockFn, }; }; pluginManager.register(mockPlugin, { test: 1 }); pluginManager.register(mockPlugin, { test: 1 }, { override: true }); await pluginManager.init(); }); it('插件增加 override 参数时可以重复注册, 被覆盖的如果已初始化,会被销毁', async () => { const mockInitFn = jest.fn(); const mockDestroyFn = jest.fn(); const mockPlugin = (ctx: ILowCodePluginContext, options: any) => { return { name: 'demoOverride', init: mockInitFn, destroy: mockDestroyFn, }; }; await pluginManager.register(mockPlugin, { test: 1 }, { autoInit: true }); expect(mockInitFn).toHaveBeenCalledTimes(1); await pluginManager.register(mockPlugin, { test: 1 }, { override: true }); expect(mockDestroyFn).toHaveBeenCalledTimes(1); await pluginManager.init(); }); it('内部事件机制', async () => { const mockFn = jest.fn(); pluginManager.register((ctx: ILowCodePluginContext, options: any) => { return { name: 'demo1', }; }, { test: 1 }); await pluginManager.init(); const plugin = pluginManager.get('demo1')!; plugin.on('haha', mockFn); plugin.emit('haha', 1, 2, 3); expect(mockFn).toHaveBeenCalledTimes(1); expect(mockFn).toHaveBeenCalledWith(1, 2, 3); plugin.removeAllListeners('haha'); plugin.emit('haha', 1, 2, 3); expect(mockFn).toHaveBeenCalledTimes(1); }); it('dispose 方法', async () => { pluginManager.register((ctx: ILowCodePluginContext, options: any) => { return { name: 'demo1', }; }, { test: 1 }); await pluginManager.init(); const plugin = pluginManager.get('demo1')!; await plugin.dispose(); expect(pluginManager.has('demo1')).toBeFalsy(); }); });