fix merge error
Project CI / Repository checks (pull_request) Successful in 2m11s
Project CI / Frontend tests (pull_request) Successful in 2m11s
Project CI / Native shell tests (pull_request) Successful in 2m46s
Project CI / Backend tests (pull_request) Successful in 3m27s

This commit is contained in:
2026-07-29 15:00:59 +08:00
parent 4a894fd332
commit c826aa0f41
4 changed files with 59 additions and 12 deletions
@@ -20,6 +20,7 @@ import {
dispatchPointerEvent,
ImageCanvasEditorView,
setupImageCanvasEditorViewTestLifecycle,
withEditorProjectCanvasRevision,
} from './ImageCanvasEditorView.test-utils';
function render(ui: Parameters<typeof testingLibraryRender>[0]) {
@@ -870,7 +871,7 @@ describe('ImageCanvasEditorView asset library integration', () => {
it('saves the canvas layout after deleting an asset linked by source resource id', async () => {
const user = userEvent.setup();
loadOrCreateRecentEditorProjectMock.mockResolvedValueOnce({
loadOrCreateRecentEditorProjectMock.mockResolvedValueOnce(withEditorProjectCanvasRevision({
projectId: 'editor-project-default',
title: '生成资源项目',
viewport: { x: 0, y: 0, scale: 1 },
@@ -900,7 +901,7 @@ describe('ImageCanvasEditorView asset library integration', () => {
},
],
updatedAt: '2026-06-12T00:00:00.000Z',
});
}));
loadEditorAssetLibraryMock.mockResolvedValueOnce({
folders: [
{
@@ -971,14 +972,14 @@ describe('ImageCanvasEditorView asset library integration', () => {
height: 240,
sourceType: 'uploaded',
});
loadOrCreateRecentEditorProjectMock.mockResolvedValueOnce({
loadOrCreateRecentEditorProjectMock.mockResolvedValueOnce(withEditorProjectCanvasRevision({
projectId: 'editor-project-default',
title: '空画布项目',
viewport: { x: 0, y: 0, scale: 1 },
layers: [],
resources: [],
updatedAt: '2026-06-12T00:00:00.000Z',
});
}));
loadEditorAssetLibraryMock.mockResolvedValueOnce({
folders: [
{
@@ -410,6 +410,7 @@ describe('ImageCanvasEditorView generation integration', () => {
project: {
projectId: input.projectId,
title: '默认项目',
canvas: { revision: 1 },
viewport: { x: 0, y: 0, scale: 1 },
resources: [
...projectResources,
@@ -477,6 +478,7 @@ describe('ImageCanvasEditorView generation integration', () => {
loadOrCreateRecentEditorProjectMock.mockResolvedValueOnce({
projectId: 'editor-project-generated-dialog',
title: '已生成画布',
canvas: { revision: 0 },
viewport: { x: 0, y: 0, scale: 1 },
layers: [
{
@@ -546,6 +548,7 @@ describe('ImageCanvasEditorView generation integration', () => {
loadOrCreateRecentEditorProjectMock.mockResolvedValueOnce({
projectId: 'editor-project-generated-layer-only',
title: '已生成画布',
canvas: { revision: 0 },
viewport: { x: 0, y: 0, scale: 1 },
layers: [
{
@@ -600,6 +603,7 @@ describe('ImageCanvasEditorView generation integration', () => {
loadOrCreateRecentEditorProjectMock.mockResolvedValueOnce({
projectId: 'editor-project-uploaded-tagged-layer',
title: '标签素材画布',
canvas: { revision: 0 },
viewport: { x: 0, y: 0, scale: 1 },
layers: [
{
@@ -645,6 +649,7 @@ describe('ImageCanvasEditorView generation integration', () => {
loadOrCreateRecentEditorProjectMock.mockResolvedValueOnce({
projectId: 'editor-project-context-tagged-layer',
title: '右键标签素材画布',
canvas: { revision: 0 },
viewport: { x: 0, y: 0, scale: 1 },
layers: [
{
@@ -695,6 +700,7 @@ describe('ImageCanvasEditorView generation integration', () => {
loadOrCreateRecentEditorProjectMock.mockResolvedValueOnce({
projectId: 'editor-project-publication-dialog',
title: '宣发画布',
canvas: { revision: 0 },
viewport: { x: 0, y: 0, scale: 1 },
layers: [
{
@@ -1322,6 +1328,7 @@ describe('ImageCanvasEditorView generation integration', () => {
loadOrCreateRecentEditorProjectMock.mockResolvedValueOnce({
projectId: 'editor-project-icons-generating',
title: '图标素材生成中画布',
canvas: { revision: 0 },
viewport: { x: 0, y: 0, scale: 1 },
layers: [
{
@@ -1694,6 +1701,7 @@ describe('ImageCanvasEditorView generation integration', () => {
loadOrCreateRecentEditorProjectMock.mockResolvedValueOnce({
projectId: 'editor-project-default',
title: '默认项目',
canvas: { revision: 0 },
viewport: { x: 0, y: 0, scale: 1 },
layers: rememberedProjectLayers,
resources: rememberedProjectResources,
@@ -2329,6 +2337,7 @@ describe('ImageCanvasEditorView generation integration', () => {
loadOrCreateRecentEditorProjectMock.mockResolvedValueOnce({
projectId: 'editor-project-default',
title: '默认项目',
canvas: { revision: 0 },
viewport: { x: 0, y: 0, scale: 1 },
layers: characterReferenceProjectLayers,
resources: characterReferenceProjectResources,
@@ -2506,6 +2515,7 @@ describe('ImageCanvasEditorView generation integration', () => {
loadOrCreateRecentEditorProjectMock.mockResolvedValueOnce({
projectId: 'editor-project-icons',
title: '图标素材画布',
canvas: { revision: 0 },
viewport: { x: 0, y: 0, scale: 1 },
layers: [
{
@@ -2681,6 +2691,7 @@ describe('ImageCanvasEditorView generation integration', () => {
loadOrCreateRecentEditorProjectMock.mockResolvedValueOnce({
projectId: 'editor-project-icon-library-refresh',
title: '图标素材刷新画布',
canvas: { revision: 0 },
viewport: { x: 0, y: 0, scale: 1 },
layers: [
{
@@ -2826,6 +2837,7 @@ describe('ImageCanvasEditorView generation integration', () => {
loadOrCreateRecentEditorProjectMock.mockResolvedValueOnce({
projectId,
title: '刷新恢复画布',
canvas: { revision: 0 },
viewport: { x: 0, y: 0, scale: 1 },
layers: [
{
@@ -2868,6 +2880,7 @@ describe('ImageCanvasEditorView generation integration', () => {
loadEditorProjectMock.mockResolvedValueOnce({
projectId,
title: '刷新恢复画布',
canvas: { revision: 0 },
viewport: { x: 0, y: 0, scale: 1 },
layers: [
{
@@ -3136,6 +3149,7 @@ describe('ImageCanvasEditorView generation integration', () => {
loadOrCreateRecentEditorProjectMock.mockResolvedValueOnce({
projectId: 'editor-project-character-animation',
title: '角色动画画布',
canvas: { revision: 0 },
viewport: { x: 0, y: 0, scale: 1 },
layers: [
{
@@ -3363,6 +3377,7 @@ describe('ImageCanvasEditorView generation integration', () => {
loadOrCreateRecentEditorProjectMock.mockResolvedValueOnce({
projectId: 'editor-project-ui-extract',
title: 'UI素材提取画布',
canvas: { revision: 0 },
viewport: { x: 0, y: 0, scale: 1 },
layers: [
{
@@ -3536,6 +3551,7 @@ describe('ImageCanvasEditorView generation integration', () => {
loadOrCreateRecentEditorProjectMock.mockResolvedValueOnce({
projectId: 'editor-project-ui-extract-dismiss',
title: 'UI素材提取外部关闭画布',
canvas: { revision: 0 },
viewport: { x: 0, y: 0, scale: 1 },
layers: [
{
@@ -4,6 +4,11 @@ import type { ContextType } from 'react';
import { afterEach, beforeEach, expect, type Mock, vi } from 'vitest';
import { ApiClientError } from '../../services/apiClient';
import type {
EditorProjectLayerSnapshot,
EditorProjectResourceSnapshot,
EditorProjectSnapshot,
} from '../../services/image-editor/editorProjectClient';
import { AuthUiContext } from '../auth/AuthUiContext';
import { ImageCanvasEditorView } from './ImageCanvasEditorView';
@@ -73,7 +78,7 @@ export const defaultEditorProjectResources = [
height: 405,
sourceType: 'uploaded',
},
];
] satisfies EditorProjectResourceSnapshot[];
export const defaultEditorProjectLayers = [
{
@@ -102,7 +107,31 @@ export const defaultEditorProjectLayers = [
zIndex: 2,
sourceType: 'uploaded',
},
];
] satisfies EditorProjectLayerSnapshot[];
export function withEditorProjectCanvasRevision<
T extends EditorProjectSnapshot,
>(project: T, revision = 0): T {
if (typeof project.canvas?.revision === 'number') {
return project;
}
return {
...project,
canvas: {
canvasId:
project.canvas?.canvasId ?? `${project.projectId}:canvas:default`,
projectId: project.projectId,
title: project.canvas?.title ?? '默认画布',
viewport: project.canvas?.viewport ?? project.viewport,
layers: project.canvas?.layers ?? project.layers,
revision,
layoutStorageVersion: project.canvas?.layoutStorageVersion ?? 0,
backgroundColor: project.canvas?.backgroundColor,
createdAt: project.canvas?.createdAt,
updatedAt: project.canvas?.updatedAt ?? project.updatedAt,
},
};
}
export const defaultEditorAssetLibraryAssets = [
{
@@ -235,14 +264,14 @@ export function setupImageCanvasEditorViewTestLifecycle({
window.sessionStorage.clear();
vi.spyOn(HTMLCanvasElement.prototype, 'getContext').mockReturnValue(null);
loadOrCreateRecentEditorProjectMock.mockImplementation(() =>
immediateAsync({
immediateAsync(withEditorProjectCanvasRevision({
projectId: 'editor-project-default',
title: '默认项目',
viewport: { x: 0, y: 0, scale: 1 },
layers: defaultEditorProjectLayers,
resources: defaultEditorProjectResources,
updatedAt: '2026-06-12T00:00:00.000Z',
}),
})),
);
loadEditorAssetLibraryMock.mockImplementation(() =>
immediateAsync({
@@ -26,6 +26,7 @@ import {
immediateAsync,
readZipText,
setupImageCanvasEditorViewTestLifecycle,
withEditorProjectCanvasRevision,
} from './ImageCanvasEditorView.test-utils';
type EditorAgentListConversations =
@@ -457,14 +458,14 @@ describe('ImageCanvasEditorView', () => {
});
it('shows the toolbar guide for a newly created blank project until a generator opens', async () => {
loadEditorProjectMock.mockResolvedValueOnce({
loadEditorProjectMock.mockResolvedValueOnce(withEditorProjectCanvasRevision({
projectId: 'editor-project-guide',
title: '空白项目',
viewport: { x: 0, y: 0, scale: 1 },
layers: [],
resources: [],
updatedAt: '2026-06-12T00:00:00.000Z',
});
}));
window.history.replaceState(
null,
'',
@@ -505,14 +506,14 @@ describe('ImageCanvasEditorView', () => {
});
it('opens the requested canvas startup tool from the project query once', async () => {
loadEditorProjectMock.mockResolvedValueOnce({
loadEditorProjectMock.mockResolvedValueOnce(withEditorProjectCanvasRevision({
projectId: 'editor-project-music',
title: '音乐项目',
viewport: { x: 0, y: 0, scale: 1 },
layers: [],
resources: [],
updatedAt: '2026-06-12T00:00:00.000Z',
});
}));
window.history.replaceState(
null,
'',