feat: plugins v1
This commit is contained in:
126
electron/plugin-library.spec.ts
Normal file
126
electron/plugin-library.spec.ts
Normal file
@@ -0,0 +1,126 @@
|
||||
import {
|
||||
afterEach,
|
||||
beforeEach,
|
||||
describe,
|
||||
expect,
|
||||
it,
|
||||
vi
|
||||
} from 'vitest';
|
||||
import {
|
||||
cp,
|
||||
mkdtemp,
|
||||
mkdir,
|
||||
rm,
|
||||
writeFile
|
||||
} from 'fs/promises';
|
||||
import { join } from 'path';
|
||||
import { tmpdir } from 'os';
|
||||
import { TEST_PLUGIN_FIXTURE_DIR, TEST_PLUGIN_ID } from '../e2e/helpers/plugin-api-test-fixture';
|
||||
|
||||
const { mockGetPath } = vi.hoisted(() => ({
|
||||
mockGetPath: vi.fn()
|
||||
}));
|
||||
|
||||
vi.mock('electron', () => ({
|
||||
app: {
|
||||
getPath: mockGetPath
|
||||
}
|
||||
}));
|
||||
|
||||
import { getLocalPluginsPath, listLocalPluginManifests } from './plugin-library';
|
||||
|
||||
describe('plugin-library', () => {
|
||||
let userDataPath: string;
|
||||
|
||||
beforeEach(async () => {
|
||||
userDataPath = await mkdtemp(join(tmpdir(), 'metoyou-plugin-library-'));
|
||||
mockGetPath.mockReturnValue(userDataPath);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await rm(userDataPath, { recursive: true, force: true });
|
||||
mockGetPath.mockReset();
|
||||
});
|
||||
|
||||
it('creates and reports the local plugins folder', async () => {
|
||||
const pluginsPath = await getLocalPluginsPath();
|
||||
const result = await listLocalPluginManifests();
|
||||
|
||||
expect(pluginsPath).toBe(join(userDataPath, 'plugins'));
|
||||
expect(result).toEqual({
|
||||
errors: [],
|
||||
plugins: [],
|
||||
pluginsPath
|
||||
});
|
||||
});
|
||||
|
||||
it('discovers immediate child plugin manifests and safe relative files', async () => {
|
||||
const pluginRoot = join(userDataPath, 'plugins', 'api-test-plugin');
|
||||
|
||||
await cp(TEST_PLUGIN_FIXTURE_DIR, pluginRoot, { recursive: true });
|
||||
|
||||
const result = await listLocalPluginManifests();
|
||||
|
||||
expect(result.errors).toEqual([]);
|
||||
expect(result.plugins).toHaveLength(1);
|
||||
expect(result.plugins[0]).toEqual(expect.objectContaining({
|
||||
entrypointPath: join(pluginRoot, 'dist', 'main.js'),
|
||||
manifestPath: join(pluginRoot, 'toju-plugin.json'),
|
||||
pluginRoot,
|
||||
readmePath: join(pluginRoot, 'README.md')
|
||||
}));
|
||||
|
||||
expect(result.plugins[0]?.manifest).toEqual(expect.objectContaining({ id: TEST_PLUGIN_ID }));
|
||||
});
|
||||
|
||||
it('reports invalid JSON and keeps scanning other plugins', async () => {
|
||||
const invalidRoot = join(userDataPath, 'plugins', 'invalid-plugin');
|
||||
const validRoot = join(userDataPath, 'plugins', 'valid-plugin');
|
||||
|
||||
await mkdir(invalidRoot, { recursive: true });
|
||||
await mkdir(validRoot, { recursive: true });
|
||||
await writeFile(join(invalidRoot, 'plugin.json'), '{', 'utf8');
|
||||
await writeFile(join(validRoot, 'plugin.json'), JSON.stringify({
|
||||
apiVersion: '1.0.0',
|
||||
compatibility: { minimumTojuVersion: '1.0.0' },
|
||||
description: 'Valid plugin',
|
||||
entrypoint: './main.js',
|
||||
id: 'valid.plugin',
|
||||
kind: 'client',
|
||||
schemaVersion: 1,
|
||||
title: 'Valid Plugin',
|
||||
version: '1.0.0'
|
||||
}), 'utf8');
|
||||
|
||||
const result = await listLocalPluginManifests();
|
||||
|
||||
expect(result.plugins.map((plugin) => plugin.pluginRoot)).toEqual([validRoot]);
|
||||
expect(result.errors).toHaveLength(1);
|
||||
expect(result.errors[0]).toEqual(expect.objectContaining({
|
||||
manifestPath: join(invalidRoot, 'plugin.json'),
|
||||
pluginRoot: invalidRoot
|
||||
}));
|
||||
});
|
||||
|
||||
it('does not resolve entrypoints outside the plugin folder', async () => {
|
||||
const pluginRoot = join(userDataPath, 'plugins', 'unsafe-plugin');
|
||||
|
||||
await mkdir(pluginRoot, { recursive: true });
|
||||
await writeFile(join(userDataPath, 'plugins', 'outside.js'), 'export default {};', 'utf8');
|
||||
await writeFile(join(pluginRoot, 'plugin.json'), JSON.stringify({
|
||||
apiVersion: '1.0.0',
|
||||
compatibility: { minimumTojuVersion: '1.0.0' },
|
||||
description: 'Unsafe plugin',
|
||||
entrypoint: '../outside.js',
|
||||
id: 'unsafe.plugin',
|
||||
kind: 'client',
|
||||
schemaVersion: 1,
|
||||
title: 'Unsafe Plugin',
|
||||
version: '1.0.0'
|
||||
}), 'utf8');
|
||||
|
||||
const result = await listLocalPluginManifests();
|
||||
|
||||
expect(result.plugins[0]?.entrypointPath).toBeUndefined();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user