diff --git a/apps/ai-game-creator-shell/tests/uiEditorPage.test.ts b/apps/ai-game-creator-shell/tests/uiEditorPage.test.ts index d321a3748..a133f480c 100644 --- a/apps/ai-game-creator-shell/tests/uiEditorPage.test.ts +++ b/apps/ai-game-creator-shell/tests/uiEditorPage.test.ts @@ -13,6 +13,10 @@ import { describe, expect, it, vi } from 'vitest'; vi.mock('@tauri-apps/api/core', () => ({ invoke: vi.fn() })); +vi.mock('@tauri-apps/plugin-clipboard-manager', () => ({ + writeText: vi.fn(), +})); + vi.mock('../src/components/AssetImporter', () => ({ AssetImporter: ({ open }: { open: boolean }) => open ? createElement('div', { role: 'dialog' }, '素材导入器') : null, @@ -24,6 +28,7 @@ vi.mock('../src/components/modal/ThemedModal', () => ({ })); import { invoke } from '@tauri-apps/api/core'; +import { writeText } from '@tauri-apps/plugin-clipboard-manager'; import type { Node as UiNode } from '../src/features/ui-editor/types/Node'; import type { State } from '../src/features/ui-editor/types/State'; @@ -789,17 +794,13 @@ describe('UiEditorPage', () => { fireEvent.click(await screen.findByRole('button', { name: '保存' })); fireEvent.click(await screen.findByRole('button', { name: '仍然保存' })); - expect((await screen.findByRole('alert')).textContent).toContain( + expect((await screen.findByRole('dialog')).textContent).toContain( '保存失败,请稍后重试。', ); - expect(screen.getByRole('alert').textContent).not.toContain( - '临时存储不可用', - ); - expect(screen.getByRole('button', { name: '保存' })).toBeTruthy(); + expect(screen.getByRole('button', { name: '重试保存' })).toBeTruthy(); expect(stateStore.save).toHaveBeenCalledTimes(1); - fireEvent.click(screen.getByRole('button', { name: '保存' })); - fireEvent.click(await screen.findByRole('button', { name: '仍然保存' })); + fireEvent.click(screen.getByRole('button', { name: '重试保存' })); expect(stateStore.save).toHaveBeenCalledTimes(2); }); @@ -823,8 +824,89 @@ describe('UiEditorPage', () => { fireEvent.click(await screen.findByRole('button', { name: '保存' })); fireEvent.click(await screen.findByRole('button', { name: '仍然保存' })); - expect((await screen.findByRole('alert')).textContent).toContain( + expect((await screen.findByRole('dialog')).textContent).toContain( '资源已在别处更新;请重新加载后再保存。', ); }); + + it('shows a generated path modal and copies the project-relative path', async () => { + const stateStore: IUiDesignStateStore = { + load: vi.fn().mockResolvedValue(structuredClone(EMPTY_SNAPSHOT)), + save: vi.fn().mockResolvedValue({ + status: 'saved', + state: structuredClone(EMPTY_SNAPSHOT.state), + revision: 1, + committedProjectRevision: 1, + }), + generateCode: vi.fn().mockResolvedValue({ + relativePath: 'ui/generated-example.js', + treeExports: ['Example'], + treeCount: 1, + nodeCount: 2, + }), + }; + vi.mocked(writeText).mockResolvedValue(undefined); + + render( + createElement(UiEditorPage, { + projectPath: '/tmp/ui-editor', + resourceId: 'ui-resource', + stateStore, + }), + ); + + fireEvent.click( + await screen.findByRole('button', { name: '保存并生成代码' }), + ); + fireEvent.click( + await screen.findByRole('button', { name: '仍然保存并生成' }), + ); + + const dialog = await screen.findByRole('dialog'); + expect(dialog.textContent).toContain('代码已生成'); + expect(dialog.textContent).toContain('ui/generated-example.js'); + + fireEvent.click(screen.getByRole('button', { name: '复制路径' })); + await waitFor(() => + expect(writeText).toHaveBeenCalledWith('ui/generated-example.js'), + ); + expect(screen.getByRole('button', { name: '已复制' })).toBeTruthy(); + }); + + it('shows a manual-copy hint when the native clipboard rejects a path', async () => { + const stateStore: IUiDesignStateStore = { + load: vi.fn().mockResolvedValue(structuredClone(EMPTY_SNAPSHOT)), + save: vi.fn().mockResolvedValue({ + status: 'saved', + state: structuredClone(EMPTY_SNAPSHOT.state), + revision: 1, + committedProjectRevision: 1, + }), + generateCode: vi.fn().mockResolvedValue({ + relativePath: 'ui/generated-example.js', + treeExports: ['Example'], + treeCount: 1, + nodeCount: 2, + }), + }; + vi.mocked(writeText).mockRejectedValue(new Error('clipboard unavailable')); + + render( + createElement(UiEditorPage, { + projectPath: '/tmp/ui-editor', + resourceId: 'ui-resource', + stateStore, + }), + ); + + fireEvent.click( + await screen.findByRole('button', { name: '保存并生成代码' }), + ); + fireEvent.click( + await screen.findByRole('button', { name: '仍然保存并生成' }), + ); + fireEvent.click(await screen.findByRole('button', { name: '复制路径' })); + + expect(await screen.findByText('复制失败,请手动复制路径。')).toBeTruthy(); + }); });