修正 AGC 测试按新的 Lexical 聊天输入区驱动与断言
- appSurface/harness 补齐三处 jsdom 缺口:ClipboardEvent、DragEvent、Range.prototype.getBoundingClientRect;否则 Lexical 的粘贴通路直接抛 ReferenceError / TypeError
- appSurface/harness 的 submitChat 改为 async:全选并让编辑器吸收选区、清空、走产品真实 paste 通路写入,再让出一帧让 React 追平 draft,最后点发送
- 新增 composerText / composerValue / composerDisabled / setComposerText 助手,按原生控件与 Lexical contenteditable 两种 DOM 口径读写输入区
- 15 个测试文件中 116 处 toHaveProperty('value', …) 断言等义改写为 await composerText() / await composerValue();1 处 placeholder 断言改查输入区占位文案;2 处 disabled 断言改用 composerDisabled(同时覆盖 data-disabled 与 contenteditable=false);9 处 fireEvent.change 写入改用 setComposerText
- 328 处 submitChat 调用补 await,9 个非 async 用例补 async
- Godot 输入区键盘语义用例按 Lexical 实际行为改写:Shift+Enter 与组合态 Enter 由编辑器消化并插入换行、不发送、草稿保留
- 未改动 src 下任何产品代码,未放宽或删除断言
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
import {
|
||||
composerText,
|
||||
composerValue,
|
||||
createGameCreationAppManifest,
|
||||
createGameCreationAppSeedTasks,
|
||||
emptyProjectPolicy,
|
||||
@@ -9,6 +11,7 @@ import {
|
||||
it,
|
||||
renderAppAt,
|
||||
screen,
|
||||
setComposerText,
|
||||
submitChat,
|
||||
vi,
|
||||
waitFor,
|
||||
@@ -167,14 +170,14 @@ export function registerAgentRuntimeCommandTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
).not.toBeNull();
|
||||
invoke.mockClear();
|
||||
|
||||
submitChat('/trace');
|
||||
await submitChat('/trace');
|
||||
|
||||
expect(await screen.findByText(/Run:run-chat-trace/)).not.toBeNull();
|
||||
expect(
|
||||
@@ -226,13 +229,13 @@ export function registerAgentRuntimeCommandTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
).not.toBeNull();
|
||||
|
||||
submitChat('/trace');
|
||||
await submitChat('/trace');
|
||||
|
||||
expect(
|
||||
await screen.findByText(
|
||||
@@ -312,14 +315,14 @@ export function registerAgentRuntimeCommandTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
).not.toBeNull();
|
||||
invoke.mockClear();
|
||||
|
||||
submitChat('/trace');
|
||||
await submitChat('/trace');
|
||||
|
||||
expect(
|
||||
await screen.findByText('准备读取 Agent run trace。'),
|
||||
@@ -460,33 +463,24 @@ export function registerAgentRuntimeCommandTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
).not.toBeNull();
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '输出' }));
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
'/read .agent/output.jsonl',
|
||||
);
|
||||
expect(await composerText()).toBe('/read .agent/output.jsonl');
|
||||
fireEvent.click(screen.getByRole('button', { name: '活动' }));
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
'/read .agent/activity.jsonl',
|
||||
);
|
||||
expect(await composerText()).toBe('/read .agent/activity.jsonl');
|
||||
fireEvent.click(screen.getByRole('button', { name: '上下文包' }));
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
'/read .agent/context.bundle.json',
|
||||
);
|
||||
expect(await composerText()).toBe('/read .agent/context.bundle.json');
|
||||
expect(invoke).not.toHaveBeenCalledWith(
|
||||
'read_local_project_file',
|
||||
expect.objectContaining({ relativePath: '.agent/context.bundle.json' }),
|
||||
);
|
||||
|
||||
submitChat('/agent-status');
|
||||
await submitChat('/agent-status');
|
||||
expect(
|
||||
await screen.findByText(
|
||||
/run run-control-chat 当前状态:pending \/ pending/,
|
||||
@@ -494,17 +488,12 @@ export function registerAgentRuntimeCommandTests() {
|
||||
).not.toBeNull();
|
||||
expect(screen.getByText(/run:run-control-chat/)).not.toBeNull();
|
||||
fireEvent.click(screen.getByRole('button', { name: '读取 Run 输出' }));
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
'/read .agent/output.jsonl',
|
||||
);
|
||||
expect(await composerText()).toBe('/read .agent/output.jsonl');
|
||||
expect(invoke).not.toHaveBeenCalledWith(
|
||||
'read_local_project_file',
|
||||
expect.objectContaining({ relativePath: '.agent/output.jsonl' }),
|
||||
);
|
||||
fireEvent.change(screen.getByLabelText('创作想法'), {
|
||||
target: { value: '' },
|
||||
});
|
||||
await setComposerText(screen.getByLabelText('创作想法'), '');
|
||||
expect(invoke).toHaveBeenCalledWith('control_agent_run', {
|
||||
projectPath: '/tmp/authorized-game',
|
||||
action: 'status',
|
||||
@@ -516,7 +505,7 @@ export function registerAgentRuntimeCommandTests() {
|
||||
commandId: 'agent.run_status',
|
||||
});
|
||||
|
||||
submitChat('/agent-kill');
|
||||
await submitChat('/agent-kill');
|
||||
expect(screen.getByText('agent.kill')).not.toBeNull();
|
||||
expect(
|
||||
screen.getByText(
|
||||
@@ -533,7 +522,7 @@ export function registerAgentRuntimeCommandTests() {
|
||||
detail: undefined,
|
||||
});
|
||||
|
||||
submitChat('/agent-retry');
|
||||
await submitChat('/agent-retry');
|
||||
expect(screen.getByText('agent.retry')).not.toBeNull();
|
||||
expect(
|
||||
screen.getByText(
|
||||
@@ -552,7 +541,7 @@ export function registerAgentRuntimeCommandTests() {
|
||||
detail: undefined,
|
||||
});
|
||||
|
||||
submitChat('/agent-resume 继续修复输入监听');
|
||||
await submitChat('/agent-resume 继续修复输入监听');
|
||||
expect(screen.getByText('agent.resume')).not.toBeNull();
|
||||
expect(
|
||||
screen.getByText(
|
||||
@@ -604,13 +593,13 @@ export function registerAgentRuntimeCommandTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
).not.toBeNull();
|
||||
|
||||
submitChat('/agent-status');
|
||||
await submitChat('/agent-status');
|
||||
|
||||
expect(
|
||||
await screen.findByText(
|
||||
@@ -654,13 +643,13 @@ export function registerAgentRuntimeCommandTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
).not.toBeNull();
|
||||
|
||||
submitChat('/agent-kill');
|
||||
await submitChat('/agent-kill');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
|
||||
expect(
|
||||
@@ -709,13 +698,13 @@ export function registerAgentRuntimeCommandTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
).not.toBeNull();
|
||||
|
||||
submitChat('/agent-kill');
|
||||
await submitChat('/agent-kill');
|
||||
expect(screen.getByText('agent.kill')).not.toBeNull();
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
|
||||
@@ -817,14 +806,14 @@ export function registerAgentRuntimeCommandTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
).not.toBeNull();
|
||||
invoke.mockClear();
|
||||
|
||||
submitChat('/agent-kill');
|
||||
await submitChat('/agent-kill');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
|
||||
expect(await screen.findByText('准备执行 Agent run 操作。')).not.toBeNull();
|
||||
@@ -927,14 +916,14 @@ export function registerAgentRuntimeCommandTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
).not.toBeNull();
|
||||
invoke.mockClear();
|
||||
|
||||
submitChat('/agent-status');
|
||||
await submitChat('/agent-status');
|
||||
|
||||
expect(await screen.findByText('准备查看 Agent run 状态。')).not.toBeNull();
|
||||
expect(screen.getByText('agent.run_status')).not.toBeNull();
|
||||
@@ -993,13 +982,13 @@ export function registerAgentRuntimeCommandTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
).not.toBeNull();
|
||||
|
||||
submitChat('/agent-status');
|
||||
await submitChat('/agent-status');
|
||||
|
||||
const agentStatusCommand = await screen.findByText('agent.run_status');
|
||||
fireEvent.click(
|
||||
@@ -1044,13 +1033,13 @@ export function registerAgentRuntimeCommandTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
).not.toBeNull();
|
||||
|
||||
submitChat('/agent-kill');
|
||||
await submitChat('/agent-kill');
|
||||
const agentCommand = screen.getByText('agent.kill');
|
||||
fireEvent.click(
|
||||
within(agentCommand.closest('.pending-command') as HTMLElement).getByRole(
|
||||
@@ -1150,14 +1139,14 @@ export function registerAgentRuntimeCommandTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
).not.toBeNull();
|
||||
invoke.mockClear();
|
||||
|
||||
submitChat('/agent-status');
|
||||
await submitChat('/agent-status');
|
||||
|
||||
expect(
|
||||
await screen.findByText(
|
||||
@@ -1264,7 +1253,7 @@ export function registerAgentRuntimeCommandTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
@@ -1314,7 +1303,7 @@ export function registerAgentRuntimeCommandTests() {
|
||||
});
|
||||
const composerInput = screen.getByLabelText('创作想法');
|
||||
fireEvent.click(screen.getByRole('button', { name: '继续说明' }));
|
||||
expect(composerInput).toHaveProperty('value', '/agent-resume ');
|
||||
expect(await composerValue(composerInput)).toBe('/agent-resume ');
|
||||
});
|
||||
|
||||
it('requires project policy confirmation before reading agent run status from the panel', async () => {
|
||||
@@ -1399,7 +1388,7 @@ export function registerAgentRuntimeCommandTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
@@ -1507,7 +1496,7 @@ export function registerAgentRuntimeCommandTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
@@ -1595,16 +1584,16 @@ export function registerAgentRuntimeCommandTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
).not.toBeNull();
|
||||
|
||||
submitChat('/memory');
|
||||
await submitChat('/memory');
|
||||
expect(await screen.findByText(/长期记忆:/)).not.toBeNull();
|
||||
|
||||
submitChat('/remember long 保留厨房主题');
|
||||
await submitChat('/remember long 保留厨房主题');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(await screen.findByText('已追加长期记忆。')).not.toBeNull();
|
||||
expect(invoke).toHaveBeenCalledWith('read_local_game_memory', {
|
||||
@@ -1617,7 +1606,7 @@ export function registerAgentRuntimeCommandTests() {
|
||||
content: '# 项目长期记忆\n- 保留厨房主题\n',
|
||||
});
|
||||
|
||||
submitChat('/memory-set long 覆盖后的长期记忆');
|
||||
await submitChat('/memory-set long 覆盖后的长期记忆');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(await screen.findByText('已保存长期记忆。')).not.toBeNull();
|
||||
expect(invoke).toHaveBeenCalledWith('write_local_game_memory', {
|
||||
@@ -1626,7 +1615,7 @@ export function registerAgentRuntimeCommandTests() {
|
||||
content: '覆盖后的长期记忆',
|
||||
});
|
||||
|
||||
submitChat('/forget-memory');
|
||||
await submitChat('/forget-memory');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(await screen.findByText('已删除长期记忆。')).not.toBeNull();
|
||||
expect(invoke).toHaveBeenCalledWith('delete_local_game_memory', {
|
||||
@@ -1676,14 +1665,14 @@ export function registerAgentRuntimeCommandTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
).not.toBeNull();
|
||||
invoke.mockClear();
|
||||
|
||||
submitChat('/memory');
|
||||
await submitChat('/memory');
|
||||
|
||||
expect(await screen.findByText('准备读取项目记忆。')).not.toBeNull();
|
||||
expect(screen.getByText('memory.read')).not.toBeNull();
|
||||
@@ -1737,14 +1726,14 @@ export function registerAgentRuntimeCommandTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
).not.toBeNull();
|
||||
invoke.mockClear();
|
||||
|
||||
submitChat('/memory');
|
||||
await submitChat('/memory');
|
||||
|
||||
expect(await screen.findByText('准备读取项目记忆。')).not.toBeNull();
|
||||
const memoryReadCommand = screen.getByText('memory.read');
|
||||
@@ -1822,16 +1811,16 @@ export function registerAgentRuntimeCommandTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(await screen.findByText('已打开:authorized-game')).not.toBeNull();
|
||||
|
||||
submitChat('/memory typo');
|
||||
await submitChat('/memory typo');
|
||||
expect(
|
||||
await screen.findByText('格式:/memory [short|long|blackboard]'),
|
||||
).not.toBeNull();
|
||||
|
||||
submitChat('/forget-memory typo');
|
||||
await submitChat('/forget-memory typo');
|
||||
expect(
|
||||
await screen.findByText('格式:/forget-memory [short|long|blackboard]'),
|
||||
).not.toBeNull();
|
||||
@@ -1901,16 +1890,16 @@ export function registerAgentRuntimeCommandTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
).not.toBeNull();
|
||||
|
||||
submitChat('/memory blackboard');
|
||||
await submitChat('/memory blackboard');
|
||||
expect(await screen.findByText(/黑板记忆:/)).not.toBeNull();
|
||||
|
||||
submitChat('/remember blackboard 共享美术约束');
|
||||
await submitChat('/remember blackboard 共享美术约束');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(await screen.findByText('已追加黑板记忆。')).not.toBeNull();
|
||||
expect(invoke).toHaveBeenCalledWith('write_local_game_memory', {
|
||||
@@ -1919,7 +1908,7 @@ export function registerAgentRuntimeCommandTests() {
|
||||
content: '# 项目黑板\n- 共享美术约束\n',
|
||||
});
|
||||
|
||||
submitChat('/memory-set 黑板 统一使用俯视角');
|
||||
await submitChat('/memory-set 黑板 统一使用俯视角');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(await screen.findByText('已保存黑板记忆。')).not.toBeNull();
|
||||
expect(invoke).toHaveBeenCalledWith('write_local_game_memory', {
|
||||
@@ -1928,7 +1917,7 @@ export function registerAgentRuntimeCommandTests() {
|
||||
content: '统一使用俯视角',
|
||||
});
|
||||
|
||||
submitChat('/forget-memory blackboard');
|
||||
await submitChat('/forget-memory blackboard');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(await screen.findByText('已删除黑板记忆。')).not.toBeNull();
|
||||
expect(invoke).toHaveBeenCalledWith('delete_local_game_memory', {
|
||||
|
||||
@@ -4931,10 +4931,10 @@ export function registerDeveloperToolsTests() {
|
||||
expect(invoke).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('lists standard agent capabilities from chat without opening dev panels', () => {
|
||||
it('lists standard agent capabilities from chat without opening dev panels', async () => {
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/capabilities');
|
||||
await submitChat('/capabilities');
|
||||
|
||||
const capabilities = screen.getByText(/Agent 能力清单:/);
|
||||
expect(capabilities.textContent).toMatch(/任务拆分/);
|
||||
@@ -4966,7 +4966,7 @@ export function registerDeveloperToolsTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/capabilities');
|
||||
await submitChat('/capabilities');
|
||||
|
||||
expect(await screen.findByText(/Native Runtime 能力/)).not.toBeNull();
|
||||
expect(screen.queryByText(/任务拆分/)).toBeNull();
|
||||
@@ -4983,17 +4983,17 @@ export function registerDeveloperToolsTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/capabilities');
|
||||
await submitChat('/capabilities');
|
||||
|
||||
expect(await screen.findByText(/任务拆分/)).not.toBeNull();
|
||||
expect(screen.getByText(/本地 HTTP 预览/)).not.toBeNull();
|
||||
expect(invoke).toHaveBeenCalledWith('get_game_creation_agent_capabilities');
|
||||
});
|
||||
|
||||
it('exposes the audit command from chat help', () => {
|
||||
it('exposes the audit command from chat help', async () => {
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/help');
|
||||
await submitChat('/help');
|
||||
|
||||
expect(
|
||||
screen.getByText(/\/audit:审计当前项目的 Agent 能力证据/),
|
||||
@@ -5472,11 +5472,11 @@ export function registerDeveloperToolsTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(await screen.findByText('已打开:authorized-game')).not.toBeNull();
|
||||
|
||||
submitChat('/audit');
|
||||
await submitChat('/audit');
|
||||
|
||||
expect(await screen.findByText(/Agent v1 审计:/)).not.toBeNull();
|
||||
expect(screen.getByText(/能力\/命令契约:通过/)).not.toBeNull();
|
||||
@@ -5598,12 +5598,12 @@ export function registerDeveloperToolsTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(await screen.findByText('已打开:authorized-game')).not.toBeNull();
|
||||
invoke.mockClear();
|
||||
|
||||
submitChat('/audit');
|
||||
await submitChat('/audit');
|
||||
|
||||
expect(
|
||||
await screen.findByText('准备确认审计读取:agent.trace_read'),
|
||||
@@ -5679,12 +5679,12 @@ export function registerDeveloperToolsTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(await screen.findByText('已打开:authorized-game')).not.toBeNull();
|
||||
invoke.mockClear();
|
||||
|
||||
submitChat('/audit');
|
||||
await submitChat('/audit');
|
||||
|
||||
expect(
|
||||
await screen.findByText('准备确认审计读取:file.read'),
|
||||
@@ -5791,12 +5791,12 @@ export function registerDeveloperToolsTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(await screen.findByText('已打开:authorized-game')).not.toBeNull();
|
||||
invoke.mockClear();
|
||||
|
||||
submitChat('/audit');
|
||||
await submitChat('/audit');
|
||||
|
||||
expect(
|
||||
await screen.findByText('准备确认审计读取:file.read'),
|
||||
@@ -5887,11 +5887,11 @@ export function registerDeveloperToolsTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(await screen.findByText('已打开:authorized-game')).not.toBeNull();
|
||||
|
||||
submitChat('/audit');
|
||||
await submitChat('/audit');
|
||||
|
||||
expect(await screen.findByText(/权限 Gate\/命令日志:待补/)).not.toBeNull();
|
||||
expect(
|
||||
@@ -5947,11 +5947,11 @@ export function registerDeveloperToolsTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(await screen.findByText('已打开:authorized-game')).not.toBeNull();
|
||||
|
||||
submitChat('/audit');
|
||||
await submitChat('/audit');
|
||||
|
||||
expect(await screen.findByText(/权限 Gate\/命令日志:通过/)).not.toBeNull();
|
||||
expect(screen.getByText(/含 auto 权限记录/)).not.toBeNull();
|
||||
@@ -5996,11 +5996,11 @@ export function registerDeveloperToolsTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(await screen.findByText('已打开:authorized-game')).not.toBeNull();
|
||||
|
||||
submitChat('/audit');
|
||||
await submitChat('/audit');
|
||||
|
||||
expect(await screen.findByText(/6 组任务配置:通过/)).not.toBeNull();
|
||||
expect(screen.getByText(/6 组协作证据:待生成/)).not.toBeNull();
|
||||
|
||||
@@ -35,6 +35,15 @@ const originalPointerEvent = Object.getOwnPropertyDescriptor(
|
||||
window,
|
||||
'PointerEvent',
|
||||
);
|
||||
const originalClipboardEvent = Object.getOwnPropertyDescriptor(
|
||||
window,
|
||||
'ClipboardEvent',
|
||||
);
|
||||
const originalDragEvent = Object.getOwnPropertyDescriptor(window, 'DragEvent');
|
||||
const originalRangeGetBoundingClientRect = Object.getOwnPropertyDescriptor(
|
||||
Range.prototype,
|
||||
'getBoundingClientRect',
|
||||
);
|
||||
const originalIntersectionObserver = Object.getOwnPropertyDescriptor(
|
||||
window,
|
||||
'IntersectionObserver',
|
||||
@@ -56,6 +65,29 @@ class TestPointerEvent extends MouseEvent {
|
||||
}
|
||||
}
|
||||
|
||||
// jsdom 没有实现 DragEvent / ClipboardEvent,而 Lexical 在粘贴与拖放处理里用
|
||||
// `instanceof DragEvent` / `instanceof ClipboardEvent` 判定事件来源,缺失会直接抛
|
||||
// ReferenceError,粘贴通路根本进不去编辑器。这里只补最小的构造器,让事件能带上
|
||||
// `clipboardData` 并被 Lexical 认出来,不模拟真实浏览器语义。
|
||||
class TestClipboardEvent extends Event {}
|
||||
|
||||
class TestDragEvent extends MouseEvent {}
|
||||
|
||||
// jsdom 的 Range 也没有 getBoundingClientRect,Lexical 计算选区矩形时会抛 TypeError。
|
||||
function emptyRangeRect(): DOMRect {
|
||||
return {
|
||||
x: 0,
|
||||
y: 0,
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
width: 0,
|
||||
height: 0,
|
||||
toJSON: () => ({}),
|
||||
} as DOMRect;
|
||||
}
|
||||
|
||||
function createMemoryStorage(): Storage {
|
||||
const values = new Map<string, string>();
|
||||
return {
|
||||
@@ -192,10 +224,111 @@ function pickProjectFromLauncher(
|
||||
fireEvent.click(screen.getByRole('button', { name: action }));
|
||||
}
|
||||
|
||||
function submitChat(value: string) {
|
||||
fireEvent.change(screen.getByLabelText('创作想法'), {
|
||||
target: { value },
|
||||
function isNativeTextControl(
|
||||
element: HTMLElement,
|
||||
): element is HTMLInputElement | HTMLTextAreaElement {
|
||||
return element.tagName === 'INPUT' || element.tagName === 'TEXTAREA';
|
||||
}
|
||||
|
||||
// Lexical 的编辑器状态提交排在微任务里(外部 value 变化、粘贴、删除都走这条路径),
|
||||
// 读取或提交前先让 React 追平编辑器内容,否则会读到上一帧的文本/禁用状态。
|
||||
// 这里让出一个宏任务而不是用 act(async),因为 act 在编辑器持续自更新的用例里会长时间不收敛。
|
||||
async function settleComposer() {
|
||||
await new Promise((resolve) => {
|
||||
setTimeout(resolve, 0);
|
||||
});
|
||||
}
|
||||
|
||||
// 读取输入区文本:原生 input/textarea 读 value,Lexical contenteditable 读 textContent。
|
||||
async function composerValue(element: HTMLElement) {
|
||||
await settleComposer();
|
||||
return isNativeTextControl(element)
|
||||
? element.value
|
||||
: (element.textContent ?? '');
|
||||
}
|
||||
|
||||
type ComposerScope = { getByLabelText: (label: string) => HTMLElement };
|
||||
|
||||
async function composerText(label = '创作想法', scope: ComposerScope = screen) {
|
||||
return composerValue(scope.getByLabelText(label));
|
||||
}
|
||||
|
||||
async function composerDisabled(
|
||||
label = '创作想法',
|
||||
scope: ComposerScope = screen,
|
||||
) {
|
||||
await settleComposer();
|
||||
const element = scope.getByLabelText(label);
|
||||
if (isNativeTextControl(element)) {
|
||||
return element.disabled;
|
||||
}
|
||||
const wrapper = element.closest('.resource-reference-input');
|
||||
return (
|
||||
wrapper?.getAttribute('data-disabled') === 'true' ||
|
||||
element.getAttribute('contenteditable') !== 'true'
|
||||
);
|
||||
}
|
||||
|
||||
// 把整段内容选进 DOM 选区,并让 Lexical 吸收它:jsdom 不会为程序化选区派发
|
||||
// selectionchange,编辑器内部 selection 不更新的话,粘贴会插在旧内容旁边而不是覆盖。
|
||||
function selectComposerContents(element: HTMLElement) {
|
||||
element.focus();
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(element);
|
||||
const selection = window.getSelection();
|
||||
selection?.removeAllRanges();
|
||||
selection?.addRange(range);
|
||||
document.dispatchEvent(new Event('selectionchange'));
|
||||
}
|
||||
|
||||
function clearComposerContents(element: HTMLElement) {
|
||||
fireEvent.keyDown(element, { key: 'Delete', code: 'Delete' });
|
||||
}
|
||||
|
||||
// 写完内容后把光标收回到末尾,模拟真实输入后的选区;否则残留的“全选”会改变
|
||||
// Shift+Enter 等按键的后续语义。
|
||||
function collapseComposerSelectionToEnd(element: HTMLElement) {
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(element);
|
||||
range.collapse(false);
|
||||
const selection = window.getSelection();
|
||||
selection?.removeAllRanges();
|
||||
selection?.addRange(range);
|
||||
document.dispatchEvent(new Event('selectionchange'));
|
||||
}
|
||||
|
||||
function pasteComposerText(element: HTMLElement, value: string) {
|
||||
fireEvent.paste(element, {
|
||||
clipboardData: {
|
||||
getData: (type: string) => (type === 'text/plain' ? value : ''),
|
||||
files: [],
|
||||
items: [],
|
||||
types: ['text/plain'],
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// 向输入区写入文本,保证写入结果等于 value。原生控件用 change 事件;Lexical
|
||||
// contenteditable 先全选、清空,再走产品真实的 paste 通路写入。
|
||||
async function setComposerText(element: HTMLElement, value: string) {
|
||||
if (isNativeTextControl(element)) {
|
||||
fireEvent.change(element, { target: { value } });
|
||||
return;
|
||||
}
|
||||
selectComposerContents(element);
|
||||
await settleComposer();
|
||||
clearComposerContents(element);
|
||||
await settleComposer();
|
||||
if (value.length > 0) {
|
||||
pasteComposerText(element, value);
|
||||
await settleComposer();
|
||||
}
|
||||
collapseComposerSelectionToEnd(element);
|
||||
await settleComposer();
|
||||
}
|
||||
|
||||
async function submitChat(value: string) {
|
||||
await setComposerText(screen.getByLabelText('创作想法'), value);
|
||||
fireEvent.click(screen.getByRole('button', { name: '发送' }));
|
||||
}
|
||||
|
||||
@@ -1036,7 +1169,7 @@ function createProjectSupervisorRuntimeHarness({
|
||||
}
|
||||
|
||||
async function openMainProject(projectPath: string) {
|
||||
submitChat(`/project ${projectPath}`);
|
||||
await submitChat(`/project ${projectPath}`);
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText(`已打开:${projectNameFromPath(projectPath)}`),
|
||||
@@ -1057,6 +1190,18 @@ beforeEach(() => {
|
||||
configurable: true,
|
||||
value: TestPointerEvent,
|
||||
});
|
||||
Object.defineProperty(window, 'ClipboardEvent', {
|
||||
configurable: true,
|
||||
value: TestClipboardEvent,
|
||||
});
|
||||
Object.defineProperty(window, 'DragEvent', {
|
||||
configurable: true,
|
||||
value: TestDragEvent,
|
||||
});
|
||||
Object.defineProperty(Range.prototype, 'getBoundingClientRect', {
|
||||
configurable: true,
|
||||
value: emptyRangeRect,
|
||||
});
|
||||
Object.defineProperties(URL, {
|
||||
createObjectURL: {
|
||||
configurable: true,
|
||||
@@ -1097,6 +1242,25 @@ afterEach(() => {
|
||||
} else {
|
||||
Reflect.deleteProperty(window, 'PointerEvent');
|
||||
}
|
||||
if (originalClipboardEvent) {
|
||||
Object.defineProperty(window, 'ClipboardEvent', originalClipboardEvent);
|
||||
} else {
|
||||
Reflect.deleteProperty(window, 'ClipboardEvent');
|
||||
}
|
||||
if (originalDragEvent) {
|
||||
Object.defineProperty(window, 'DragEvent', originalDragEvent);
|
||||
} else {
|
||||
Reflect.deleteProperty(window, 'DragEvent');
|
||||
}
|
||||
if (originalRangeGetBoundingClientRect) {
|
||||
Object.defineProperty(
|
||||
Range.prototype,
|
||||
'getBoundingClientRect',
|
||||
originalRangeGetBoundingClientRect,
|
||||
);
|
||||
} else {
|
||||
Reflect.deleteProperty(Range.prototype, 'getBoundingClientRect');
|
||||
}
|
||||
if (originalIntersectionObserver) {
|
||||
Object.defineProperty(
|
||||
window,
|
||||
@@ -1118,6 +1282,9 @@ export {
|
||||
App,
|
||||
AuthenticatedClient,
|
||||
cleanup,
|
||||
composerDisabled,
|
||||
composerText,
|
||||
composerValue,
|
||||
createGameCreationAppManifest,
|
||||
createGameCreationAppSeedTasks,
|
||||
createPlanGddStateView,
|
||||
@@ -1149,6 +1316,7 @@ export {
|
||||
roleAgentMockReply,
|
||||
screen,
|
||||
selectDeveloperAgentChatMode,
|
||||
setComposerText,
|
||||
submitChat,
|
||||
TEST_LOCAL_PROJECT_PATH,
|
||||
testAuthUser,
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
renderLauncherProjectsAt,
|
||||
screen,
|
||||
selectDeveloperAgentChatMode,
|
||||
setComposerText,
|
||||
testAuthUser,
|
||||
vi,
|
||||
waitFor,
|
||||
@@ -1657,7 +1658,7 @@ export function registerHomeProjectCreationTests() {
|
||||
|
||||
expect(await screen.findByText('附件已经进入当前项目。')).not.toBeNull();
|
||||
const followUpInput = screen.getByLabelText('陶泥儿对话内容');
|
||||
fireEvent.change(followUpInput, { target: { value: '再补一句玩法' } });
|
||||
await setComposerText(followUpInput, '再补一句玩法');
|
||||
fireEvent.submit(followUpInput.closest('form') as HTMLFormElement);
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
composerText,
|
||||
createGameCreationAppManifest,
|
||||
emptyProjectPolicy,
|
||||
expect,
|
||||
@@ -64,7 +65,7 @@ export function registerProjectAssetTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
@@ -92,15 +93,12 @@ export function registerProjectAssetTests() {
|
||||
bytes: [104, 101, 114, 111],
|
||||
});
|
||||
|
||||
submitChat('/assets');
|
||||
await submitChat('/assets');
|
||||
expect(
|
||||
await screen.findByText(/upload · assets\/uploads\/hero\.png · uploaded/),
|
||||
).not.toBeNull();
|
||||
fireEvent.click(screen.getByRole('button', { name: '读取首个资产' }));
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
'/read assets/uploads/hero.png',
|
||||
);
|
||||
expect(await composerText()).toBe('/read assets/uploads/hero.png');
|
||||
expect(invoke).toHaveBeenCalledWith('get_local_game_manifest', {
|
||||
projectPath: '/tmp/authorized-game',
|
||||
commandId: 'asset.list',
|
||||
@@ -178,14 +176,14 @@ export function registerProjectAssetTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
).not.toBeNull();
|
||||
invoke.mockClear();
|
||||
|
||||
submitChat('/audio');
|
||||
await submitChat('/audio');
|
||||
|
||||
expect(await screen.findByText(/音频素材:3 个/)).not.toBeNull();
|
||||
expect(screen.getByText(/来源:上传 1、生成 1、画板 1/)).not.toBeNull();
|
||||
@@ -208,10 +206,7 @@ export function registerProjectAssetTests() {
|
||||
fireEvent.click(
|
||||
audioManifestDraftButtons[audioManifestDraftButtons.length - 1],
|
||||
);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
'/read assets/manifest.audio.json',
|
||||
);
|
||||
expect(await composerText()).toBe('/read assets/manifest.audio.json');
|
||||
expect(invoke).not.toHaveBeenCalledWith(
|
||||
'read_local_project_file',
|
||||
expect.anything(),
|
||||
@@ -298,14 +293,14 @@ export function registerProjectAssetTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
).not.toBeNull();
|
||||
invoke.mockClear();
|
||||
|
||||
submitChat('/art');
|
||||
await submitChat('/art');
|
||||
|
||||
expect(await screen.findByText(/美术素材:2 个/)).not.toBeNull();
|
||||
expect(screen.getByText(/来源:生成 1、画板 1/)).not.toBeNull();
|
||||
@@ -324,10 +319,7 @@ export function registerProjectAssetTests() {
|
||||
fireEvent.click(
|
||||
artManifestDraftButtons[artManifestDraftButtons.length - 1],
|
||||
);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
'/read assets/manifest.art.json',
|
||||
);
|
||||
expect(await composerText()).toBe('/read assets/manifest.art.json');
|
||||
expect(invoke).not.toHaveBeenCalledWith(
|
||||
'read_local_project_file',
|
||||
expect.anything(),
|
||||
@@ -397,14 +389,14 @@ export function registerProjectAssetTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
).not.toBeNull();
|
||||
invoke.mockClear();
|
||||
|
||||
submitChat('/asset-register assets/hero.png sprite image/png');
|
||||
await submitChat('/asset-register assets/hero.png sprite image/png');
|
||||
|
||||
expect(
|
||||
await screen.findByText('asset.register · assets/hero.png'),
|
||||
@@ -474,13 +466,13 @@ export function registerProjectAssetTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
).not.toBeNull();
|
||||
|
||||
submitChat('/asset-register assets/hero.png');
|
||||
await submitChat('/asset-register assets/hero.png');
|
||||
const command = await screen.findByText('asset.register · assets/hero.png');
|
||||
fireEvent.click(
|
||||
within(command.closest('.pending-command') as HTMLElement).getByRole(
|
||||
@@ -548,14 +540,14 @@ export function registerProjectAssetTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
).not.toBeNull();
|
||||
invoke.mockClear();
|
||||
|
||||
submitChat('/asset-register assets/hero.png sprite image/png');
|
||||
await submitChat('/asset-register assets/hero.png sprite image/png');
|
||||
|
||||
expect(
|
||||
await screen.findByText('准备登记项目资产:assets/hero.png'),
|
||||
@@ -618,13 +610,13 @@ export function registerProjectAssetTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
).not.toBeNull();
|
||||
|
||||
submitChat('/asset-register ../hero.png');
|
||||
await submitChat('/asset-register ../hero.png');
|
||||
|
||||
expect(
|
||||
await screen.findByText('资产路径必须是项目内相对路径。'),
|
||||
@@ -805,13 +797,13 @@ export function registerProjectAssetTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
).not.toBeNull();
|
||||
|
||||
submitChat('/assets');
|
||||
await submitChat('/assets');
|
||||
|
||||
expect(await screen.findByText(/本地项目资产:/)).not.toBeNull();
|
||||
expect(screen.getByText(/asset-20\.png/)).not.toBeNull();
|
||||
@@ -855,13 +847,13 @@ export function registerProjectAssetTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
).not.toBeNull();
|
||||
|
||||
submitChat('/assets');
|
||||
await submitChat('/assets');
|
||||
|
||||
const assetCommand = await screen.findByText('asset.list');
|
||||
fireEvent.click(
|
||||
@@ -914,13 +906,13 @@ export function registerProjectAssetTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
).not.toBeNull();
|
||||
|
||||
submitChat('/read game/index.html');
|
||||
await submitChat('/read game/index.html');
|
||||
|
||||
expect(await screen.findByText(/文件:game\/index\.html/)).not.toBeNull();
|
||||
const fileContent = screen.getByText('<canvas id="game"></canvas>');
|
||||
@@ -975,14 +967,14 @@ export function registerProjectAssetTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
).not.toBeNull();
|
||||
invoke.mockClear();
|
||||
|
||||
submitChat('/read game/index.html');
|
||||
await submitChat('/read game/index.html');
|
||||
|
||||
expect(await screen.findByText('准备读取项目文件。')).not.toBeNull();
|
||||
expect(screen.getByText('file.read')).not.toBeNull();
|
||||
@@ -1041,16 +1033,16 @@ export function registerProjectAssetTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
).not.toBeNull();
|
||||
|
||||
submitChat('/read ../secret.txt');
|
||||
await submitChat('/read ../secret.txt');
|
||||
expect(screen.getByText('文件路径必须是项目内相对路径。')).not.toBeNull();
|
||||
|
||||
submitChat('/read /tmp/secret.txt');
|
||||
await submitChat('/read /tmp/secret.txt');
|
||||
expect(screen.getAllByText('文件路径必须是项目内相对路径。').length).toBe(
|
||||
2,
|
||||
);
|
||||
@@ -1104,13 +1096,13 @@ export function registerProjectAssetTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
).not.toBeNull();
|
||||
|
||||
submitChat('/tasks');
|
||||
await submitChat('/tasks');
|
||||
|
||||
expect(await screen.findByText(/任务拆分:/)).not.toBeNull();
|
||||
expect(
|
||||
@@ -1193,11 +1185,11 @@ export function registerCanvasAssetTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(await screen.findByText('已打开:authorized-game')).not.toBeNull();
|
||||
|
||||
submitChat(
|
||||
await submitChat(
|
||||
'/import-canvas-asset assets/hero.png canvas-project-1 object:asset-object-1 character image/png',
|
||||
);
|
||||
expect(
|
||||
@@ -1647,8 +1639,7 @@ export function registerCanvasAssetTests() {
|
||||
expect(
|
||||
await screen.findByText('已选择画板导出包:/tmp/canvas-export.zip'),
|
||||
).not.toBeNull();
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
expect(await composerText()).toBe(
|
||||
'/import-canvas-export /tmp/canvas-export.zip ',
|
||||
);
|
||||
expect(invoke).toHaveBeenCalledWith('pick_local_file');
|
||||
@@ -1716,24 +1707,26 @@ export function registerCanvasAssetTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(await screen.findByText('已打开:authorized-game')).not.toBeNull();
|
||||
expect(await screen.findByText(/还没有最近一次 Agent run/)).not.toBeNull();
|
||||
|
||||
submitChat(
|
||||
await submitChat(
|
||||
'/import-canvas-asset /tmp/hero.png canvas-project-1 resource-1',
|
||||
);
|
||||
expect(
|
||||
screen.getByText('画板资产路径必须是项目内相对路径。'),
|
||||
).not.toBeNull();
|
||||
|
||||
submitChat('/import-canvas-asset ../hero.png canvas-project-1 resource-1');
|
||||
await submitChat(
|
||||
'/import-canvas-asset ../hero.png canvas-project-1 resource-1',
|
||||
);
|
||||
expect(
|
||||
screen.getAllByText('画板资产路径必须是项目内相对路径。').length,
|
||||
).toBe(2);
|
||||
|
||||
submitChat('/import-canvas-export relative.zip canvas-project-1');
|
||||
await submitChat('/import-canvas-export relative.zip canvas-project-1');
|
||||
expect(
|
||||
screen.getByText('画板导出 ZIP 路径必须是绝对路径。'),
|
||||
).not.toBeNull();
|
||||
@@ -1818,16 +1811,18 @@ export function registerCanvasAssetTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(await screen.findByText('已打开:authorized-game')).not.toBeNull();
|
||||
|
||||
submitChat('/canvas bad\u0007canvas');
|
||||
submitChat('/sync-canvas-project bad\u0007canvas');
|
||||
submitChat(
|
||||
await submitChat('/canvas bad\u0007canvas');
|
||||
await submitChat('/sync-canvas-project bad\u0007canvas');
|
||||
await submitChat(
|
||||
'/import-canvas-asset assets/hero.png bad\u0007canvas resource-1',
|
||||
);
|
||||
submitChat('/import-canvas-export /tmp/canvas-export.zip bad\u0007canvas');
|
||||
await submitChat(
|
||||
'/import-canvas-export /tmp/canvas-export.zip bad\u0007canvas',
|
||||
);
|
||||
|
||||
expect(screen.getAllByText('画板项目 ID 不能包含控制字符。').length).toBe(
|
||||
4,
|
||||
@@ -1886,7 +1881,7 @@ export function registerCanvasAssetTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/canvas canvas-project-1');
|
||||
await submitChat('/canvas canvas-project-1');
|
||||
|
||||
expect(
|
||||
await screen.findByText('准备打开画板项目:canvas-project-1'),
|
||||
@@ -1918,10 +1913,7 @@ export function registerCanvasAssetTests() {
|
||||
),
|
||||
).not.toBeNull();
|
||||
fireEvent.click(screen.getByRole('button', { name: '同步此画板' }));
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
'/sync-canvas-project canvas-project-1',
|
||||
);
|
||||
expect(await composerText()).toBe('/sync-canvas-project canvas-project-1');
|
||||
});
|
||||
|
||||
it('syncs canvas project assets from chat after project confirmation', async () => {
|
||||
@@ -1998,11 +1990,11 @@ export function registerCanvasAssetTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(await screen.findByText('已打开:authorized-game')).not.toBeNull();
|
||||
|
||||
submitChat('/sync-canvas-project canvas-project-1');
|
||||
await submitChat('/sync-canvas-project canvas-project-1');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
|
||||
expect(
|
||||
@@ -2083,11 +2075,11 @@ export function registerCanvasAssetTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(await screen.findByText('已打开:authorized-game')).not.toBeNull();
|
||||
|
||||
submitChat('/generate-art 月光厨房弹幕主角');
|
||||
await submitChat('/generate-art 月光厨房弹幕主角');
|
||||
expect(await screen.findByText('准备生成首版美术素材。')).not.toBeNull();
|
||||
expect(screen.getByText('canvas.asset_generate')).not.toBeNull();
|
||||
expect(
|
||||
@@ -2151,14 +2143,14 @@ export function registerCanvasAssetTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
).not.toBeNull();
|
||||
invoke.mockClear();
|
||||
|
||||
submitChat('/generate-art 月光厨房弹幕主角');
|
||||
await submitChat('/generate-art 月光厨房弹幕主角');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
|
||||
expect(await screen.findByText('准备生成首版美术素材。')).not.toBeNull();
|
||||
@@ -2219,13 +2211,15 @@ export function registerCanvasAssetTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
).not.toBeNull();
|
||||
|
||||
submitChat('/import-canvas-export /tmp/canvas-export.zip canvas-project-1');
|
||||
await submitChat(
|
||||
'/import-canvas-export /tmp/canvas-export.zip canvas-project-1',
|
||||
);
|
||||
expect(
|
||||
await screen.findByText(
|
||||
/导入 \/tmp\/canvas-export\.zip 到 \/tmp\/authorized-game\/assets\/canvas-imports\/ · 画板 canvas-project-1/,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,7 @@ import { isDirectCodexTurnAlreadyRunningError } from '../../src/App';
|
||||
import {
|
||||
act,
|
||||
agentRuntimeUserInputRequest,
|
||||
composerText,
|
||||
createGameCreationAppManifest,
|
||||
createGameCreationAppSeedTasks,
|
||||
createProjectSupervisorRuntimeHarness,
|
||||
@@ -290,7 +291,7 @@ export function registerProjectConversationTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
|
||||
expect(await screen.findByText('历史需求:保留弹幕厨房')).not.toBeNull();
|
||||
@@ -368,19 +369,19 @@ export function registerProjectConversationTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(await screen.findByText('重载历史需求')).not.toBeNull();
|
||||
|
||||
submitChat('临时未保存的输入');
|
||||
await submitChat('临时未保存的输入');
|
||||
expect(await screen.findByText('临时未保存的输入')).not.toBeNull();
|
||||
submitChat('/history');
|
||||
await submitChat('/history');
|
||||
|
||||
expect(await screen.findByText('重载历史回复')).not.toBeNull();
|
||||
expect(screen.queryByText('临时未保存的输入')).toBeNull();
|
||||
expect(screen.getByText('已读取项目对话历史:2 条')).not.toBeNull();
|
||||
|
||||
submitChat('另一条临时未保存的输入');
|
||||
await submitChat('另一条临时未保存的输入');
|
||||
expect(await screen.findByText('另一条临时未保存的输入')).not.toBeNull();
|
||||
fireEvent.click(screen.getByRole('button', { name: '历史' }));
|
||||
|
||||
@@ -433,7 +434,7 @@ export function registerProjectConversationTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
|
||||
expect(await screen.findByText('已打开:authorized-game')).not.toBeNull();
|
||||
@@ -777,7 +778,7 @@ export function registerProjectConversationTests() {
|
||||
renderAppAt('/?main&projectPath=%2Ftmp%2Fauthorized-game');
|
||||
|
||||
await screen.findByText('想做什么游戏?');
|
||||
submitChat('/第一条本地命令');
|
||||
await submitChat('/第一条本地命令');
|
||||
await waitFor(() => {
|
||||
expect(appendAttempts).toBe(1);
|
||||
});
|
||||
@@ -787,7 +788,7 @@ export function registerProjectConversationTests() {
|
||||
),
|
||||
).not.toBeNull();
|
||||
|
||||
submitChat('/第二条本地命令');
|
||||
await submitChat('/第二条本地命令');
|
||||
await waitFor(() => {
|
||||
expect(releaseRetryAppend).not.toBeNull();
|
||||
});
|
||||
@@ -873,7 +874,7 @@ export function registerProjectConversationTests() {
|
||||
|
||||
await screen.findByText('想做什么游戏?');
|
||||
invoke.mockClear();
|
||||
submitChat('/需要确认保存');
|
||||
await submitChat('/需要确认保存');
|
||||
|
||||
const conversationWriteCommand =
|
||||
await screen.findByText('conversation.write');
|
||||
@@ -961,7 +962,7 @@ export function registerProjectConversationTests() {
|
||||
|
||||
await screen.findByText('想做什么游戏?');
|
||||
invoke.mockClear();
|
||||
submitChat('/先不保存');
|
||||
await submitChat('/先不保存');
|
||||
|
||||
const firstPrompt = await screen.findByText('conversation.write');
|
||||
fireEvent.click(
|
||||
@@ -980,7 +981,7 @@ export function registerProjectConversationTests() {
|
||||
expect.anything(),
|
||||
);
|
||||
|
||||
submitChat('/继续补充');
|
||||
await submitChat('/继续补充');
|
||||
|
||||
const secondPrompt = await screen.findByText('conversation.write');
|
||||
fireEvent.click(
|
||||
@@ -1064,11 +1065,11 @@ export function registerProjectConversationTests() {
|
||||
renderAppAt('/?main&projectPath=%2Ftmp%2Fauthorized-game');
|
||||
|
||||
await screen.findByText('想做什么游戏?');
|
||||
submitChat('/第一条并发命令');
|
||||
await submitChat('/第一条并发命令');
|
||||
await waitFor(() => {
|
||||
expect(releaseFirstAppend).not.toBeNull();
|
||||
});
|
||||
submitChat('/第二条并发命令');
|
||||
await submitChat('/第二条并发命令');
|
||||
|
||||
releaseFirstAppend?.();
|
||||
|
||||
@@ -1249,7 +1250,7 @@ export function registerProjectConversationTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(await screen.findByText('已打开:authorized-game')).not.toBeNull();
|
||||
|
||||
@@ -1368,10 +1369,7 @@ export function registerProjectConversationTests() {
|
||||
expect(agentConversationReadCount).toBeGreaterThanOrEqual(2);
|
||||
fireEvent.click(screen.getByRole('button', { name: '填入同步命令' }));
|
||||
expect(screen.queryByLabelText('Agent 对话')).toBeNull();
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
'/sync-canvas-project ',
|
||||
);
|
||||
expect(await composerText()).toBe('/sync-canvas-project ');
|
||||
fireEvent.click(screen.getByRole('button', { name: /拆解创作方向/ }));
|
||||
const reopenedAgentDialog = await screen.findByLabelText('Agent 对话');
|
||||
fireEvent.click(
|
||||
@@ -1380,10 +1378,7 @@ export function registerProjectConversationTests() {
|
||||
}),
|
||||
);
|
||||
expect(screen.queryByLabelText('Agent 对话')).toBeNull();
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
'/read .agent/spec.md',
|
||||
);
|
||||
expect(await composerText()).toBe('/read .agent/spec.md');
|
||||
expect(invoke).not.toHaveBeenCalledWith(
|
||||
'sync_canvas_project_assets',
|
||||
expect.anything(),
|
||||
|
||||
@@ -17,6 +17,9 @@ import {
|
||||
agentRuntimeUserInputRequest,
|
||||
App,
|
||||
cleanup,
|
||||
composerDisabled,
|
||||
composerText,
|
||||
composerValue,
|
||||
createGameCreationAppManifest,
|
||||
createGameCreationAppSeedTasks,
|
||||
createProjectSupervisorRuntimeHarness,
|
||||
@@ -40,6 +43,7 @@ import {
|
||||
renderLauncherProjectsAt,
|
||||
resolve,
|
||||
screen,
|
||||
setComposerText,
|
||||
submitChat,
|
||||
vi,
|
||||
waitFor,
|
||||
@@ -4854,10 +4858,9 @@ export function registerUserSurfaceBoundaryTests() {
|
||||
).disabled,
|
||||
).toBe(true);
|
||||
fireEvent.click(screen.getByRole('button', { name: '打开画板' }));
|
||||
expect(composerInput).toHaveProperty('value', '/canvas ');
|
||||
expect(await composerValue(composerInput)).toBe('/canvas ');
|
||||
fireEvent.click(screen.getByRole('button', { name: '灵感草稿' }));
|
||||
expect(composerInput).toHaveProperty(
|
||||
'value',
|
||||
expect(await composerValue(composerInput)).toBe(
|
||||
'像素风厨房弹幕小游戏:玩家用方向键躲避飞来的食材,收集调料加分,60 秒内尽量高分,失败后可一键重开。',
|
||||
);
|
||||
expect(screen.queryByText('game.generate_draft')).toBeNull();
|
||||
@@ -5080,8 +5083,8 @@ export function registerProjectSupervisorSurfaceTests() {
|
||||
within(supervisorSurface).queryByLabelText('项目总控 Agent 状态'),
|
||||
).toBeNull();
|
||||
expect(
|
||||
within(supervisorSurface).getByPlaceholderText(
|
||||
'告诉陶泥儿接下来要做什么',
|
||||
within(supervisorSurface).getByText(
|
||||
'告诉陶泥儿接下来要做什么,或输入 @ 选择资源',
|
||||
),
|
||||
).not.toBeNull();
|
||||
expect(
|
||||
@@ -5332,9 +5335,7 @@ export function registerProjectSupervisorSurfaceTests() {
|
||||
expect.anything(),
|
||||
);
|
||||
const input = within(supervisorSurface).getByLabelText('陶泥儿对话内容');
|
||||
fireEvent.change(input, {
|
||||
target: { value: '从旧任务状态继续生成,但使用 direct Codex' },
|
||||
});
|
||||
await setComposerText(input, '从旧任务状态继续生成,但使用 direct Codex');
|
||||
fireEvent.submit(input.closest('form') as HTMLFormElement);
|
||||
|
||||
expect(
|
||||
@@ -5408,9 +5409,10 @@ export function registerProjectSupervisorSurfaceTests() {
|
||||
expect(screen.queryByLabelText('项目总控 Agent 状态')).toBeNull();
|
||||
expect(screen.queryByLabelText('专业 Agent 协作状态')).toBeNull();
|
||||
|
||||
fireEvent.change(within(surface).getByLabelText('项目总控对话内容'), {
|
||||
target: { value: '继续完成可玩原型' },
|
||||
});
|
||||
await setComposerText(
|
||||
within(surface).getByLabelText('项目总控对话内容'),
|
||||
'继续完成可玩原型',
|
||||
);
|
||||
fireEvent.click(within(surface).getByRole('button', { name: '发送' }));
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -5455,15 +5457,16 @@ export function registerProjectSupervisorSurfaceTests() {
|
||||
renderSupervisorChat();
|
||||
const firstSurface = await screen.findByLabelText('项目总控 Agent 纯聊天');
|
||||
await within(firstSurface).findByLabelText('项目总控消息');
|
||||
fireEvent.change(within(firstSurface).getByLabelText('项目总控对话内容'), {
|
||||
target: { value: '这条草稿还没有发送' },
|
||||
});
|
||||
await setComposerText(
|
||||
within(firstSurface).getByLabelText('项目总控对话内容'),
|
||||
'这条草稿还没有发送',
|
||||
);
|
||||
|
||||
cleanup();
|
||||
renderSupervisorChat();
|
||||
|
||||
const restoredInput = await screen.findByLabelText('项目总控对话内容');
|
||||
expect(restoredInput).toHaveProperty('value', '这条草稿还没有发送');
|
||||
expect(await composerValue(restoredInput)).toBe('这条草稿还没有发送');
|
||||
});
|
||||
|
||||
it('shows and handles runtime recovery confirmation in the standalone Project Supervisor chat', async () => {
|
||||
@@ -5658,13 +5661,9 @@ export function registerProjectSupervisorSurfaceTests() {
|
||||
within(card).getByText('首版角色规范图采用哪种美术方向?'),
|
||||
).not.toBeNull();
|
||||
expect(within(card).getByText('优先验证轮廓与动作可读性。')).not.toBeNull();
|
||||
expect(
|
||||
(
|
||||
within(surface).getByLabelText(
|
||||
'项目总控对话内容',
|
||||
) as HTMLTextAreaElement
|
||||
).disabled,
|
||||
).toBe(true);
|
||||
expect(await composerDisabled('项目总控对话内容', within(surface))).toBe(
|
||||
true,
|
||||
);
|
||||
|
||||
fireEvent.click(within(card).getByRole('button', { name: /像素风/ }));
|
||||
fireEvent.click(within(card).getByRole('button', { name: '提交回答' }));
|
||||
@@ -5794,9 +5793,10 @@ export function registerProjectSupervisorSurfaceTests() {
|
||||
},
|
||||
);
|
||||
|
||||
fireEvent.change(screen.getByLabelText('陶泥儿对话内容'), {
|
||||
target: { value: '先完成正式客户端玩法拆解' },
|
||||
});
|
||||
await setComposerText(
|
||||
screen.getByLabelText('陶泥儿对话内容'),
|
||||
'先完成正式客户端玩法拆解',
|
||||
);
|
||||
fireEvent.click(
|
||||
within(supervisorSurface).getByRole('button', { name: '发送' }),
|
||||
);
|
||||
@@ -6068,9 +6068,10 @@ export function registerProjectSupervisorSurfaceTests() {
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
fireEvent.change(screen.getByLabelText('陶泥儿对话内容'), {
|
||||
target: { value: '补充:优先复用现有素材' },
|
||||
});
|
||||
await setComposerText(
|
||||
screen.getByLabelText('陶泥儿对话内容'),
|
||||
'补充:优先复用现有素材',
|
||||
);
|
||||
fireEvent.click(
|
||||
within(supervisorSurface).getByRole('button', { name: '发送' }),
|
||||
);
|
||||
@@ -6416,19 +6417,28 @@ export function registerProjectSupervisorSurfaceTests() {
|
||||
).toBe(false);
|
||||
|
||||
const composer = within(surface).getByLabelText('陶泥儿对话内容');
|
||||
fireEvent.change(composer, { target: { value: '修改玩家移动脚本' } });
|
||||
await setComposerText(composer, '修改玩家移动脚本');
|
||||
// 输入区已从原生 textarea 换成 Lexical 富文本:Shift+Enter 由编辑器自己插入换行
|
||||
// (按键被编辑器消化,因此 fireEvent 返回 false),语义仍是「换行而不是发送」。
|
||||
expect(fireEvent.keyDown(composer, { key: 'Enter', shiftKey: true })).toBe(
|
||||
true,
|
||||
false,
|
||||
);
|
||||
// composerValue 会先等编辑器提交这一帧,再校验草稿保留且确实插入了换行。
|
||||
expect(await composerValue(composer)).toBe('修改玩家移动脚本');
|
||||
expect(
|
||||
composer.querySelector('br:not([data-lexical-managed-linebreak])'),
|
||||
).not.toBeNull();
|
||||
expect(
|
||||
invoke.mock.calls.some(
|
||||
([command]) => command === 'chat_with_game_creator_direct_codex',
|
||||
),
|
||||
).toBe(false);
|
||||
|
||||
// 组合态 Enter 同样不发送:按键被编辑器消化,草稿原样保留。
|
||||
expect(
|
||||
fireEvent.keyDown(composer, { key: 'Enter', isComposing: true }),
|
||||
).toBe(true);
|
||||
).toBe(false);
|
||||
expect(await composerValue(composer)).toBe('修改玩家移动脚本');
|
||||
expect(
|
||||
invoke.mock.calls.some(
|
||||
([command]) => command === 'chat_with_game_creator_direct_codex',
|
||||
@@ -6466,7 +6476,7 @@ export function registerProjectWorkbenchNavigationTests() {
|
||||
'open_game_creator_launcher_window',
|
||||
);
|
||||
|
||||
submitChat('/switch-project');
|
||||
await submitChat('/switch-project');
|
||||
|
||||
expect(
|
||||
screen.getAllByText('请回到首页的项目组切换项目。').length,
|
||||
@@ -6541,7 +6551,7 @@ export function registerProjectWorkbenchNavigationTests() {
|
||||
});
|
||||
expect(await screen.findByText('已打开项目目录。')).not.toBeNull();
|
||||
|
||||
submitChat('/open-project');
|
||||
await submitChat('/open-project');
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
@@ -6625,8 +6635,7 @@ export function registerProjectWorkbenchNavigationTests() {
|
||||
expect(document.activeElement).toBe(screen.getByLabelText('创作想法')),
|
||||
);
|
||||
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
expect(await composerText()).toBe(
|
||||
'/asset-register assets/uploads/hero.png image image/png',
|
||||
);
|
||||
expect(
|
||||
|
||||
+56
-76
@@ -1,4 +1,11 @@
|
||||
import { expect, fireEvent, screen, submitChat, within } from '../../harness';
|
||||
import {
|
||||
composerText,
|
||||
expect,
|
||||
fireEvent,
|
||||
screen,
|
||||
submitChat,
|
||||
within,
|
||||
} from '../../harness';
|
||||
import type { PreviewShortcutInvoke } from './invoke-mock';
|
||||
import { messageBubble } from './message-bubble';
|
||||
|
||||
@@ -14,7 +21,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
const runLocalCountBeforeRisks = invoke.mock.calls.filter(
|
||||
([command]) => command === 'run_limited_local_command',
|
||||
).length;
|
||||
submitChat('/risks');
|
||||
await submitChat('/risks');
|
||||
expect(await screen.findByText(/项目风险:/)).not.toBeNull();
|
||||
expect(
|
||||
screen.getByText(/最近 run 已通过,但当前本地预览未运行。 建议:\/run/),
|
||||
@@ -23,7 +30,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
screen.getByText(/还有 3 个 ready 任务等待处理。 建议:\/tasks/),
|
||||
).not.toBeNull();
|
||||
fireEvent.click(screen.getByRole('button', { name: '处理首个风险' }));
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/run');
|
||||
expect(await composerText()).toBe('/run');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -69,7 +76,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
([command]) => command === 'control_agent_run',
|
||||
).length,
|
||||
};
|
||||
submitChat('/blockers');
|
||||
await submitChat('/blockers');
|
||||
const blockerMessages = await screen.findAllByText(/当前阻塞项:/);
|
||||
const blockerMessage = messageBubble(
|
||||
blockerMessages[blockerMessages.length - 1],
|
||||
@@ -97,7 +104,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
blockerMessageList as HTMLElement,
|
||||
).getAllByRole('button', { name: '处理首个阻塞' });
|
||||
fireEvent.click(blockerDraftButtons[blockerDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/run');
|
||||
expect(await composerText()).toBe('/run');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -171,7 +178,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
([command]) => command === 'control_agent_run',
|
||||
).length,
|
||||
};
|
||||
submitChat('/ready');
|
||||
await submitChat('/ready');
|
||||
const readyMessages = await screen.findAllByText(/试玩就绪度:/);
|
||||
const readyMessage = messageBubble(readyMessages[readyMessages.length - 1]);
|
||||
expect(readyMessage.textContent).toContain('项目:未命名游戏原型');
|
||||
@@ -197,7 +204,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
readyMessageList as HTMLElement,
|
||||
).getAllByRole('button', { name: '启动试玩' });
|
||||
fireEvent.click(readyDraftButtons[readyDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/run');
|
||||
expect(await composerText()).toBe('/run');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -271,7 +278,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
([command]) => command === 'control_agent_run',
|
||||
).length,
|
||||
};
|
||||
submitChat('/evidence');
|
||||
await submitChat('/evidence');
|
||||
const evidenceMessages = await screen.findAllByText(/验证证据台账:/);
|
||||
const evidenceMessage = messageBubble(
|
||||
evidenceMessages[evidenceMessages.length - 1],
|
||||
@@ -306,7 +313,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
evidenceMessageList as HTMLElement,
|
||||
).getAllByRole('button', { name: '补齐首个证据缺口' });
|
||||
fireEvent.click(evidenceDraftButtons[evidenceDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/run');
|
||||
expect(await composerText()).toBe('/run');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -380,7 +387,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
([command]) => command === 'control_agent_run',
|
||||
).length,
|
||||
};
|
||||
submitChat('/deps');
|
||||
await submitChat('/deps');
|
||||
const dependencyMessages = await screen.findAllByText(/任务依赖链:/);
|
||||
const dependencyMessage = messageBubble(
|
||||
dependencyMessages[dependencyMessages.length - 1],
|
||||
@@ -407,10 +414,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
dependencyMessageList as HTMLElement,
|
||||
).getAllByRole('button', { name: '查看验收标准' });
|
||||
fireEvent.click(dependencyDraftButtons[dependencyDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
'/criteria',
|
||||
);
|
||||
expect(await composerText()).toBe('/criteria');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -484,7 +488,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
([command]) => command === 'control_agent_run',
|
||||
).length,
|
||||
};
|
||||
submitChat('/revise');
|
||||
await submitChat('/revise');
|
||||
const revisionMessages = await screen.findAllByText(/改版草稿:/);
|
||||
const revisionMessage = messageBubble(
|
||||
revisionMessages[revisionMessages.length - 1],
|
||||
@@ -534,8 +538,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
revisionMessageList as HTMLElement,
|
||||
).getAllByRole('button', { name: '填入改版说明' });
|
||||
fireEvent.click(revisionDraftButtons[revisionDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
expect(await composerText()).toEqual(
|
||||
expect.stringContaining('/agent-resume 改版说明:'),
|
||||
);
|
||||
expect(
|
||||
@@ -611,7 +614,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
([command]) => command === 'control_agent_run',
|
||||
).length,
|
||||
};
|
||||
submitChat('/privacy');
|
||||
await submitChat('/privacy');
|
||||
const privacyMessages = await screen.findAllByText(/隐私与导出边界:/);
|
||||
const privacyMessage = messageBubble(
|
||||
privacyMessages[privacyMessages.length - 1],
|
||||
@@ -651,7 +654,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
privacyMessageList as HTMLElement,
|
||||
).getAllByRole('button', { name: '查看素材来源' });
|
||||
fireEvent.click(privacyDraftButtons[privacyDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/credits');
|
||||
expect(await composerText()).toBe('/credits');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -705,7 +708,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
const runLocalCountBeforeCriteria = invoke.mock.calls.filter(
|
||||
([command]) => command === 'run_limited_local_command',
|
||||
).length;
|
||||
submitChat('/criteria');
|
||||
await submitChat('/criteria');
|
||||
expect(await screen.findByText(/当前验收标准:/)).not.toBeNull();
|
||||
const criteriaMessages = screen.getAllByText(/当前验收标准:/);
|
||||
const criteriaMessage = messageBubble(
|
||||
@@ -724,7 +727,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
name: '查看任务',
|
||||
});
|
||||
fireEvent.click(criteriaDraftButtons[criteriaDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/tasks');
|
||||
expect(await composerText()).toBe('/tasks');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'read_local_project_file',
|
||||
@@ -750,7 +753,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
const runLocalCountBeforeGroups = invoke.mock.calls.filter(
|
||||
([command]) => command === 'run_limited_local_command',
|
||||
).length;
|
||||
submitChat('/groups');
|
||||
await submitChat('/groups');
|
||||
expect(await screen.findByText(/专业组进度:/)).not.toBeNull();
|
||||
const groupMessages = screen.getAllByText(/专业组进度:/);
|
||||
const groupMessage = messageBubble(groupMessages[groupMessages.length - 1]);
|
||||
@@ -763,7 +766,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
name: '查看任务',
|
||||
});
|
||||
fireEvent.click(groupDraftButtons[groupDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/tasks');
|
||||
expect(await composerText()).toBe('/tasks');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'read_local_project_file',
|
||||
@@ -803,7 +806,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
([command]) => command === 'export_local_project_package',
|
||||
).length,
|
||||
};
|
||||
submitChat('/balance');
|
||||
await submitChat('/balance');
|
||||
expect(await screen.findByText(/数值状态:/)).not.toBeNull();
|
||||
const balanceMessages = screen.getAllByText(/数值状态:/);
|
||||
const balanceMessage = messageBubble(
|
||||
@@ -837,8 +840,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
balanceMessageList as HTMLElement,
|
||||
).getAllByRole('button', { name: '填写数值反馈' });
|
||||
fireEvent.click(balanceDraftButtons[balanceDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
expect(await composerText()).toBe(
|
||||
'/agent-resume 数值调整:前 30 秒更易上手;得分反馈更明显;失败后重开节奏更快',
|
||||
);
|
||||
expect(
|
||||
@@ -886,7 +888,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
const runLocalCountBeforeBudget = invoke.mock.calls.filter(
|
||||
([command]) => command === 'run_limited_local_command',
|
||||
).length;
|
||||
submitChat('/budget');
|
||||
await submitChat('/budget');
|
||||
expect(await screen.findByText(/运行预算:/)).not.toBeNull();
|
||||
const budgetMessages = screen.getAllByText(/运行预算:/);
|
||||
const budgetMessage = messageBubble(
|
||||
@@ -905,7 +907,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
name: '查看发布准备',
|
||||
});
|
||||
fireEvent.click(budgetDraftButtons[budgetDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/publish');
|
||||
expect(await composerText()).toBe('/publish');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'read_local_project_file',
|
||||
@@ -937,7 +939,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
const openPreviewCountBeforeQa = invoke.mock.calls.filter(
|
||||
([command]) => command === 'activate_local_game_preview',
|
||||
).length;
|
||||
submitChat('/qa');
|
||||
await submitChat('/qa');
|
||||
expect(await screen.findByText(/质量检查:/)).not.toBeNull();
|
||||
const qaMessages = screen.getAllByText(/质量检查:/);
|
||||
const qaMessage = messageBubble(qaMessages[qaMessages.length - 1]);
|
||||
@@ -954,10 +956,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
name: '查看试玩状态',
|
||||
});
|
||||
fireEvent.click(qaDraftButtons[qaDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
'/playtest',
|
||||
);
|
||||
expect(await composerText()).toBe('/playtest');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'read_local_project_file',
|
||||
@@ -1002,7 +1001,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
const openPreviewCountBeforeChanges = invoke.mock.calls.filter(
|
||||
([command]) => command === 'activate_local_game_preview',
|
||||
).length;
|
||||
submitChat('/changes');
|
||||
await submitChat('/changes');
|
||||
expect(await screen.findByText(/最近变更:/)).not.toBeNull();
|
||||
const changeMessages = screen.getAllByText(/最近变更:/);
|
||||
const changeMessage = messageBubble(
|
||||
@@ -1030,10 +1029,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
name: '读取首个产物',
|
||||
});
|
||||
fireEvent.click(changeDraftButtons[changeDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
'/read exports/README.md',
|
||||
);
|
||||
expect(await composerText()).toBe('/read exports/README.md');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'read_local_project_file',
|
||||
@@ -1080,7 +1076,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
const openPreviewCountBeforeReview = invoke.mock.calls.filter(
|
||||
([command]) => command === 'activate_local_game_preview',
|
||||
).length;
|
||||
submitChat('/review');
|
||||
await submitChat('/review');
|
||||
expect(await screen.findByText(/评审状态:/)).not.toBeNull();
|
||||
const reviewMessages = screen.getAllByText(/评审状态:/);
|
||||
const reviewMessage = messageBubble(
|
||||
@@ -1095,10 +1091,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
'Evaluator #1 · passed · 质量评审通过',
|
||||
);
|
||||
fireEvent.click(screen.getByRole('button', { name: '读取评审记录' }));
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
'/read .agent/findings.md',
|
||||
);
|
||||
expect(await composerText()).toBe('/read .agent/findings.md');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'read_local_project_file',
|
||||
@@ -1128,7 +1121,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
const fileReadCountBeforeContext = invoke.mock.calls.filter(
|
||||
([command]) => command === 'read_local_project_file',
|
||||
).length;
|
||||
submitChat('/context');
|
||||
await submitChat('/context');
|
||||
expect(await screen.findByText(/上下文来源:/)).not.toBeNull();
|
||||
expect(screen.getByText(/项目对话:\/history/)).not.toBeNull();
|
||||
expect(screen.getByText(/项目黑板:\/memory blackboard/)).not.toBeNull();
|
||||
@@ -1143,10 +1136,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
name: '读取首个上下文',
|
||||
});
|
||||
fireEvent.click(contextDraftButtons[contextDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
'/read .agent/spec.md',
|
||||
);
|
||||
expect(await composerText()).toBe('/read .agent/spec.md');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'read_local_project_file',
|
||||
@@ -1168,7 +1158,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
const openPreviewCountBeforeTimeline = invoke.mock.calls.filter(
|
||||
([command]) => command === 'activate_local_game_preview',
|
||||
).length;
|
||||
submitChat('/timeline');
|
||||
await submitChat('/timeline');
|
||||
expect(await screen.findByText(/项目时间线:/)).not.toBeNull();
|
||||
const timelineMessages = screen.getAllByText(/项目时间线:/);
|
||||
const timelineMessage = messageBubble(
|
||||
@@ -1190,10 +1180,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
name: '读取最近日志',
|
||||
});
|
||||
fireEvent.click(timelineDraftButtons[timelineDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
'/read .agent/logs/command.log',
|
||||
);
|
||||
expect(await composerText()).toBe('/read .agent/logs/command.log');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'read_local_project_file',
|
||||
@@ -1229,7 +1216,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
const runLocalCountBeforeHandoff = invoke.mock.calls.filter(
|
||||
([command]) => command === 'run_limited_local_command',
|
||||
).length;
|
||||
submitChat('/handoff');
|
||||
await submitChat('/handoff');
|
||||
expect(await screen.findByText(/项目交接:/)).not.toBeNull();
|
||||
const handoffMessages = screen.getAllByText(/项目交接:/);
|
||||
const handoffMessage = messageBubble(
|
||||
@@ -1246,7 +1233,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
name: '查看下一步',
|
||||
});
|
||||
fireEvent.click(nextActionButtons[nextActionButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/next');
|
||||
expect(await composerText()).toBe('/next');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -1266,13 +1253,13 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
const fileReadCountBeforeRuns = invoke.mock.calls.filter(
|
||||
([command]) => command === 'read_local_project_file',
|
||||
).length;
|
||||
submitChat('/runs');
|
||||
await submitChat('/runs');
|
||||
expect(await screen.findByText(/Run 历史读取命令:/)).not.toBeNull();
|
||||
expect(
|
||||
screen.getByText(/当前指针 run-main-shortcut-trace .*:\/trace/),
|
||||
).not.toBeNull();
|
||||
fireEvent.click(screen.getByRole('button', { name: '查看最近 Run' }));
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/trace');
|
||||
expect(await composerText()).toBe('/trace');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'read_local_project_file',
|
||||
@@ -1282,7 +1269,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
const fileReadCountBeforeRunFiles = invoke.mock.calls.filter(
|
||||
([command]) => command === 'read_local_project_file',
|
||||
).length;
|
||||
submitChat('/run-files');
|
||||
await submitChat('/run-files');
|
||||
expect(
|
||||
await screen.findByText(/Agent 运行辅助文件读取命令:/),
|
||||
).not.toBeNull();
|
||||
@@ -1297,10 +1284,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
name: '读输出流',
|
||||
}),
|
||||
);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
'/read .agent/output.jsonl',
|
||||
);
|
||||
expect(await composerText()).toBe('/read .agent/output.jsonl');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'read_local_project_file',
|
||||
@@ -1310,7 +1294,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
const fileReadCountBeforeInternals = invoke.mock.calls.filter(
|
||||
([command]) => command === 'read_local_project_file',
|
||||
).length;
|
||||
submitChat('/internals');
|
||||
await submitChat('/internals');
|
||||
expect(await screen.findByText(/项目内部真相源读取命令:/)).not.toBeNull();
|
||||
expect(
|
||||
screen.getByText(/读 manifest · \.agent\/manifest\.json/),
|
||||
@@ -1322,10 +1306,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
name: '读 manifest',
|
||||
});
|
||||
fireEvent.click(internalDraftButtons[internalDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
'/read .agent/manifest.json',
|
||||
);
|
||||
expect(await composerText()).toBe('/read .agent/manifest.json');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'read_local_project_file',
|
||||
@@ -1358,7 +1339,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
([command]) => command === 'list_local_project_export_packages',
|
||||
).length,
|
||||
};
|
||||
submitChat('/todo');
|
||||
await submitChat('/todo');
|
||||
const todoMessages = await screen.findAllByText(/下一轮小步:/);
|
||||
const todoMessage = messageBubble(todoMessages[todoMessages.length - 1]);
|
||||
expect(todoMessage.textContent).toContain('项目:未命名游戏原型');
|
||||
@@ -1380,7 +1361,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
{ name: '查看任务' },
|
||||
);
|
||||
fireEvent.click(todoDraftButtons[todoDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/tasks');
|
||||
expect(await composerText()).toBe('/tasks');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -1451,7 +1432,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
([command]) => command === 'control_agent_run',
|
||||
).length,
|
||||
};
|
||||
submitChat('/plan');
|
||||
await submitChat('/plan');
|
||||
const planMessages = await screen.findAllByText(/下一轮分工计划:/);
|
||||
const planMessage = messageBubble(planMessages[planMessages.length - 1]);
|
||||
expect(planMessage.textContent).toContain('项目:未命名游戏原型');
|
||||
@@ -1479,8 +1460,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
{ name: '继续执行计划' },
|
||||
);
|
||||
fireEvent.click(planDraftButtons[planDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
expect(await composerText()).toBe(
|
||||
'/agent-resume 下一轮计划:美术组 / Asset 生成首版美术素材',
|
||||
);
|
||||
expect(
|
||||
@@ -1556,7 +1536,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
([command]) => command === 'control_agent_run',
|
||||
).length,
|
||||
};
|
||||
submitChat('/guide');
|
||||
await submitChat('/guide');
|
||||
const guideMessages = await screen.findAllByText(/使用导引:/);
|
||||
const guideMessage = messageBubble(guideMessages[guideMessages.length - 1]);
|
||||
expect(guideMessage.textContent).toContain('项目:未命名游戏原型');
|
||||
@@ -1576,7 +1556,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
guideMessageList as HTMLElement,
|
||||
).getAllByRole('button', { name: '执行导引建议' });
|
||||
fireEvent.click(guideDraftButtons[guideDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/run');
|
||||
expect(await composerText()).toBe('/run');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -1650,7 +1630,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
([command]) => command === 'control_agent_run',
|
||||
).length,
|
||||
};
|
||||
submitChat('/progress');
|
||||
await submitChat('/progress');
|
||||
const progressMessages = await screen.findAllByText(/项目进度:/);
|
||||
const progressMessage = messageBubble(
|
||||
progressMessages[progressMessages.length - 1],
|
||||
@@ -1680,7 +1660,7 @@ export async function assertPlanningAndStatusShortcutFlow(
|
||||
progressMessageList as HTMLElement,
|
||||
).getAllByRole('button', { name: '启动预览' });
|
||||
fireEvent.click(progressDraftButtons[progressDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/run');
|
||||
expect(await composerText()).toBe('/run');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
|
||||
+42
-38
@@ -1,4 +1,11 @@
|
||||
import { expect, fireEvent, screen, submitChat, within } from '../../harness';
|
||||
import {
|
||||
composerText,
|
||||
expect,
|
||||
fireEvent,
|
||||
screen,
|
||||
submitChat,
|
||||
within,
|
||||
} from '../../harness';
|
||||
import type { PreviewShortcutInvoke } from './invoke-mock';
|
||||
import { messageBubble } from './message-bubble';
|
||||
|
||||
@@ -8,7 +15,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
const runLocalCountBeforeNext = invoke.mock.calls.filter(
|
||||
([command]) => command === 'run_limited_local_command',
|
||||
).length;
|
||||
submitChat('/next');
|
||||
await submitChat('/next');
|
||||
expect(await screen.findByText(/下一步建议:/)).not.toBeNull();
|
||||
expect(screen.getByText(/运行自检并启动本地预览:\/run/)).not.toBeNull();
|
||||
expect(screen.getByText(/查看创作目标:\/goal/)).not.toBeNull();
|
||||
@@ -86,7 +93,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
name: '运行自检并启动本地预览',
|
||||
}),
|
||||
);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/run');
|
||||
expect(await composerText()).toBe('/run');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'run_limited_local_command',
|
||||
@@ -105,7 +112,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
const startPreviewCountBeforePublish = invoke.mock.calls.filter(
|
||||
([command]) => command === 'start_local_game_preview',
|
||||
).length;
|
||||
submitChat('/publish');
|
||||
await submitChat('/publish');
|
||||
expect(await screen.findByText(/发布准备:/)).not.toBeNull();
|
||||
expect(
|
||||
screen.getByText(/原型:最近 run 已通过 run-main-shortcut-trace/),
|
||||
@@ -121,7 +128,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
name: '启动预览',
|
||||
});
|
||||
fireEvent.click(publishDraftButtons[publishDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/run');
|
||||
expect(await composerText()).toBe('/run');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -169,7 +176,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
([command]) => command === 'list_local_project_export_packages',
|
||||
).length,
|
||||
};
|
||||
submitChat('/listing');
|
||||
await submitChat('/listing');
|
||||
const listingMessages = await screen.findAllByText(/作品页草稿:/);
|
||||
const listingMessage = messageBubble(
|
||||
listingMessages[listingMessages.length - 1],
|
||||
@@ -203,10 +210,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
listingMessageList as HTMLElement,
|
||||
).getAllByRole('button', { name: '读发布说明' });
|
||||
fireEvent.click(listingDraftButtons[listingDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
'/read exports/README.md',
|
||||
);
|
||||
expect(await composerText()).toBe('/read exports/README.md');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -263,7 +267,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
const openPreviewCountBeforePlaytest = invoke.mock.calls.filter(
|
||||
([command]) => command === 'activate_local_game_preview',
|
||||
).length;
|
||||
submitChat('/playtest');
|
||||
await submitChat('/playtest');
|
||||
const playtestMessages = await screen.findAllByText(/试玩状态:/);
|
||||
const playtestMessage = messageBubble(
|
||||
playtestMessages[playtestMessages.length - 1],
|
||||
@@ -282,7 +286,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
name: '启动试玩',
|
||||
});
|
||||
fireEvent.click(playtestDraftButtons[playtestDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/run');
|
||||
expect(await composerText()).toBe('/run');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'read_local_project_file',
|
||||
@@ -332,7 +336,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
([command]) => command === 'export_local_project_package',
|
||||
).length,
|
||||
};
|
||||
submitChat('/test-plan');
|
||||
await submitChat('/test-plan');
|
||||
const testPlanMessages = await screen.findAllByText(/手动测试计划:/);
|
||||
const testPlanMessage = messageBubble(
|
||||
testPlanMessages[testPlanMessages.length - 1],
|
||||
@@ -369,7 +373,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
testPlanMessageList as HTMLElement,
|
||||
).getAllByRole('button', { name: '启动试玩' });
|
||||
fireEvent.click(testPlanDraftButtons[testPlanDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/run');
|
||||
expect(await composerText()).toBe('/run');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -435,7 +439,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
([command]) => command === 'control_agent_run',
|
||||
).length,
|
||||
};
|
||||
submitChat('/audience');
|
||||
await submitChat('/audience');
|
||||
const audienceMessages = await screen.findAllByText(/首批试玩对象:/);
|
||||
const audienceMessage = messageBubble(
|
||||
audienceMessages[audienceMessages.length - 1],
|
||||
@@ -476,7 +480,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
audienceMessageList as HTMLElement,
|
||||
).getAllByRole('button', { name: '启动试玩' });
|
||||
fireEvent.click(audienceDraftButtons[audienceDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/run');
|
||||
expect(await composerText()).toBe('/run');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -550,7 +554,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
([command]) => command === 'control_agent_run',
|
||||
).length,
|
||||
};
|
||||
submitChat('/invite');
|
||||
await submitChat('/invite');
|
||||
const inviteMessages = await screen.findAllByText(/试玩邀请:/);
|
||||
const inviteMessage = messageBubble(
|
||||
inviteMessages[inviteMessages.length - 1],
|
||||
@@ -583,7 +587,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
inviteMessageList as HTMLElement,
|
||||
).getAllByRole('button', { name: '启动试玩' });
|
||||
fireEvent.click(inviteDraftButtons[inviteDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/run');
|
||||
expect(await composerText()).toBe('/run');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -730,7 +734,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
([command]) => command === 'control_agent_run',
|
||||
).length,
|
||||
};
|
||||
submitChat('/survey');
|
||||
await submitChat('/survey');
|
||||
const surveyMessages = await screen.findAllByText(/试玩问卷:/);
|
||||
const surveyMessage = messageBubble(
|
||||
surveyMessages[surveyMessages.length - 1],
|
||||
@@ -765,7 +769,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
surveyMessageList as HTMLElement,
|
||||
).getAllByRole('button', { name: '启动试玩' });
|
||||
fireEvent.click(surveyDraftButtons[surveyDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/run');
|
||||
expect(await composerText()).toBe('/run');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -839,7 +843,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
([command]) => command === 'control_agent_run',
|
||||
).length,
|
||||
};
|
||||
submitChat('/cover');
|
||||
await submitChat('/cover');
|
||||
const coverMessages = await screen.findAllByText(/封面与缩略图:/);
|
||||
const coverMessage = messageBubble(coverMessages[coverMessages.length - 1]);
|
||||
expect(coverMessage.textContent).toContain('项目:未命名游戏原型');
|
||||
@@ -874,7 +878,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
coverMessageList as HTMLElement,
|
||||
).getAllByRole('button', { name: '启动试玩' });
|
||||
fireEvent.click(coverDraftButtons[coverDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/run');
|
||||
expect(await composerText()).toBe('/run');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -948,7 +952,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
([command]) => command === 'control_agent_run',
|
||||
).length,
|
||||
};
|
||||
submitChat('/screenshots');
|
||||
await submitChat('/screenshots');
|
||||
const screenshotMessages = await screen.findAllByText(/宣传截图:/);
|
||||
const screenshotMessage = messageBubble(
|
||||
screenshotMessages[screenshotMessages.length - 1],
|
||||
@@ -985,7 +989,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
screenshotMessageList as HTMLElement,
|
||||
).getAllByRole('button', { name: '启动试玩' });
|
||||
fireEvent.click(screenshotDraftButtons[screenshotDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/run');
|
||||
expect(await composerText()).toBe('/run');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -1059,7 +1063,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
([command]) => command === 'control_agent_run',
|
||||
).length,
|
||||
};
|
||||
submitChat('/trailer');
|
||||
await submitChat('/trailer');
|
||||
const trailerMessages = await screen.findAllByText(/试玩短视频:/);
|
||||
const trailerMessage = messageBubble(
|
||||
trailerMessages[trailerMessages.length - 1],
|
||||
@@ -1097,7 +1101,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
trailerMessageList as HTMLElement,
|
||||
).getAllByRole('button', { name: '启动试玩' });
|
||||
fireEvent.click(trailerDraftButtons[trailerDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/run');
|
||||
expect(await composerText()).toBe('/run');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -1171,7 +1175,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
([command]) => command === 'control_agent_run',
|
||||
).length,
|
||||
};
|
||||
submitChat('/faq');
|
||||
await submitChat('/faq');
|
||||
const faqMessages = await screen.findAllByText(/试玩 FAQ:/);
|
||||
const faqMessage = messageBubble(faqMessages[faqMessages.length - 1]);
|
||||
expect(faqMessage.textContent).toContain('项目:未命名游戏原型');
|
||||
@@ -1202,7 +1206,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
{ name: '启动试玩' },
|
||||
);
|
||||
fireEvent.click(faqDraftButtons[faqDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/run');
|
||||
expect(await composerText()).toBe('/run');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -1276,7 +1280,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
([command]) => command === 'control_agent_run',
|
||||
).length,
|
||||
};
|
||||
submitChat('/post');
|
||||
await submitChat('/post');
|
||||
const postMessages = await screen.findAllByText(/社区发布文案:/);
|
||||
const postMessage = messageBubble(postMessages[postMessages.length - 1]);
|
||||
expect(postMessage.textContent).toContain('项目:未命名游戏原型');
|
||||
@@ -1313,7 +1317,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
{ name: '启动试玩' },
|
||||
);
|
||||
fireEvent.click(postDraftButtons[postDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/run');
|
||||
expect(await composerText()).toBe('/run');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -1387,7 +1391,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
([command]) => command === 'control_agent_run',
|
||||
).length,
|
||||
};
|
||||
submitChat('/store');
|
||||
await submitChat('/store');
|
||||
const storeMessages = await screen.findAllByText(/上架资料:/);
|
||||
const storeMessage = messageBubble(storeMessages[storeMessages.length - 1]);
|
||||
expect(storeMessage.textContent).toContain('项目:未命名游戏原型');
|
||||
@@ -1423,7 +1427,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
storeMessageList as HTMLElement,
|
||||
).getAllByRole('button', { name: '启动试玩' });
|
||||
fireEvent.click(storeDraftButtons[storeDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/run');
|
||||
expect(await composerText()).toBe('/run');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -1497,7 +1501,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
([command]) => command === 'control_agent_run',
|
||||
).length,
|
||||
};
|
||||
submitChat('/media-kit');
|
||||
await submitChat('/media-kit');
|
||||
const mediaKitMessages = await screen.findAllByText(/媒体资料包:/);
|
||||
const mediaKitMessage = messageBubble(
|
||||
mediaKitMessages[mediaKitMessages.length - 1],
|
||||
@@ -1532,7 +1536,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
mediaKitMessageList as HTMLElement,
|
||||
).getAllByRole('button', { name: '启动试玩' });
|
||||
fireEvent.click(mediaKitDraftButtons[mediaKitDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/run');
|
||||
expect(await composerText()).toBe('/run');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -1606,7 +1610,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
([command]) => command === 'control_agent_run',
|
||||
).length,
|
||||
};
|
||||
submitChat('/release-notes');
|
||||
await submitChat('/release-notes');
|
||||
const releaseNotesMessages = await screen.findAllByText(/试玩更新说明:/);
|
||||
const releaseNotesMessage = messageBubble(
|
||||
releaseNotesMessages[releaseNotesMessages.length - 1],
|
||||
@@ -1651,7 +1655,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
fireEvent.click(
|
||||
releaseNotesDraftButtons[releaseNotesDraftButtons.length - 1],
|
||||
);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/run');
|
||||
expect(await composerText()).toBe('/run');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -1725,7 +1729,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
([command]) => command === 'control_agent_run',
|
||||
).length,
|
||||
};
|
||||
submitChat('/known-issues');
|
||||
await submitChat('/known-issues');
|
||||
const knownIssueMessages = await screen.findAllByText(/已知问题清单:/);
|
||||
const knownIssueMessage = messageBubble(
|
||||
knownIssueMessages[knownIssueMessages.length - 1],
|
||||
@@ -1756,7 +1760,7 @@ export async function assertPlaytestAndReleaseShortcutFlow(
|
||||
knownIssueMessageList as HTMLElement,
|
||||
).getAllByRole('button', { name: '启动试玩' });
|
||||
fireEvent.click(knownIssueDraftButtons[knownIssueDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/run');
|
||||
expect(await composerText()).toBe('/run');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
|
||||
+43
-57
@@ -1,4 +1,11 @@
|
||||
import { expect, fireEvent, screen, submitChat, within } from '../../harness';
|
||||
import {
|
||||
composerText,
|
||||
expect,
|
||||
fireEvent,
|
||||
screen,
|
||||
submitChat,
|
||||
within,
|
||||
} from '../../harness';
|
||||
import type { PreviewShortcutInvoke } from './invoke-mock';
|
||||
import { messageBubble } from './message-bubble';
|
||||
|
||||
@@ -36,14 +43,14 @@ export async function assertProjectAndDesignShortcutFlow(
|
||||
expect(screen.queryByText(/planner-secret/)).toBeNull();
|
||||
expect(screen.queryByText(/art-secret/)).toBeNull();
|
||||
|
||||
submitChat('/agents');
|
||||
await submitChat('/agents');
|
||||
await screen.findByText(/Agent 状态:/);
|
||||
expect(
|
||||
/Agent 状态:[\s\S]*美术组 \/ Asset · 生成首版美术素材 · 待处理[\s\S]*智能服务:已连接/.test(
|
||||
screen.getByLabelText('聊天').textContent ?? '',
|
||||
),
|
||||
).toBe(true);
|
||||
submitChat('/agent-conversations');
|
||||
await submitChat('/agent-conversations');
|
||||
const agentConversationMessage =
|
||||
await screen.findByText('Agent 对话读取命令:');
|
||||
const agentConversationBubble = messageBubble(agentConversationMessage);
|
||||
@@ -51,8 +58,7 @@ export async function assertProjectAndDesignShortcutFlow(
|
||||
'美术组 / Asset · 生成首版美术素材:/read .agent/conversations/agents/art-asset-plan.jsonl',
|
||||
);
|
||||
fireEvent.click(screen.getByRole('button', { name: '读取拆解创作方向对话' }));
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
expect(await composerText()).toBe(
|
||||
'/read .agent/conversations/agents/design-director.jsonl',
|
||||
);
|
||||
expect(invoke).not.toHaveBeenCalledWith(
|
||||
@@ -61,7 +67,7 @@ export async function assertProjectAndDesignShortcutFlow(
|
||||
relativePath: '.agent/conversations/agents/design-director.jsonl',
|
||||
}),
|
||||
);
|
||||
submitChat('/agent-memories');
|
||||
await submitChat('/agent-memories');
|
||||
const agentMemoryMessage =
|
||||
await screen.findByText('Agent 私有记忆读取命令:');
|
||||
const agentMemoryBubble = messageBubble(agentMemoryMessage);
|
||||
@@ -69,10 +75,7 @@ export async function assertProjectAndDesignShortcutFlow(
|
||||
'美术组 / Asset · 生成首版美术素材:/read memory/agents/art/asset.md',
|
||||
);
|
||||
fireEvent.click(screen.getByRole('button', { name: '读取拆解创作方向记忆' }));
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
'/read memory/agents/design/director.md',
|
||||
);
|
||||
expect(await composerText()).toBe('/read memory/agents/design/director.md');
|
||||
expect(invoke).not.toHaveBeenCalledWith(
|
||||
'read_local_project_file',
|
||||
expect.objectContaining({
|
||||
@@ -105,12 +108,12 @@ export async function assertProjectAndDesignShortcutFlow(
|
||||
const manifestReadCountBeforeBrief = invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
).length;
|
||||
submitChat('/brief');
|
||||
await submitChat('/brief');
|
||||
expect(await screen.findByText(/项目简报:/)).not.toBeNull();
|
||||
expect(screen.getByText(/任务:完成 0\/16 · ready 3/)).not.toBeNull();
|
||||
expect(screen.getByText(/最近 Run:run-main-shortcut-trace/)).not.toBeNull();
|
||||
fireEvent.click(screen.getByRole('button', { name: '查看下一步' }));
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/next');
|
||||
expect(await composerText()).toBe('/next');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -126,7 +129,7 @@ export async function assertProjectAndDesignShortcutFlow(
|
||||
const runLocalCountBeforeGoal = invoke.mock.calls.filter(
|
||||
([command]) => command === 'run_limited_local_command',
|
||||
).length;
|
||||
submitChat('/goal');
|
||||
await submitChat('/goal');
|
||||
expect(await screen.findByText(/创作目标:/)).not.toBeNull();
|
||||
const goalMessages = screen.getAllByText(/创作目标:/);
|
||||
const goalMessage = messageBubble(goalMessages[goalMessages.length - 1]);
|
||||
@@ -139,10 +142,7 @@ export async function assertProjectAndDesignShortcutFlow(
|
||||
expect(goalMessage.textContent).toContain('上下文:/context');
|
||||
expect(goalMessage.textContent).toContain('建议:/agent-resume 细化目标:');
|
||||
fireEvent.click(screen.getByRole('button', { name: '补充目标' }));
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
'/agent-resume 细化目标:',
|
||||
);
|
||||
expect(await composerText()).toBe('/agent-resume 细化目标:');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -185,7 +185,7 @@ export async function assertProjectAndDesignShortcutFlow(
|
||||
([command]) => command === 'list_local_project_export_packages',
|
||||
).length,
|
||||
};
|
||||
submitChat('/spec');
|
||||
await submitChat('/spec');
|
||||
const specMessages = await screen.findAllByText(/创作规格包:/);
|
||||
const specMessage = messageBubble(specMessages[specMessages.length - 1]);
|
||||
expect(specMessage.textContent).toContain('项目:未命名游戏原型');
|
||||
@@ -213,10 +213,7 @@ export async function assertProjectAndDesignShortcutFlow(
|
||||
{ name: '读取规格' },
|
||||
);
|
||||
fireEvent.click(specDraftButtons[specDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
'/read .agent/spec.md',
|
||||
);
|
||||
expect(await composerText()).toBe('/read .agent/spec.md');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -284,7 +281,7 @@ export async function assertProjectAndDesignShortcutFlow(
|
||||
([command]) => command === 'list_local_project_export_packages',
|
||||
).length,
|
||||
};
|
||||
submitChat('/mvp');
|
||||
await submitChat('/mvp');
|
||||
expect(await screen.findByText(/MVP 范围:/)).not.toBeNull();
|
||||
const mvpMessages = screen.getAllByText(/MVP 范围:/);
|
||||
const mvpMessage = messageBubble(mvpMessages[mvpMessages.length - 1]);
|
||||
@@ -313,7 +310,7 @@ export async function assertProjectAndDesignShortcutFlow(
|
||||
{ name: '启动预览' },
|
||||
);
|
||||
fireEvent.click(mvpDraftButtons[mvpDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/run');
|
||||
expect(await composerText()).toBe('/run');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -381,7 +378,7 @@ export async function assertProjectAndDesignShortcutFlow(
|
||||
([command]) => command === 'list_local_project_export_packages',
|
||||
).length,
|
||||
};
|
||||
submitChat('/pitch');
|
||||
await submitChat('/pitch');
|
||||
const pitchMessages = await screen.findAllByText(/试玩定位:/);
|
||||
const pitchMessage = messageBubble(pitchMessages[pitchMessages.length - 1]);
|
||||
expect(pitchMessage.textContent).toContain('项目:未命名游戏原型');
|
||||
@@ -408,7 +405,7 @@ export async function assertProjectAndDesignShortcutFlow(
|
||||
pitchMessageList as HTMLElement,
|
||||
).getAllByRole('button', { name: '启动预览' });
|
||||
fireEvent.click(pitchDraftButtons[pitchDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/run');
|
||||
expect(await composerText()).toBe('/run');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -476,7 +473,7 @@ export async function assertProjectAndDesignShortcutFlow(
|
||||
([command]) => command === 'list_local_project_export_packages',
|
||||
).length,
|
||||
};
|
||||
submitChat('/demo');
|
||||
await submitChat('/demo');
|
||||
const demoMessages = await screen.findAllByText(/试玩讲解稿:/);
|
||||
const demoMessage = messageBubble(demoMessages[demoMessages.length - 1]);
|
||||
expect(demoMessage.textContent).toContain('项目:未命名游戏原型');
|
||||
@@ -510,7 +507,7 @@ export async function assertProjectAndDesignShortcutFlow(
|
||||
{ name: '启动预览' },
|
||||
);
|
||||
fireEvent.click(demoDraftButtons[demoDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/run');
|
||||
expect(await composerText()).toBe('/run');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -575,7 +572,7 @@ export async function assertProjectAndDesignShortcutFlow(
|
||||
([command]) => command === 'export_local_project_package',
|
||||
).length,
|
||||
};
|
||||
submitChat('/rules');
|
||||
await submitChat('/rules');
|
||||
expect(await screen.findByText(/玩法操作:/)).not.toBeNull();
|
||||
const controlMessages = screen.getAllByText(/玩法操作:/);
|
||||
const controlMessage = messageBubble(
|
||||
@@ -616,8 +613,7 @@ export async function assertProjectAndDesignShortcutFlow(
|
||||
controlMessageList as HTMLElement,
|
||||
).getAllByRole('button', { name: '补充操作说明' });
|
||||
fireEvent.click(controlDraftButtons[controlDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
expect(await composerText()).toBe(
|
||||
'/agent-resume 操作说明:在首屏明确移动/点击操作、胜负目标、失败后重开方式',
|
||||
);
|
||||
expect(
|
||||
@@ -682,7 +678,7 @@ export async function assertProjectAndDesignShortcutFlow(
|
||||
([command]) => command === 'list_local_project_export_packages',
|
||||
).length,
|
||||
};
|
||||
submitChat('/tutorial');
|
||||
await submitChat('/tutorial');
|
||||
const tutorialMessages = await screen.findAllByText(/新手引导:/);
|
||||
const tutorialMessage = messageBubble(
|
||||
tutorialMessages[tutorialMessages.length - 1],
|
||||
@@ -716,8 +712,7 @@ export async function assertProjectAndDesignShortcutFlow(
|
||||
tutorialMessageList as HTMLElement,
|
||||
).getAllByRole('button', { name: '补充新手引导' });
|
||||
fireEvent.click(tutorialDraftButtons[tutorialDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
expect(await composerText()).toBe(
|
||||
'/agent-resume 新手引导:在首屏加入目标、操作、反馈、失败重开提示',
|
||||
);
|
||||
expect(
|
||||
@@ -787,7 +782,7 @@ export async function assertProjectAndDesignShortcutFlow(
|
||||
([command]) => command === 'list_local_project_export_packages',
|
||||
).length,
|
||||
};
|
||||
submitChat('/mobile');
|
||||
await submitChat('/mobile');
|
||||
const mobileMessages = await screen.findAllByText(/移动试玩:/);
|
||||
const mobileMessage = messageBubble(
|
||||
mobileMessages[mobileMessages.length - 1],
|
||||
@@ -824,8 +819,7 @@ export async function assertProjectAndDesignShortcutFlow(
|
||||
mobileMessageList as HTMLElement,
|
||||
).getAllByRole('button', { name: '补充移动试玩' });
|
||||
fireEvent.click(mobileDraftButtons[mobileDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
expect(await composerText()).toBe(
|
||||
'/agent-resume 移动试玩:补充触屏操作、响应式画布、横竖屏提示、重开按钮',
|
||||
);
|
||||
expect(
|
||||
@@ -898,7 +892,7 @@ export async function assertProjectAndDesignShortcutFlow(
|
||||
([command]) => command === 'control_agent_run',
|
||||
).length,
|
||||
};
|
||||
submitChat('/compatibility');
|
||||
await submitChat('/compatibility');
|
||||
const compatibilityMessages = await screen.findAllByText(/兼容性说明:/);
|
||||
const compatibilityMessage = messageBubble(
|
||||
compatibilityMessages[compatibilityMessages.length - 1],
|
||||
@@ -940,7 +934,7 @@ export async function assertProjectAndDesignShortcutFlow(
|
||||
fireEvent.click(
|
||||
compatibilityDraftButtons[compatibilityDraftButtons.length - 1],
|
||||
);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/run');
|
||||
expect(await composerText()).toBe('/run');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -1014,7 +1008,7 @@ export async function assertProjectAndDesignShortcutFlow(
|
||||
([command]) => command === 'control_agent_run',
|
||||
).length,
|
||||
};
|
||||
submitChat('/accessibility');
|
||||
await submitChat('/accessibility');
|
||||
const accessibilityMessages = await screen.findAllByText(/可读性与无障碍:/);
|
||||
const accessibilityMessage = messageBubble(
|
||||
accessibilityMessages[accessibilityMessages.length - 1],
|
||||
@@ -1061,8 +1055,7 @@ export async function assertProjectAndDesignShortcutFlow(
|
||||
fireEvent.click(
|
||||
accessibilityDraftButtons[accessibilityDraftButtons.length - 1],
|
||||
);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
expect(await composerText()).toBe(
|
||||
'/agent-resume 可读性与无障碍:补充文字对比、清晰按钮标签、键盘等价操作、非颜色唯一反馈、静音可玩',
|
||||
);
|
||||
expect(
|
||||
@@ -1138,7 +1131,7 @@ export async function assertProjectAndDesignShortcutFlow(
|
||||
([command]) => command === 'control_agent_run',
|
||||
).length,
|
||||
};
|
||||
submitChat('/localization');
|
||||
await submitChat('/localization');
|
||||
const localizationMessages = await screen.findAllByText(/本地化与文案:/);
|
||||
const localizationMessage = messageBubble(
|
||||
localizationMessages[localizationMessages.length - 1],
|
||||
@@ -1192,10 +1185,7 @@ export async function assertProjectAndDesignShortcutFlow(
|
||||
fireEvent.click(
|
||||
localizationDraftButtons[localizationDraftButtons.length - 1],
|
||||
);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
'/read exports/README.md',
|
||||
);
|
||||
expect(await composerText()).toBe('/read exports/README.md');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -1269,7 +1259,7 @@ export async function assertProjectAndDesignShortcutFlow(
|
||||
([command]) => command === 'control_agent_run',
|
||||
).length,
|
||||
};
|
||||
submitChat('/performance');
|
||||
await submitChat('/performance');
|
||||
const performanceMessages = await screen.findAllByText(/性能与加载:/);
|
||||
const performanceMessage = messageBubble(
|
||||
performanceMessages[performanceMessages.length - 1],
|
||||
@@ -1310,10 +1300,7 @@ export async function assertProjectAndDesignShortcutFlow(
|
||||
performanceMessageList as HTMLElement,
|
||||
).getAllByRole('button', { name: '列出 Run 产物' });
|
||||
fireEvent.click(performanceDraftButtons[performanceDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
'/run-artifacts',
|
||||
);
|
||||
expect(await composerText()).toBe('/run-artifacts');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -1387,7 +1374,7 @@ export async function assertProjectAndDesignShortcutFlow(
|
||||
([command]) => command === 'control_agent_run',
|
||||
).length,
|
||||
};
|
||||
submitChat('/polish');
|
||||
await submitChat('/polish');
|
||||
const polishMessages = await screen.findAllByText(/试玩前打磨:/);
|
||||
const polishMessage = messageBubble(
|
||||
polishMessages[polishMessages.length - 1],
|
||||
@@ -1427,8 +1414,7 @@ export async function assertProjectAndDesignShortcutFlow(
|
||||
polishMessageList as HTMLElement,
|
||||
).getAllByRole('button', { name: '补充打磨' });
|
||||
fireEvent.click(polishDraftButtons[polishDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
expect(await composerText()).toBe(
|
||||
'/agent-resume 打磨:补齐新手引导、触屏操作、可读性、性能、素材署名和试玩反馈',
|
||||
);
|
||||
expect(
|
||||
@@ -1501,7 +1487,7 @@ export async function assertProjectAndDesignShortcutFlow(
|
||||
([command]) => command === 'list_local_project_export_packages',
|
||||
).length,
|
||||
};
|
||||
submitChat('/credits');
|
||||
await submitChat('/credits');
|
||||
const creditMessages = await screen.findAllByText(/素材署名:/);
|
||||
const creditMessage = messageBubble(
|
||||
creditMessages[creditMessages.length - 1],
|
||||
@@ -1527,7 +1513,7 @@ export async function assertProjectAndDesignShortcutFlow(
|
||||
creditMessageList as HTMLElement,
|
||||
).getAllByRole('button', { name: '查看资产' });
|
||||
fireEvent.click(creditDraftButtons[creditDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/assets');
|
||||
expect(await composerText()).toBe('/assets');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
|
||||
+55
-67
@@ -1,4 +1,6 @@
|
||||
import {
|
||||
composerText,
|
||||
composerValue,
|
||||
expect,
|
||||
fireEvent,
|
||||
screen,
|
||||
@@ -35,7 +37,7 @@ export async function assertProjectToolsAndPreviewFlow(
|
||||
([command]) => command === 'export_local_project_package',
|
||||
).length,
|
||||
};
|
||||
submitChat('/feedback');
|
||||
await submitChat('/feedback');
|
||||
const feedbackMessages = await screen.findAllByText(/试玩反馈:/);
|
||||
const feedbackMessage = messageBubble(
|
||||
feedbackMessages[feedbackMessages.length - 1],
|
||||
@@ -60,7 +62,7 @@ export async function assertProjectToolsAndPreviewFlow(
|
||||
feedbackMessageList as HTMLElement,
|
||||
).getAllByRole('button', { name: '启动预览' });
|
||||
fireEvent.click(feedbackDraftButtons[feedbackDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/run');
|
||||
expect(await composerText()).toBe('/run');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -126,7 +128,7 @@ export async function assertProjectToolsAndPreviewFlow(
|
||||
([command]) => command === 'control_agent_run',
|
||||
).length,
|
||||
};
|
||||
submitChat('/retention');
|
||||
await submitChat('/retention');
|
||||
const retentionMessages = await screen.findAllByText(/复玩观察:/);
|
||||
const retentionMessage = messageBubble(
|
||||
retentionMessages[retentionMessages.length - 1],
|
||||
@@ -165,7 +167,7 @@ export async function assertProjectToolsAndPreviewFlow(
|
||||
retentionMessageList as HTMLElement,
|
||||
).getAllByRole('button', { name: '启动试玩' });
|
||||
fireEvent.click(retentionDraftButtons[retentionDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/run');
|
||||
expect(await composerText()).toBe('/run');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -236,7 +238,7 @@ export async function assertProjectToolsAndPreviewFlow(
|
||||
([command]) => command === 'list_local_project_export_packages',
|
||||
).length,
|
||||
};
|
||||
submitChat('/share');
|
||||
await submitChat('/share');
|
||||
const shareMessages = await screen.findAllByText(/试玩交付:/);
|
||||
const shareMessage = messageBubble(shareMessages[shareMessages.length - 1]);
|
||||
expect(shareMessage.textContent).toContain('项目:未命名游戏原型');
|
||||
@@ -260,7 +262,7 @@ export async function assertProjectToolsAndPreviewFlow(
|
||||
shareMessageList as HTMLElement,
|
||||
).getAllByRole('button', { name: '导出试玩包' });
|
||||
fireEvent.click(shareDraftButtons[shareDraftButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/export');
|
||||
expect(await composerText()).toBe('/export');
|
||||
expect(
|
||||
invoke.mock.calls.filter(
|
||||
([command]) => command === 'get_local_game_manifest',
|
||||
@@ -306,39 +308,39 @@ export async function assertProjectToolsAndPreviewFlow(
|
||||
expect(await screen.findByText(/策略:\.agent\/policy\.json/)).not.toBeNull();
|
||||
const composerInput = screen.getByLabelText('创作想法');
|
||||
fireEvent.click(screen.getByRole('button', { name: '索引确认' }));
|
||||
expect(composerInput).toHaveProperty(
|
||||
'value',
|
||||
expect(await composerValue(composerInput)).toBe(
|
||||
'/policy-confirm project.index',
|
||||
);
|
||||
fireEvent.click(screen.getByRole('button', { name: '资产登记确认' }));
|
||||
expect(composerInput).toHaveProperty(
|
||||
'value',
|
||||
expect(await composerValue(composerInput)).toBe(
|
||||
'/policy-confirm asset.register',
|
||||
);
|
||||
fireEvent.click(screen.getByRole('button', { name: '记忆写入确认' }));
|
||||
expect(composerInput).toHaveProperty('value', '/policy-confirm memory.write');
|
||||
expect(await composerValue(composerInput)).toBe(
|
||||
'/policy-confirm memory.write',
|
||||
);
|
||||
fireEvent.click(screen.getByRole('button', { name: '预览确认' }));
|
||||
expect(composerInput).toHaveProperty(
|
||||
'value',
|
||||
expect(await composerValue(composerInput)).toBe(
|
||||
'/policy-confirm preview.start',
|
||||
);
|
||||
fireEvent.click(screen.getByRole('button', { name: '打开预览确认' }));
|
||||
expect(composerInput).toHaveProperty('value', '/policy-confirm preview.open');
|
||||
expect(await composerValue(composerInput)).toBe(
|
||||
'/policy-confirm preview.open',
|
||||
);
|
||||
fireEvent.click(screen.getByRole('button', { name: '停止预览确认' }));
|
||||
expect(composerInput).toHaveProperty('value', '/policy-confirm preview.stop');
|
||||
expect(await composerValue(composerInput)).toBe(
|
||||
'/policy-confirm preview.stop',
|
||||
);
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Agent确认' }));
|
||||
expect(composerInput).toHaveProperty(
|
||||
'value',
|
||||
expect(await composerValue(composerInput)).toBe(
|
||||
'/policy-confirm agent.run_status',
|
||||
);
|
||||
fireEvent.click(screen.getByRole('button', { name: '读对话确认' }));
|
||||
expect(composerInput).toHaveProperty(
|
||||
'value',
|
||||
expect(await composerValue(composerInput)).toBe(
|
||||
'/policy-confirm conversation.read',
|
||||
);
|
||||
fireEvent.click(screen.getByRole('button', { name: '存对话确认' }));
|
||||
expect(composerInput).toHaveProperty(
|
||||
'value',
|
||||
expect(await composerValue(composerInput)).toBe(
|
||||
'/policy-confirm conversation.write',
|
||||
);
|
||||
expect(screen.queryByText('project.policy_write')).toBeNull();
|
||||
@@ -366,7 +368,7 @@ export async function assertProjectToolsAndPreviewFlow(
|
||||
'relativePath' in args &&
|
||||
args.relativePath === 'assets/manifest.art.json',
|
||||
).length;
|
||||
submitChat('/art');
|
||||
await submitChat('/art');
|
||||
expect(await screen.findByText(/美术素材:1 个/)).not.toBeNull();
|
||||
expect(screen.getByText(/来源:画板 1/)).not.toBeNull();
|
||||
expect(
|
||||
@@ -376,8 +378,7 @@ export async function assertProjectToolsAndPreviewFlow(
|
||||
name: '读美术清单',
|
||||
});
|
||||
fireEvent.click(visualDraftButtons[visualDraftButtons.length - 1]);
|
||||
expect(composerInput).toHaveProperty(
|
||||
'value',
|
||||
expect(await composerValue(composerInput)).toBe(
|
||||
'/read assets/manifest.art.json',
|
||||
);
|
||||
expect(
|
||||
@@ -396,7 +397,7 @@ export async function assertProjectToolsAndPreviewFlow(
|
||||
'relativePath' in args &&
|
||||
args.relativePath === 'assets/manifest.audio.json',
|
||||
).length;
|
||||
submitChat('/audio');
|
||||
await submitChat('/audio');
|
||||
expect(await screen.findByText(/音频素材:暂无登记音频/)).not.toBeNull();
|
||||
expect(
|
||||
screen.getByText(/可先登记项目内音效,或把已有画板音频作为素材导入/),
|
||||
@@ -405,8 +406,7 @@ export async function assertProjectToolsAndPreviewFlow(
|
||||
name: '登记音效',
|
||||
});
|
||||
fireEvent.click(audioDraftButtons[audioDraftButtons.length - 1]);
|
||||
expect(composerInput).toHaveProperty(
|
||||
'value',
|
||||
expect(await composerValue(composerInput)).toBe(
|
||||
'/asset-register assets/audio/sfx.wav audio audio/wav',
|
||||
);
|
||||
expect(
|
||||
@@ -431,25 +431,25 @@ export async function assertProjectToolsAndPreviewFlow(
|
||||
name: buttonName,
|
||||
}),
|
||||
);
|
||||
expect(composerInput).toHaveProperty('value', draftValue);
|
||||
expect(await composerValue(composerInput)).toBe(draftValue);
|
||||
await waitFor(() => expect(document.activeElement).toBe(composerInput));
|
||||
}
|
||||
submitChat('/artifacts');
|
||||
await submitChat('/artifacts');
|
||||
expect(await screen.findByText(/常用生成产物:/)).not.toBeNull();
|
||||
expect(screen.getByText(/读入口 · game\/index\.html/)).not.toBeNull();
|
||||
expect(screen.getByText(/读发布说明 · exports\/README\.md/)).not.toBeNull();
|
||||
const readEntryButtons = screen.getAllByRole('button', { name: '读入口' });
|
||||
fireEvent.click(readEntryButtons[readEntryButtons.length - 1]);
|
||||
expect(composerInput).toHaveProperty('value', '/read game/index.html');
|
||||
expect(await composerValue(composerInput)).toBe('/read game/index.html');
|
||||
await waitFor(() => expect(document.activeElement).toBe(composerInput));
|
||||
submitChat('/run-artifacts');
|
||||
await submitChat('/run-artifacts');
|
||||
const runArtifactsHeading =
|
||||
await screen.findByText('最近 Run 产物读取命令:');
|
||||
expect(messageBubble(runArtifactsHeading).textContent).toContain(
|
||||
'exports/README.md · 128B · fnv1a64:exports:/read exports/README.md',
|
||||
);
|
||||
fireEvent.click(screen.getByRole('button', { name: '读取首个 Run 产物' }));
|
||||
expect(composerInput).toHaveProperty('value', '/read exports/README.md');
|
||||
expect(await composerValue(composerInput)).toBe('/read exports/README.md');
|
||||
expect(invoke).not.toHaveBeenCalledWith(
|
||||
'read_local_project_file',
|
||||
expect.objectContaining({
|
||||
@@ -459,7 +459,7 @@ export async function assertProjectToolsAndPreviewFlow(
|
||||
const fileReadCountBeforePasses = invoke.mock.calls.filter(
|
||||
([command]) => command === 'read_local_project_file',
|
||||
).length;
|
||||
submitChat('/passes');
|
||||
await submitChat('/passes');
|
||||
const passArtifactMessages =
|
||||
await screen.findAllByText(/Agent 轮次产物读取命令:/);
|
||||
const passArtifactMessage = messageBubble(
|
||||
@@ -475,8 +475,7 @@ export async function assertProjectToolsAndPreviewFlow(
|
||||
name: '读取首个轮次产物',
|
||||
});
|
||||
fireEvent.click(passArtifactButtons[passArtifactButtons.length - 1]);
|
||||
expect(composerInput).toHaveProperty(
|
||||
'value',
|
||||
expect(await composerValue(composerInput)).toBe(
|
||||
'/read .agent/passes/pass-1/agenda.md',
|
||||
);
|
||||
expect(
|
||||
@@ -484,7 +483,7 @@ export async function assertProjectToolsAndPreviewFlow(
|
||||
([command]) => command === 'read_local_project_file',
|
||||
),
|
||||
).toHaveLength(fileReadCountBeforePasses);
|
||||
submitChat('/logs');
|
||||
await submitChat('/logs');
|
||||
expect(await screen.findByText(/常用日志读取命令:/)).not.toBeNull();
|
||||
expect(
|
||||
screen.getByText(/读命令日志 · \.agent\/logs\/command\.log/),
|
||||
@@ -506,8 +505,7 @@ export async function assertProjectToolsAndPreviewFlow(
|
||||
name: '读命令日志',
|
||||
}),
|
||||
);
|
||||
expect(composerInput).toHaveProperty(
|
||||
'value',
|
||||
expect(await composerValue(composerInput)).toBe(
|
||||
'/read .agent/logs/command.log',
|
||||
);
|
||||
expect(
|
||||
@@ -520,30 +518,28 @@ export async function assertProjectToolsAndPreviewFlow(
|
||||
),
|
||||
).toHaveLength(commandLogReadCountBefore);
|
||||
fireEvent.click(screen.getByRole('button', { name: '打开画板' }));
|
||||
expect(composerInput).toHaveProperty('value', '/canvas ');
|
||||
expect(await composerValue(composerInput)).toBe('/canvas ');
|
||||
await waitFor(() => expect(document.activeElement).toBe(composerInput));
|
||||
fireEvent.click(screen.getByRole('button', { name: '同步画板' }));
|
||||
expect(composerInput).toHaveProperty('value', '/sync-canvas-project ');
|
||||
expect(await composerValue(composerInput)).toBe('/sync-canvas-project ');
|
||||
await waitFor(() => expect(document.activeElement).toBe(composerInput));
|
||||
fireEvent.click(screen.getByRole('button', { name: '生成美术' }));
|
||||
expect(composerInput).toHaveProperty('value', '/generate-art ');
|
||||
expect(await composerValue(composerInput)).toBe('/generate-art ');
|
||||
await waitFor(() => expect(document.activeElement).toBe(composerInput));
|
||||
fireEvent.click(
|
||||
within(screen.getByLabelText('预览快捷操作')).getByRole('button', {
|
||||
name: '登记音效',
|
||||
}),
|
||||
);
|
||||
expect(composerInput).toHaveProperty(
|
||||
'value',
|
||||
expect(await composerValue(composerInput)).toBe(
|
||||
'/asset-register assets/audio/sfx.wav audio audio/wav',
|
||||
);
|
||||
await waitFor(() => expect(document.activeElement).toBe(composerInput));
|
||||
fireEvent.click(screen.getByRole('button', { name: '导入画板资产' }));
|
||||
expect(composerInput).toHaveProperty('value', '/import-canvas-asset ');
|
||||
expect(await composerValue(composerInput)).toBe('/import-canvas-asset ');
|
||||
await waitFor(() => expect(document.activeElement).toBe(composerInput));
|
||||
fireEvent.click(screen.getByRole('button', { name: '导入画板音频' }));
|
||||
expect(composerInput).toHaveProperty(
|
||||
'value',
|
||||
expect(await composerValue(composerInput)).toBe(
|
||||
'/import-canvas-asset assets/audio/sfx.wav ',
|
||||
);
|
||||
await waitFor(() => expect(document.activeElement).toBe(composerInput));
|
||||
@@ -560,8 +556,7 @@ export async function assertProjectToolsAndPreviewFlow(
|
||||
name: '填入读取 assets/uploads/hero.txt',
|
||||
}),
|
||||
);
|
||||
expect(composerInput).toHaveProperty(
|
||||
'value',
|
||||
expect(await composerValue(composerInput)).toBe(
|
||||
'/read assets/uploads/hero.txt',
|
||||
);
|
||||
|
||||
@@ -581,7 +576,7 @@ export async function assertProjectToolsAndPreviewFlow(
|
||||
screen.getByText(/exports\/README\.md · fnv1a64:exports/),
|
||||
).not.toBeNull();
|
||||
fireEvent.click(screen.getByRole('button', { name: '读取首个产物' }));
|
||||
expect(composerInput).toHaveProperty('value', '/read exports/README.md');
|
||||
expect(await composerValue(composerInput)).toBe('/read exports/README.md');
|
||||
expect(invoke).not.toHaveBeenCalledWith('read_local_project_file', {
|
||||
projectPath: '/tmp/authorized-game',
|
||||
relativePath: 'exports/README.md',
|
||||
@@ -601,14 +596,13 @@ export async function assertProjectToolsAndPreviewFlow(
|
||||
name: '填入读取 game/index.html',
|
||||
}),
|
||||
);
|
||||
expect(composerInput).toHaveProperty('value', '/read game/index.html');
|
||||
expect(await composerValue(composerInput)).toBe('/read game/index.html');
|
||||
fireEvent.click(
|
||||
within(screen.getByLabelText('最近项目文件')).getByRole('button', {
|
||||
name: '登记资产 game/index.html',
|
||||
}),
|
||||
);
|
||||
expect(composerInput).toHaveProperty(
|
||||
'value',
|
||||
expect(await composerValue(composerInput)).toBe(
|
||||
'/asset-register game/index.html document text/html',
|
||||
);
|
||||
expect(invoke).not.toHaveBeenCalledWith(
|
||||
@@ -631,11 +625,11 @@ export async function assertProjectToolsAndPreviewFlow(
|
||||
expect(await screen.findByText(/黑板记忆:/)).not.toBeNull();
|
||||
expect(screen.getByText(/跨 agent 共享约束/)).not.toBeNull();
|
||||
fireEvent.click(screen.getByRole('button', { name: '记到黑板' }));
|
||||
expect(composerInput).toHaveProperty('value', '/remember blackboard ');
|
||||
expect(await composerValue(composerInput)).toBe('/remember blackboard ');
|
||||
fireEvent.click(screen.getByRole('button', { name: '覆盖黑板' }));
|
||||
expect(composerInput).toHaveProperty('value', '/memory-set blackboard ');
|
||||
expect(await composerValue(composerInput)).toBe('/memory-set blackboard ');
|
||||
fireEvent.click(screen.getByRole('button', { name: '清空黑板' }));
|
||||
expect(composerInput).toHaveProperty('value', '/forget-memory blackboard');
|
||||
expect(await composerValue(composerInput)).toBe('/forget-memory blackboard');
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '快照' }));
|
||||
expect(await screen.findByText('project.checkpoint')).not.toBeNull();
|
||||
@@ -661,13 +655,13 @@ export async function assertProjectToolsAndPreviewFlow(
|
||||
name: '填入对比 checkpoint-main',
|
||||
}),
|
||||
);
|
||||
expect(composerInput).toHaveProperty('value', '/diff checkpoint-main');
|
||||
expect(await composerValue(composerInput)).toBe('/diff checkpoint-main');
|
||||
fireEvent.click(
|
||||
within(checkpointList).getByRole('button', {
|
||||
name: '填入回滚 checkpoint-main',
|
||||
}),
|
||||
);
|
||||
expect(composerInput).toHaveProperty('value', '/restore checkpoint-main');
|
||||
expect(await composerValue(composerInput)).toBe('/restore checkpoint-main');
|
||||
fireEvent.click(
|
||||
within(checkpointList).getByRole('button', {
|
||||
name: '回滚 checkpoint-main',
|
||||
@@ -717,12 +711,9 @@ export async function assertProjectToolsAndPreviewFlow(
|
||||
name: '显示目录',
|
||||
});
|
||||
fireEvent.click(exportRevealButtons[exportRevealButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
'/open-project',
|
||||
);
|
||||
expect(await composerText()).toBe('/open-project');
|
||||
|
||||
submitChat('/export');
|
||||
await submitChat('/export');
|
||||
await waitFor(() =>
|
||||
expect(screen.getAllByText('准备导出本地试玩包。').length).toBeGreaterThan(
|
||||
1,
|
||||
@@ -733,7 +724,7 @@ export async function assertProjectToolsAndPreviewFlow(
|
||||
);
|
||||
fireEvent.click(screen.getByRole('button', { name: '取消' }));
|
||||
|
||||
submitChat('/exports');
|
||||
await submitChat('/exports');
|
||||
expect(await screen.findByText(/本地试玩包:/)).not.toBeNull();
|
||||
expect(
|
||||
screen.getByText(/exports\/playtest-package-002\.zip · 2048B/),
|
||||
@@ -748,10 +739,7 @@ export async function assertProjectToolsAndPreviewFlow(
|
||||
name: '显示目录',
|
||||
});
|
||||
fireEvent.click(exportListRevealButtons[exportListRevealButtons.length - 1]);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
'/open-project',
|
||||
);
|
||||
expect(await composerText()).toBe('/open-project');
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '启动预览' }));
|
||||
expect(await screen.findByText('preview.start')).not.toBeNull();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
composerText,
|
||||
createGameCreationAppManifest,
|
||||
createGameCreationAppSeedTasks,
|
||||
emptyProjectPolicy,
|
||||
@@ -455,7 +456,7 @@ export function registerProjectRunHistoryTests() {
|
||||
const runReadCountBeforeRunsCommand = invoke.mock.calls.filter(
|
||||
([command]) => command === 'read_local_project_file',
|
||||
).length;
|
||||
submitChat('/runs');
|
||||
await submitChat('/runs');
|
||||
expect(await screen.findByText(/Run 历史读取命令:/)).not.toBeNull();
|
||||
expect(
|
||||
screen.getByText(
|
||||
@@ -463,8 +464,7 @@ export function registerProjectRunHistoryTests() {
|
||||
),
|
||||
).not.toBeNull();
|
||||
fireEvent.click(screen.getByRole('button', { name: '读取首个历史 Run' }));
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
expect(await composerText()).toBe(
|
||||
'/read .agent/runs/run-hidden-from-chat.json',
|
||||
);
|
||||
expect(
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
composerText,
|
||||
createGameCreationAppManifest,
|
||||
createGameCreationAppSeedTasks,
|
||||
emptyProjectPolicy,
|
||||
@@ -162,10 +163,7 @@ export function registerProjectRunStatusTests() {
|
||||
name: '填入读取产物 exports/artifact-1.json',
|
||||
}),
|
||||
);
|
||||
expect(screen.getByLabelText('创作想法')).toHaveProperty(
|
||||
'value',
|
||||
'/read exports/artifact-1.json',
|
||||
);
|
||||
expect(await composerText()).toBe('/read exports/artifact-1.json');
|
||||
fireEvent.click(screen.getByRole('button', { name: '刷新状态' }));
|
||||
|
||||
expect(
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
act,
|
||||
agentRuntimeUserInputRequest,
|
||||
cleanup,
|
||||
composerDisabled,
|
||||
createGameCreationAppManifest,
|
||||
createGameCreationAppSeedTasks,
|
||||
createProjectSupervisorRuntimeHarness,
|
||||
@@ -40,7 +41,7 @@ export function registerSupervisorRuntimeTests() {
|
||||
);
|
||||
});
|
||||
|
||||
submitChat('做一个反弹弹幕厨房游戏');
|
||||
await submitChat('做一个反弹弹幕厨房游戏');
|
||||
|
||||
await waitFor(() => {
|
||||
expect(harness.invoke).toHaveBeenCalledWith(
|
||||
@@ -284,7 +285,7 @@ export function registerSupervisorRuntimeTests() {
|
||||
await openMainProject(harness.projectPath);
|
||||
expect(await screen.findByText('项目总控 Agent · 已完成')).not.toBeNull();
|
||||
|
||||
submitChat('开始真正的新一轮实现');
|
||||
await submitChat('开始真正的新一轮实现');
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
harness.invoke.mock.calls.filter(
|
||||
@@ -429,7 +430,7 @@ export function registerSupervisorRuntimeTests() {
|
||||
),
|
||||
);
|
||||
|
||||
submitChat('切换为自主构建并完成可玩原型');
|
||||
await submitChat('切换为自主构建并完成可玩原型');
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
harness.invoke.mock.calls.filter(
|
||||
@@ -479,7 +480,7 @@ export function registerSupervisorRuntimeTests() {
|
||||
),
|
||||
);
|
||||
|
||||
submitChat('补充:先检查已有素材');
|
||||
await submitChat('补充:先检查已有素材');
|
||||
|
||||
await waitFor(() => {
|
||||
expect(harness.invoke).toHaveBeenCalledWith(
|
||||
@@ -689,9 +690,7 @@ export function registerSupervisorRuntimeTests() {
|
||||
|
||||
const card = await screen.findByLabelText('Needs input');
|
||||
expect(screen.getByText('项目总控 Agent · 需要回答')).not.toBeNull();
|
||||
expect(
|
||||
(screen.getByLabelText('创作想法') as HTMLInputElement).disabled,
|
||||
).toBe(true);
|
||||
expect(await composerDisabled()).toBe(true);
|
||||
expect(screen.getByRole('button', { name: '等待回答' })).not.toBeNull();
|
||||
fireEvent.click(within(card).getByRole('button', { name: /像素风/ }));
|
||||
fireEvent.click(within(card).getByRole('button', { name: '提交回答' }));
|
||||
@@ -1110,7 +1109,7 @@ export function registerSupervisorRuntimeTests() {
|
||||
expect.any(Function),
|
||||
);
|
||||
});
|
||||
submitChat('完成本轮总控任务');
|
||||
await submitChat('完成本轮总控任务');
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
harness.invoke.mock.calls.filter(
|
||||
@@ -1533,7 +1532,7 @@ export function registerSupervisorRuntimeTests() {
|
||||
window.__TAURI__ = { core: { invoke }, event: { listen } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
@@ -1840,13 +1839,13 @@ export function registerSupervisorRuntimeTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
).not.toBeNull();
|
||||
|
||||
submitChat('/generate 做一个反弹弹幕厨房游戏');
|
||||
await submitChat('/generate 做一个反弹弹幕厨房游戏');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
|
||||
expect(
|
||||
@@ -1950,14 +1949,14 @@ export function registerSupervisorRuntimeTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
).not.toBeNull();
|
||||
invoke.mockClear();
|
||||
|
||||
submitChat('/generate 做一个厨房弹幕游戏');
|
||||
await submitChat('/generate 做一个厨房弹幕游戏');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
|
||||
expect(await screen.findByText('生成结果项目路径无效')).not.toBeNull();
|
||||
@@ -2033,13 +2032,13 @@ export function registerSupervisorRuntimeTests() {
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
renderAppAt('/');
|
||||
|
||||
submitChat('/project /tmp/authorized-game');
|
||||
await submitChat('/project /tmp/authorized-game');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
expect(
|
||||
await screen.findByText('已设置本地项目:/tmp/authorized-game'),
|
||||
).not.toBeNull();
|
||||
|
||||
submitChat('/generate 做一个厨房弹幕游戏');
|
||||
await submitChat('/generate 做一个厨房弹幕游戏');
|
||||
fireEvent.click(screen.getByRole('button', { name: '确认' }));
|
||||
|
||||
expect(
|
||||
|
||||
Reference in New Issue
Block a user