Files
dashcaddy/dashcaddy-api/__tests__/plugins/plugin-manager.test.js
T
Krystie 503de258b8 [grade=pending] QA sprint: commit 103 at-risk files from multi-agent sprint work
Committed by Hermes autonomous QA sprint 2026-08-13.
These files were modified during the Aug 12 sprint but never committed.
2026-08-12 17:34:10 -07:00

156 lines
4.8 KiB
JavaScript

/**
* DC-080: Plugin manager tests
*/
const fs = require('fs');
const path = require('path');
const os = require('os');
const { PluginManager } = require('../../src/plugins/plugin-manager');
describe('DC-080: Plugin Manager', () => {
let tmpDir, manager;
beforeEach(() => {
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'dc-plugins-'));
manager = new PluginManager({
dataDir: tmpDir,
log: { info: jest.fn(), error: jest.fn() },
});
});
afterEach(() => {
fs.rmSync(tmpDir, { recursive: true, force: true });
});
describe('loadAll()', () => {
it('creates plugin directory if it does not exist', async () => {
const pluginDir = path.join(tmpDir, 'plugins');
expect(fs.existsSync(pluginDir)).toBe(false);
await manager.loadAll();
expect(fs.existsSync(pluginDir)).toBe(true);
});
it('loads successfully with empty plugin dir', async () => {
await manager.loadAll();
expect(manager.plugins.size).toBe(0);
expect(manager.loaded).toBe(true);
});
it('skips hidden directories', async () => {
const hiddenDir = path.join(tmpDir, 'plugins', '.hidden');
fs.mkdirSync(hiddenDir, { recursive: true });
await manager.loadAll();
expect(manager.plugins.size).toBe(0);
});
});
describe('loadOne()', () => {
it('loads a plugin with valid manifest', async () => {
const pluginDir = path.join(tmpDir, 'plugins', 'test-plugin');
fs.mkdirSync(pluginDir, { recursive: true });
fs.writeFileSync(
path.join(pluginDir, 'manifest.json'),
JSON.stringify({
name: 'test-plugin',
version: '1.0.0',
description: 'A test plugin',
})
);
await manager.loadOne(pluginDir);
expect(manager.plugins.has('test-plugin')).toBe(true);
});
it('throws if manifest.json is missing', async () => {
const pluginDir = path.join(tmpDir, 'plugins', 'no-manifest');
fs.mkdirSync(pluginDir, { recursive: true });
await expect(manager.loadOne(pluginDir)).rejects.toThrow('manifest.json');
});
it('throws if manifest lacks name or version', async () => {
const pluginDir = path.join(tmpDir, 'plugins', 'invalid');
fs.mkdirSync(pluginDir, { recursive: true });
fs.writeFileSync(
path.join(pluginDir, 'manifest.json'),
JSON.stringify({ description: 'no name' })
);
await expect(manager.loadOne(pluginDir)).rejects.toThrow('name and version');
});
it('throws on duplicate plugin name', async () => {
const pluginDir = path.join(tmpDir, 'plugins', 'dup');
fs.mkdirSync(pluginDir, { recursive: true });
fs.writeFileSync(
path.join(pluginDir, 'manifest.json'),
JSON.stringify({ name: 'dup', version: '1.0.0' })
);
await manager.loadOne(pluginDir);
await expect(manager.loadOne(pluginDir)).rejects.toThrow('already loaded');
});
});
describe('unload()', () => {
it('unloads a loaded plugin', async () => {
const pluginDir = path.join(tmpDir, 'plugins', 'removable');
fs.mkdirSync(pluginDir, { recursive: true });
fs.writeFileSync(
path.join(pluginDir, 'manifest.json'),
JSON.stringify({ name: 'removable', version: '1.0.0' })
);
await manager.loadOne(pluginDir);
expect(manager.plugins.has('removable')).toBe(true);
manager.unload('removable');
expect(manager.plugins.has('removable')).toBe(false);
});
it('returns false for unknown plugin', () => {
expect(manager.unload('nonexistent')).toBe(false);
});
});
describe('list()', () => {
it('returns empty array when no plugins', () => {
expect(manager.list()).toEqual([]);
});
it('returns plugin metadata', async () => {
const pluginDir = path.join(tmpDir, 'plugins', 'listed');
fs.mkdirSync(pluginDir, { recursive: true });
fs.writeFileSync(
path.join(pluginDir, 'manifest.json'),
JSON.stringify({ name: 'listed', version: '2.0.0', description: 'Test' })
);
await manager.loadOne(pluginDir);
const list = manager.list();
expect(list).toHaveLength(1);
expect(list[0].name).toBe('listed');
expect(list[0].version).toBe('2.0.0');
});
});
describe('executeHook()', () => {
it('returns empty results when no plugins have the hook', async () => {
await manager.loadAll();
const results = await manager.executeHook('service:health-check');
expect(results).toEqual([]);
});
});
describe('getWidgets()', () => {
it('returns empty array by default', () => {
expect(manager.getWidgets()).toEqual([]);
});
});
describe('getServiceTypes()', () => {
it('returns empty array by default', () => {
expect(manager.getServiceTypes()).toEqual([]);
});
});
});