新增图片画布项目页
新增 /project 项目页和我的页项目入口 补齐图片画布工程列表、重命名和删除 API 支持 /editor/canvas 按 projectid 加载指定工程 更新图片画布文档、TRACKING 和对应测试
This commit is contained in:
@@ -2,13 +2,15 @@
|
||||
|
||||
import { fireEvent, render, screen, waitFor, within } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { ApiClientError } from '../../services/apiClient';
|
||||
import { ImageCanvasEditorView } from './ImageCanvasEditorView';
|
||||
|
||||
const generateEditorImageMock = vi.hoisted(() => vi.fn());
|
||||
const editEditorImageMock = vi.hoisted(() => vi.fn());
|
||||
const loadEditorProjectMock = vi.hoisted(() => vi.fn());
|
||||
const loadOrCreateRecentEditorProjectMock = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock('../../services/image-editor/editorProjectClient', async () => {
|
||||
const actual = await vi.importActual<
|
||||
@@ -18,6 +20,8 @@ vi.mock('../../services/image-editor/editorProjectClient', async () => {
|
||||
...actual,
|
||||
editEditorImage: editEditorImageMock,
|
||||
generateEditorImage: generateEditorImageMock,
|
||||
loadEditorProject: loadEditorProjectMock,
|
||||
loadOrCreateRecentEditorProject: loadOrCreateRecentEditorProjectMock,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -36,10 +40,47 @@ function dispatchPointerEvent(
|
||||
}
|
||||
|
||||
describe('ImageCanvasEditorView', () => {
|
||||
beforeEach(() => {
|
||||
loadOrCreateRecentEditorProjectMock.mockResolvedValue({
|
||||
projectId: 'editor-project-default',
|
||||
title: '默认项目',
|
||||
viewport: { x: 0, y: 0, scale: 1 },
|
||||
layers: [],
|
||||
resources: [],
|
||||
updatedAt: '2026-06-12T00:00:00.000Z',
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
generateEditorImageMock.mockReset();
|
||||
editEditorImageMock.mockReset();
|
||||
loadEditorProjectMock.mockReset();
|
||||
loadOrCreateRecentEditorProjectMock.mockReset();
|
||||
window.history.replaceState(null, '', '/editor/canvas');
|
||||
});
|
||||
|
||||
it('loads the project from projectid query before falling back to recent project', async () => {
|
||||
loadEditorProjectMock.mockResolvedValueOnce({
|
||||
projectId: 'editor-project-query',
|
||||
title: '查询项目',
|
||||
viewport: { x: 12, y: 16, scale: 0.8 },
|
||||
layers: [],
|
||||
resources: [],
|
||||
updatedAt: '2026-06-12T00:00:00.000Z',
|
||||
});
|
||||
window.history.replaceState(
|
||||
null,
|
||||
'',
|
||||
'/editor/canvas?projectid=editor-project-query',
|
||||
);
|
||||
|
||||
render(<ImageCanvasEditorView />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(loadEditorProjectMock).toHaveBeenCalledWith('editor-project-query');
|
||||
});
|
||||
expect(loadOrCreateRecentEditorProjectMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('toggles the shared sidebar from canvas panel buttons', () => {
|
||||
@@ -196,6 +237,9 @@ describe('ImageCanvasEditorView', () => {
|
||||
value: createObjectUrlSpy,
|
||||
});
|
||||
render(<ImageCanvasEditorView />);
|
||||
await waitFor(() => {
|
||||
expect(loadOrCreateRecentEditorProjectMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
const bottomToolbar = screen.getByRole('toolbar', { name: 'AI画布工具栏' });
|
||||
|
||||
@@ -344,11 +388,15 @@ describe('ImageCanvasEditorView', () => {
|
||||
await waitFor(() => {
|
||||
expect(screen.getByAltText(/画布图片:生成图片/)).toBeTruthy();
|
||||
});
|
||||
const generatedLayer = screen.getByAltText(/画布图片:生成图片/).closest('button')!;
|
||||
const anchoredGenerateDialog = screen.getByRole('dialog', { name: '生成图片' });
|
||||
expect(anchoredGenerateDialog).toBeTruthy();
|
||||
expect(
|
||||
Number.parseFloat((anchoredGenerateDialog as HTMLElement).style.top),
|
||||
).toBeCloseTo(initialComposerTop, 1);
|
||||
).toBeGreaterThan(Number.parseFloat((generatedLayer as HTMLElement).style.top));
|
||||
expect(
|
||||
Number.parseFloat((generatedLayer as HTMLElement).style.top),
|
||||
).toBeLessThan(initialComposerTop);
|
||||
expect(screen.queryByLabelText('图像生成占位图')).toBeNull();
|
||||
const metadataButtons = screen.getAllByRole('button', {
|
||||
name: /查看生成图片 .*元数据/,
|
||||
@@ -369,6 +417,9 @@ describe('ImageCanvasEditorView', () => {
|
||||
taskId: 'editor-drag-frame-1',
|
||||
});
|
||||
render(<ImageCanvasEditorView />);
|
||||
await waitFor(() => {
|
||||
expect(loadOrCreateRecentEditorProjectMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '生成工具' }));
|
||||
const initialComposerTop = Number.parseFloat(
|
||||
@@ -409,10 +460,10 @@ describe('ImageCanvasEditorView', () => {
|
||||
expect(anchoredGenerateDialog).toBeTruthy();
|
||||
expect(
|
||||
Number.parseFloat((anchoredGenerateDialog as HTMLElement).style.top),
|
||||
).toBeCloseTo(draggedComposerTop, 1);
|
||||
).toBeGreaterThan(Number.parseFloat((generatedLayer as HTMLElement).style.top));
|
||||
expect(screen.queryByLabelText('图像生成占位图')).toBeNull();
|
||||
expect(Number.parseFloat((generatedLayer as HTMLElement).style.left)).toBeGreaterThan(700);
|
||||
expect(Number.parseFloat((generatedLayer as HTMLElement).style.top)).toBeGreaterThan(150);
|
||||
expect(Number.parseFloat((generatedLayer as HTMLElement).style.left)).toBeGreaterThan(300);
|
||||
expect(Number.parseFloat((generatedLayer as HTMLElement).style.top)).toBeGreaterThan(180);
|
||||
});
|
||||
|
||||
it('keeps the generation composer when selecting another image', () => {
|
||||
|
||||
Reference in New Issue
Block a user