594063a1e0
- 按 vitest 0.34 的参数元组口径改写 mock 泛型 - 修正 noUncheckedIndexedAccess 下的下标访问 - 补齐与当前类型脱节的测试桩字段 - 按 scripts/*.mjs 的运行时契约补局部类型声明
120 lines
3.8 KiB
TypeScript
120 lines
3.8 KiB
TypeScript
/** @vitest-environment jsdom */
|
|
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
|
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
|
|
import { createGameCreationAppManifest } from '../../../packages/shared/src/contracts/gameCreationApp';
|
|
import ProjectDevelopmentView from '../src/view/project-development';
|
|
|
|
const openUrl = vi.fn(async (_url: string) => undefined);
|
|
vi.mock('@tauri-apps/plugin-opener', () => ({
|
|
openUrl: (url: string) => openUrl(url),
|
|
}));
|
|
|
|
const PREVIEW_URL = 'http://127.0.0.1:4173/';
|
|
|
|
function installInvoke() {
|
|
window.__TAURI__ = {
|
|
core: {
|
|
invoke: vi.fn(async (command: string, args?: Record<string, unknown>) => {
|
|
if (command === 'read_local_project_resource_graph') {
|
|
return {
|
|
resourceIds: [],
|
|
referenceEdges: [],
|
|
taskFlows: [],
|
|
categories: [],
|
|
diagnostics: [],
|
|
};
|
|
}
|
|
if (command === 'read_local_project_resource_canvas_layout') {
|
|
return {
|
|
schemaVersion: 'game-creator-resource-layout.v1',
|
|
projectId: args?.expectedProjectId,
|
|
mode: args?.mode,
|
|
revision: 0,
|
|
positions: [],
|
|
updatedAt: 0,
|
|
};
|
|
}
|
|
throw new Error(`unexpected invoke ${command}`);
|
|
}),
|
|
},
|
|
} as unknown as typeof window.__TAURI__;
|
|
}
|
|
|
|
function renderRunView(options: { withPreview?: boolean } = {}) {
|
|
installInvoke();
|
|
const manifest = createGameCreationAppManifest(
|
|
'run-preview-browser-open',
|
|
'运行页浏览器入口',
|
|
);
|
|
const onNotice = vi.fn();
|
|
render(
|
|
<ProjectDevelopmentView
|
|
projectName={manifest.name}
|
|
projectPath="/tmp/run-preview-browser-open"
|
|
manifest={manifest}
|
|
attachments={[]}
|
|
recentRunStatus={null}
|
|
recentRunStopReason={null}
|
|
preview={
|
|
options.withPreview === false
|
|
? null
|
|
: { status: 'running', url: PREVIEW_URL, port: 4173 }
|
|
}
|
|
chat={<div>项目总控</div>}
|
|
onHomeOpen={vi.fn()}
|
|
onProjectsOpen={vi.fn()}
|
|
onNotice={onNotice}
|
|
/>,
|
|
);
|
|
return { onNotice };
|
|
}
|
|
|
|
afterEach(() => {
|
|
document.body.innerHTML = '';
|
|
vi.clearAllMocks();
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
describe('运行页「在浏览器打开」', () => {
|
|
it('点顶栏那枚按钮就把当前预览地址交给系统浏览器', async () => {
|
|
renderRunView();
|
|
|
|
const entry = await screen.findByRole('button', {
|
|
name: '在浏览器打开',
|
|
});
|
|
// 入口住在工作台顶栏的动作区里,与版本入口同一排;预览地址本身不再以文字出现。
|
|
expect(entry.closest('.game-workbench-view-actions')).not.toBeNull();
|
|
expect(document.body.textContent ?? '').not.toContain(PREVIEW_URL);
|
|
expect(document.querySelector('.game-run-status-hint')).toBeNull();
|
|
fireEvent.click(entry);
|
|
|
|
await waitFor(() => expect(openUrl).toHaveBeenCalledWith(PREVIEW_URL));
|
|
// 成功不弹提示:浏览器真的起来了,用户自己看得见。
|
|
expect(openUrl).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('没有活预览时不渲染这枚入口', async () => {
|
|
renderRunView({ withPreview: false });
|
|
|
|
await screen.findByRole('tab', { name: '运行' });
|
|
expect(screen.queryByRole('button', { name: '在浏览器打开' })).toBeNull();
|
|
});
|
|
|
|
it('打开失败时把原因交给统一提示通道,而不是静默吞掉', async () => {
|
|
openUrl.mockRejectedValueOnce(new Error('permission denied'));
|
|
const { onNotice } = renderRunView();
|
|
|
|
fireEvent.click(
|
|
await screen.findByRole('button', { name: '在浏览器打开' }),
|
|
);
|
|
|
|
await waitFor(() =>
|
|
expect(onNotice).toHaveBeenCalledWith({
|
|
tone: 'error',
|
|
message: '在浏览器打开失败:permission denied',
|
|
}),
|
|
);
|
|
});
|
|
});
|