补充 UI 编辑器保存结果测试

覆盖保存和生成成功弹窗与项目相对路径复制

覆盖保存失败、冲突和剪贴板失败反馈
This commit is contained in:
2026-09-14 18:52:38 +08:00
parent 27859d3e19
commit 9cfb47d945
@@ -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();
});
});