Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 55 additions & 1 deletion test/plugins/plugin-manager.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,19 @@ describe('PluginManager', () => {
metadata: { name: 'test', version: '1.0.0' },
install: jest.fn()
} as any;

await expect(pluginManager.installPlugin(plugin))
.rejects.toThrow('Plugin must implement uninstall method');
});

it('should fail when required dependencies are missing', async () => {
const plugin = createMockPlugin('dep-plugin');
plugin.metadata.dependencies = { 'non-existent-package': '1.0.0' };

await expect(pluginManager.installPlugin(plugin))
.rejects.toThrow('Dependency non-existent-package@1.0.0 not found');
expect(plugin.install).not.toHaveBeenCalled();
});
});

describe('Plugin Uninstallation', () => {
Expand All @@ -159,6 +168,15 @@ describe('PluginManager', () => {
await expect(pluginManager.uninstallPlugin('inexistent-plugin'))
.rejects.toThrow('Plugin inexistent-plugin not found');
});

it('should handle errors during plugin uninstallation', async () => {
const plugin = createMockPlugin('test-plugin');
plugin.uninstall = jest.fn().mockRejectedValue(new Error('Uninstall error'));
await pluginManager.installPlugin(plugin);

await expect(pluginManager.uninstallPlugin('test-plugin'))
.rejects.toThrow('Uninstall error');
});
});

describe('Plugin Enable/Disable', () => {
Expand Down Expand Up @@ -301,6 +319,23 @@ describe('PluginManager', () => {
expect(results[1].success).toBe(true);
expect(successHook).toHaveBeenCalled();
});

it('should remove hooks when plugin is uninstalled', async () => {
const hook = jest.fn().mockResolvedValue({});
const plugin = createMockPlugin('test-plugin');
plugin.getHooks = jest.fn().mockReturnValue({
beforePermissionCheck: hook
});

await pluginManager.installPlugin(plugin);
await pluginManager.uninstallPlugin('test-plugin');

const data: HookData = { role: 'user', operation: 'read', params: {} };
const results = await pluginManager.executeHooks('beforePermissionCheck', data);

expect(results).toHaveLength(0);
expect(hook).not.toHaveBeenCalled();
});
});

describe('Plugin Configuration', () => {
Expand Down Expand Up @@ -360,6 +395,18 @@ describe('PluginManager', () => {
});
});

describe('Internal Utilities', () => {
it('should return null when handler has no associated plugin', () => {
const result = (pluginManager as any).findPluginByHandler(() => {});
expect(result).toBeNull();
});

it('should attempt to load plugins from directory', async () => {
await expect(pluginManager.loadPluginsFromDirectory('/tmp'))
.resolves.not.toThrow();
Comment on lines +404 to +406

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Use proper matcher for successful loadPluginsFromDirectory

The new test attempts to verify that loadPluginsFromDirectory doesn’t throw by doing await expect(pluginManager.loadPluginsFromDirectory('/tmp')).resolves.not.toThrow();. After .resolves the matcher is applied to the resolved value (undefined), so using toThrow raises Jest’s own assertion error (received value must be a function) and the test fails even if the method behaves correctly. To assert the absence of errors, wrap the call in a function or check the resolved value, e.g. await expect(() => pluginManager.loadPluginsFromDirectory('/tmp')).not.toThrow() or await expect(pluginManager.loadPluginsFromDirectory('/tmp')).resolves.toBeUndefined();.

Useful? React with 👍 / 👎.

});
});

describe('Events', () => {
it('should emit installation event', async () => {
const eventSpy = jest.fn();
Expand Down Expand Up @@ -446,6 +493,13 @@ describe('PluginManager', () => {
})
}));
});

it('should log plugin system errors', () => {
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
(pluginManager as any).registry.events.emit('error', 'boom');
expect(errorSpy).toHaveBeenCalledWith(expect.stringContaining('boom'));
errorSpy.mockRestore();
});
});

describe('Strict Mode', () => {
Expand Down