Files
Genarrative/src/components/image-editor/useImageCanvasEditorChrome.test.tsx
T
kdletters 8dad52f040 实现画布Agent侧边栏聊天
新增画布Agent会话契约、领域规则、SpacetimeDB元数据表和生成绑定。
新增api-server画布Agent会话CRUD、OSS消息文档读写、SSE消息流和生成工具编排。
新增前端右侧Agent对话面板、会话状态hook、SSE客户端、BFF客户端和相关测试。
调整画布侧栏、任务栏、小地图默认状态和面板互斥交互。
补齐画布Agent、OSS消息存储、SSE收口、后端契约和项目记忆文档。
2026-07-04 12:03:58 +08:00

154 lines
4.9 KiB
TypeScript

/* @vitest-environment jsdom */
import { act, renderHook, waitFor } from '@testing-library/react';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { ApiClientError } from '../../services/apiClient';
import { useImageCanvasEditorChrome } from './useImageCanvasEditorChrome';
const renameEditorProjectMock = vi.hoisted(() => vi.fn());
vi.mock('../../services/image-editor/editorProjectClient', async () => {
const actual = await vi.importActual<
typeof import('../../services/image-editor/editorProjectClient')
>('../../services/image-editor/editorProjectClient');
return {
...actual,
renameEditorProject: renameEditorProjectMock,
};
});
function renderChrome({
openEditorLoginModal = vi.fn(),
}: {
openEditorLoginModal?: (postLoginAction?: (() => void) | null) => void;
} = {}) {
return renderHook(() => useImageCanvasEditorChrome({ openEditorLoginModal }));
}
describe('useImageCanvasEditorChrome', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('renames projects and resets rename state from the saved title', async () => {
renameEditorProjectMock.mockResolvedValueOnce({
projectId: 'project-1',
title: '后端项目名',
viewport: { x: 0, y: 0, scale: 1 },
layers: [],
resources: [],
updatedAt: '2026-06-17T00:00:00.000Z',
});
const { result } = renderChrome();
act(() => {
result.current.setProjectTitle('已有项目');
});
act(() => {
result.current.startProjectRename();
});
expect(result.current.projectRenameValue).toBe('已有项目');
act(() => {
result.current.setProjectRenameValue(' 新项目 ');
});
act(() => {
result.current.submitProjectRename('project-1');
});
expect(result.current.isProjectRenameSaving).toBe(true);
await waitFor(() => {
expect(renameEditorProjectMock).toHaveBeenCalledWith(
'project-1',
'新项目',
);
});
await waitFor(() => {
expect(result.current.isProjectRenameSaving).toBe(false);
});
expect(result.current.projectTitle).toBe('后端项目名');
expect(result.current.projectRenameValue).toBe('后端项目名');
expect(result.current.isRenamingProject).toBe(false);
});
it('validates rename input and opens login on rename auth errors', async () => {
const openEditorLoginModal = vi.fn();
renameEditorProjectMock.mockRejectedValueOnce(
new ApiClientError({
message: '未授权访问',
status: 401,
code: 'UNAUTHORIZED',
}),
);
const { result } = renderChrome({ openEditorLoginModal });
act(() => {
result.current.setProjectRenameValue(' ');
});
act(() => {
result.current.submitProjectRename('project-1');
});
expect(result.current.projectRenameError).toBe('项目名称不能为空');
expect(renameEditorProjectMock).not.toHaveBeenCalled();
act(() => {
result.current.setProjectRenameValue('新项目');
});
act(() => {
result.current.submitProjectRename('project-1');
});
await waitFor(() => {
expect(openEditorLoginModal).toHaveBeenCalledTimes(1);
});
expect(result.current.projectRenameError).toBe('未授权访问');
});
it('manages background colors and chrome panel toggles', () => {
const { result } = renderChrome();
expect(result.current.activeSidebarPanel).toBeNull();
expect(result.current.isMinimapOpen).toBe(false);
act(() => {
result.current.applyCanvasBackgroundColor('#abc');
});
expect(result.current.canvasBackgroundColor).toBe('#aabbcc');
expect(result.current.canvasBackgroundHexValue).toBe('#aabbcc');
act(() => {
result.current.handleCanvasBackgroundHexChange('#not-a-color');
});
expect(result.current.canvasBackgroundColor).toBe('#aabbcc');
expect(result.current.canvasBackgroundHexValue).toBe('#not-a-color');
act(() => {
result.current.handleCanvasBackgroundHexChange('#ffffff');
});
expect(result.current.canvasBackgroundColor).toBe('#ffffff');
expect(result.current.canvasBackgroundHexValue).toBe('#ffffff');
act(() => {
result.current.toggleSidebarPanel('assets');
result.current.toggleSidebarPanel('layers');
result.current.toggleZoomMenu();
result.current.toggleBackgroundSettings();
result.current.toggleMinimap();
result.current.setActiveTool('hand');
});
expect(result.current.activeSidebarPanel).toBe('layers');
expect(result.current.isZoomMenuOpen).toBe(true);
expect(result.current.isBackgroundSettingsOpen).toBe(true);
expect(result.current.isMinimapOpen).toBe(true);
expect(result.current.activeTool).toBe('hand');
act(() => {
result.current.closeEditorChromePanels();
});
expect(result.current.activeSidebarPanel).toBeNull();
expect(result.current.isZoomMenuOpen).toBe(false);
expect(result.current.isBackgroundSettingsOpen).toBe(false);
});
});