Files
Genarrative/apps/ai-game-creator-shell/tests/homeWebPreflight.test.tsx
T
kdletters 44f415d057
Project CI / AI game creator shell Rust lane 1/2 (push) Failing after 2m23s
Project CI / AI game creator shell Rust lane 2/2 (push) Failing after 1m15s
Project CI / AI game creator shell Rust crates (push) Successful in 1m14s
Project CI / AI game creator shell Rust smoke (push) Successful in 1m35s
Project CI / Frontend tests (push) Successful in 2m53s
Project CI / Repository checks (push) Successful in 3m36s
Project CI / Backend tests (push) Successful in 4m26s
Project CI / AI game creator shell web tests (push) Successful in 2m23s
Project CI / Native shell tests (push) Successful in 7m27s
合并 origin/master(58 个提交):生产 Nginx 模板收敛与记录同步
- 合并 origin/master 58 个提交,解决 2 处文件冲突:决策记录与踩坑记录均按两侧新增条目并存处理
- claude_code_cli.rs 自动合并通过:本机 Claude sidecar 诊断改动与上游 sidecar 归位并存,无重复函数定义、无冲突残留
- 保留本地未推送提交:AGC Claude 执行认证与错误诊断、Claude sidecar 超时诊断
- 本次推送主体内容不变:生产 Nginx 模板收敛、host-only snippet 与运维/踩坑/决策文档同步
2026-10-01 18:38:56 +08:00

143 lines
5.0 KiB
TypeScript

// @vitest-environment jsdom
import { act, cleanup, renderHook } from '@testing-library/react';
import { afterEach, expect, it, vi } from 'vitest';
import { createGameCreationAppManifest } from '../../../packages/shared/src/contracts/gameCreationApp';
import {
HOME_WEB_PREFLIGHT_FAILURE,
HOME_WEB_PREFLIGHT_IPC_FAILURE,
} from '../src/features/app-shell/homeWebPreflight';
import { useHomeProjectCreation } from '../src/features/app-shell/useHomeProjectCreation';
afterEach(() => {
cleanup();
delete window.__TAURI__;
});
function mount(preflight: () => Promise<unknown>) {
const calls: string[] = [];
const invoke = vi.fn(async (command: string) => {
if (command !== 'capture_analytics_context') calls.push(command);
if (command === 'preflight_web_game_creation') return preflight();
if (command === 'suggest_automatic_project_name') return '预检项目';
if (command === 'create_automatic_local_game_project')
return {
projectPath: 'C:/test/preflight-game',
manifestPath: 'C:/test/preflight-game/.agent/manifest.json',
manifest: createGameCreationAppManifest('preflight-game', '预检项目'),
};
if (command === 'get_local_game_project_revision') return { revision: 1 };
if (command === 'set_design_agent_runtime_mode')
return { activeRuntime: 'design' };
return null;
});
window.__TAURI__ = { core: { invoke } } as unknown as typeof window.__TAURI__;
const hook = renderHook(() =>
useHomeProjectCreation({
setStatus: vi.fn(),
showTransientNotice: vi.fn(),
setLauncherView: vi.fn(),
setAgentChatProjectPath: vi.fn(),
rememberRecentWorkspace: vi.fn(),
}),
);
return { ...hook, calls, invoke };
}
it('awaits the real home preflight before naming or creating a game', async () => {
let ready!: (value: unknown) => void;
const pending = new Promise((resolve) => {
ready = resolve;
});
const { result, calls } = mount(() => pending);
let creation!: Promise<string>;
await act(async () => {
creation = result.current.createHomeDraftAutomatically(
{ creationType: 'game', prompt: '做一个小游戏', attachments: [] },
'direct-build',
);
});
expect(calls).toEqual(['preflight_web_game_creation']);
await act(async () => {
ready({ status: 'ready' });
await creation;
});
expect(calls.slice(0, 3)).toEqual([
'preflight_web_game_creation',
'suggest_automatic_project_name',
'create_automatic_local_game_project',
]);
expect(result.current.currentProjectContext?.creationType).toBe('game');
});
it('blocks naming, creation, and first generation with the host error code', async () => {
const { result, calls } = mount(async () => {
throw new Error(
'Web 游戏环境预检未通过:web-preflight-browser-failed;尚未启动生成',
);
});
let status = '';
await act(async () => {
status = await result.current.createHomeDraftAutomatically(
{ creationType: 'game', prompt: '做一个小游戏', attachments: [] },
'direct-build',
);
});
expect(status).toBe(
'Web 游戏环境预检未通过(web-preflight-browser-failed);尚未开始生成。',
);
expect(calls).toEqual(['preflight_web_game_creation']);
expect(result.current.currentProjectContext).toBeNull();
});
it('distinguishes an IPC failure from a host preflight failure', async () => {
const { result, calls } = mount(async () => {
throw new Error('Failed to fetch');
});
let status = '';
await act(async () => {
status = await result.current.createHomeDraftAutomatically(
{ creationType: 'game', prompt: '做一个小游戏', attachments: [] },
'direct-build',
);
});
expect(status).toBe(HOME_WEB_PREFLIGHT_IPC_FAILURE);
expect(calls).toEqual([
'preflight_web_game_creation',
'preflight_web_game_creation',
]);
expect(result.current.currentProjectContext).toBeNull();
});
it('keeps the legacy fallback for a blocked report without a code', async () => {
const { result, calls } = mount(async () => ({ status: 'blocked' }));
let status = '';
await act(async () => {
status = await result.current.createHomeDraftAutomatically(
{ creationType: 'game', prompt: '做一个小游戏', attachments: [] },
'direct-build',
);
});
expect(status).toBe(HOME_WEB_PREFLIGHT_FAILURE);
expect(calls).toEqual(['preflight_web_game_creation']);
expect(result.current.currentProjectContext).toBeNull();
});
it.each(['game', 'doc'] as const)(
'does not require the Web preflight for %s planning',
async (creationType) => {
const { result, calls } = mount(async () => {
throw new Error('must not run');
});
await act(async () => {
await result.current.createHomeDraftAutomatically(
{ creationType, prompt: '策划需求', attachments: [] },
'planning',
);
});
expect(calls).not.toContain('preflight_web_game_creation');
expect(calls).not.toContain('suggest_automatic_project_name');
expect(calls).toContain('create_automatic_local_game_project');
},
);