5822b64d7c
接入 Godot 原生桥、受控执行、Runner 回执与编辑器操作指南 保留主分支 Cocos 和 Unity 跨工程能力及外置提示词结构 解决插件生命周期、工具目录、前端启动和文档合并冲突
140 lines
4.6 KiB
TypeScript
140 lines
4.6 KiB
TypeScript
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
|
|
import {
|
|
setAgcPluginProjectPath,
|
|
startAvailableAgcEditorPlugins,
|
|
} from '../src/services/pluginHost';
|
|
|
|
afterEach(() => vi.unstubAllGlobals());
|
|
|
|
const editorPlugins = [
|
|
{ id: 'agc-cocos-editor', name: 'Cocos Creator' },
|
|
{ id: 'agc-unity-editor', name: 'Unity' },
|
|
{ id: 'agc-godot-editor', name: 'Godot' },
|
|
].map((plugin) => ({
|
|
...plugin,
|
|
builtin: true,
|
|
enabled: true,
|
|
hasRuntime: true,
|
|
status: 'stopped',
|
|
}));
|
|
|
|
describe('插件自动启动使用后端能力投影', () => {
|
|
it.each(
|
|
[
|
|
[],
|
|
[
|
|
{
|
|
...editorPlugins[0],
|
|
enabled: false,
|
|
hasRuntime: true,
|
|
status: 'stopped',
|
|
},
|
|
],
|
|
[
|
|
{
|
|
...editorPlugins[0],
|
|
enabled: true,
|
|
hasRuntime: false,
|
|
status: 'package',
|
|
},
|
|
],
|
|
[
|
|
{
|
|
...editorPlugins[0],
|
|
enabled: true,
|
|
hasRuntime: true,
|
|
status: 'invalid',
|
|
},
|
|
],
|
|
[{ ...editorPlugins[0], status: 'running' }],
|
|
[{ ...editorPlugins[0], status: 'failed' }],
|
|
[{ ...editorPlugins[0], status: 'disabled' }],
|
|
[{ ...editorPlugins[0], builtin: false }],
|
|
[{ ...editorPlugins[0], id: 'other-plugin' }],
|
|
].map((plugins) => ({ plugins })),
|
|
)('只启动宿主投影允许自动启动的内置编辑器插件(%j)', async ({ plugins }) => {
|
|
const invoke = vi.fn(async () => plugins);
|
|
vi.stubGlobal('window', { __TAURI__: { core: { invoke } } });
|
|
await startAvailableAgcEditorPlugins();
|
|
expect(invoke).toHaveBeenCalledTimes(1);
|
|
expect(invoke).toHaveBeenCalledWith('list_agc_plugins');
|
|
});
|
|
|
|
it.each(['stopped', 'discovered'])(
|
|
'从同一份宿主列表启动所有可用的编辑器插件:%s',
|
|
async (status) => {
|
|
const invoke = vi.fn(async (command: string) =>
|
|
command === 'list_agc_plugins'
|
|
? editorPlugins.map((plugin) => ({ ...plugin, status }))
|
|
: {},
|
|
);
|
|
vi.stubGlobal('window', { __TAURI__: { core: { invoke } } });
|
|
await startAvailableAgcEditorPlugins();
|
|
expect(invoke.mock.calls).toEqual([
|
|
['list_agc_plugins'],
|
|
['start_agc_plugin', { id: 'agc-cocos-editor' }],
|
|
['start_agc_plugin', { id: 'agc-unity-editor' }],
|
|
['start_agc_plugin', { id: 'agc-godot-editor' }],
|
|
]);
|
|
},
|
|
);
|
|
|
|
it('一个编辑器插件启动失败仍启动其余插件,且不自动重试', async () => {
|
|
const invoke = vi.fn(async (command: string, params?: { id: string }) => {
|
|
if (command === 'list_agc_plugins') return editorPlugins;
|
|
if (params?.id === 'agc-cocos-editor') throw new Error('进程已退出');
|
|
return {};
|
|
});
|
|
vi.stubGlobal('window', { __TAURI__: { core: { invoke } } });
|
|
await expect(startAvailableAgcEditorPlugins()).rejects.toThrow(
|
|
'Cocos Creator:进程已退出',
|
|
);
|
|
expect(invoke.mock.calls).toEqual([
|
|
['list_agc_plugins'],
|
|
['start_agc_plugin', { id: 'agc-cocos-editor' }],
|
|
['start_agc_plugin', { id: 'agc-unity-editor' }],
|
|
['start_agc_plugin', { id: 'agc-godot-editor' }],
|
|
]);
|
|
});
|
|
|
|
it('项目切换后迟到的插件列表不会启动旧项目的插件', async () => {
|
|
let finishList!: (plugins: typeof editorPlugins) => void;
|
|
const invoke = vi.fn(
|
|
() =>
|
|
new Promise<typeof editorPlugins>((resolve) => {
|
|
finishList = resolve;
|
|
}),
|
|
);
|
|
vi.stubGlobal('window', { __TAURI__: { core: { invoke } } });
|
|
let active = true;
|
|
const start = startAvailableAgcEditorPlugins(() => active);
|
|
active = false;
|
|
finishList(editorPlugins);
|
|
await start;
|
|
expect(invoke).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('快速切换项目时旧 cleanup 不能晚于新项目设置抵达宿主', async () => {
|
|
const received: Array<string | null> = [];
|
|
let finishFirst: () => void = () => undefined;
|
|
const invoke = vi.fn(
|
|
async (_command: string, params: { projectPath: string | null }) => {
|
|
if (params.projectPath === 'C:/A')
|
|
await new Promise<void>((resolve) => {
|
|
finishFirst = resolve;
|
|
});
|
|
received.push(params.projectPath);
|
|
},
|
|
);
|
|
vi.stubGlobal('window', { __TAURI__: { core: { invoke } } });
|
|
const first = setAgcPluginProjectPath('C:/A');
|
|
const cleanup = setAgcPluginProjectPath(null);
|
|
const second = setAgcPluginProjectPath('C:/B');
|
|
await vi.waitFor(() => expect(invoke).toHaveBeenCalledTimes(1));
|
|
finishFirst();
|
|
await Promise.all([first, cleanup, second]);
|
|
expect(received).toEqual(['C:/A', null, 'C:/B']);
|
|
});
|
|
});
|