Files
Genarrative/src/components/image-editor/ImageCanvasPanelDockView.test.tsx
T
menghao 03a4410272
Project CI / Repository checks (push) Successful in 1m5s
Project CI / Frontend tests (push) Successful in 3m20s
Project CI / Backend tests (push) Successful in 4m1s
Project CI / Native shell tests (push) Failing after 11m56s
game agent无限画布开发 (#136)
主要工作是共享同一套“画布内核与通用 UI 源码”,网站和 Tauri 只分别实现宿主适配层。

---------

Co-authored-by: 段舒康 <kdletters@qq.com>
Co-authored-by: kdletters <kdletters@qq.com>
Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/136
Co-authored-by: menghao <mh18530625731@163.com>
Co-committed-by: menghao <mh18530625731@163.com>
2026-08-12 10:54:16 +08:00

237 lines
8.0 KiB
TypeScript

/* @vitest-environment jsdom */
import { fireEvent, render, screen, within } from '@testing-library/react';
import { describe, expect, it, vi } from 'vitest';
import type { StageMinimapModel } from './ImageCanvasInteractionModel';
import { ImageCanvasPanelDockView } from './ImageCanvasPanelDockView';
function renderPanelDock(
overrides: Partial<Parameters<typeof ImageCanvasPanelDockView>[0]> = {},
) {
const props: Parameters<typeof ImageCanvasPanelDockView>[0] = {
viewport: { x: 0, y: 0, scale: 1 },
canvasBackgroundColor: '#f8fafc',
canvasBackgroundHexValue: '#f8fafc',
canUndo: true,
canRedo: true,
isZoomMenuOpen: false,
isBackgroundSettingsOpen: false,
activeSidebarPanel: null,
isAgentConversationEnabled: true,
isAgentConversationOpen: false,
isMinimapOpen: false,
minimapModel: null,
onFitLayers: vi.fn(),
onUndoCanvasChange: vi.fn(),
onRedoCanvasChange: vi.fn(),
onUpdateScaleFromCenter: vi.fn(),
onToggleZoomMenu: vi.fn(),
onCloseZoomMenu: vi.fn(),
onToggleBackgroundSettings: vi.fn(),
onApplyCanvasBackgroundColor: vi.fn(),
onCanvasBackgroundHexChange: vi.fn(),
onToggleSidebarPanel: vi.fn(),
onToggleAgentConversation: vi.fn(),
onToggleMinimap: vi.fn(),
onMinimapPointerDown: vi.fn(),
...overrides,
};
render(<ImageCanvasPanelDockView {...props} />);
return props;
}
function mockElementRect(
element: Element,
rect: Pick<DOMRect, 'left' | 'top' | 'width' | 'height'>,
) {
Object.defineProperty(element, 'getBoundingClientRect', {
configurable: true,
value: () => ({
...rect,
right: rect.left + rect.width,
bottom: rect.top + rect.height,
x: rect.left,
y: rect.top,
toJSON: () => ({}),
}),
});
}
describe('ImageCanvasPanelDockView', () => {
it('renders panel dock actions and forwards common controls', () => {
const props = renderPanelDock({
activeSidebarPanel: 'assets',
isMinimapOpen: true,
minimapModel: {
bounds: { minX: 0, minY: 0, maxX: 100, maxY: 100 },
scale: 1,
layers: [],
viewport: { left: '10%', top: '12%', width: '20%', height: '24%' },
} satisfies StageMinimapModel,
});
const toolbar = screen.getByRole('toolbar', { name: '画布面板入口' });
expect(toolbar.className).toContain(
'image-canvas-editor__panel-dock--sidebar-open',
);
expect(
within(toolbar)
.getByRole('button', { name: '打开素材' })
.getAttribute('aria-pressed'),
).toBe('true');
expect(within(toolbar).getByRole('button', { name: '恢复' })).toBeTruthy();
expect(screen.getByRole('button', { name: '画布小地图' })).toBeTruthy();
fireEvent.click(screen.getByRole('button', { name: '重置画布视图' }));
fireEvent.click(within(toolbar).getByRole('button', { name: '撤销' }));
fireEvent.click(within(toolbar).getByRole('button', { name: '恢复' }));
fireEvent.click(within(toolbar).getByRole('button', { name: '打开图层' }));
fireEvent.click(
within(toolbar).getByRole('button', { name: '画布 Agent' }),
);
fireEvent.click(
within(toolbar).getByRole('button', { name: '切换小地图' }),
);
expect(props.onFitLayers).toHaveBeenCalledTimes(1);
expect(props.onUndoCanvasChange).toHaveBeenCalledTimes(1);
expect(props.onRedoCanvasChange).toHaveBeenCalledTimes(1);
expect(props.onToggleSidebarPanel).toHaveBeenCalledWith('layers');
expect(props.onToggleAgentConversation).toHaveBeenCalledTimes(1);
expect(props.onToggleMinimap).toHaveBeenCalledTimes(1);
});
it('hides the Agent entry when the Agent sidebar is disabled', () => {
renderPanelDock({ isAgentConversationEnabled: false });
expect(screen.queryByRole('button', { name: '画布 Agent' })).toBeNull();
});
it('keeps the background picker visible when the selected color is white', () => {
const props = renderPanelDock({
canvasBackgroundColor: '#ffffff',
canvasBackgroundHexValue: '#ffffff',
isBackgroundSettingsOpen: true,
});
const panel = screen.getByRole('dialog', { name: '画布背景设置' });
expect(
screen
.getByRole('button', { name: '画布背景色' })
.getAttribute('aria-expanded'),
).toBe('true');
const spectrumButton = within(panel).getByRole('button', {
name: '画布背景色盘',
});
const hueButton = within(panel).getByRole('button', {
name: '画布背景色相',
});
const spectrumHandle = spectrumButton.querySelector(
'.image-canvas-editor__background-spectrum-handle',
) as HTMLElement;
const hueHandle = hueButton.querySelector(
'.image-canvas-editor__background-hue-handle',
) as HTMLElement;
expect(
spectrumButton.style.getPropertyValue(
'--image-canvas-background-hue-color',
),
).toBe('#0080ff');
expect(
spectrumHandle.style.getPropertyValue(
'--image-canvas-background-spectrum-handle-left',
),
).toBe('clamp(0.42rem, 0%, calc(100% - 0.42rem))');
expect(
spectrumHandle.style.getPropertyValue(
'--image-canvas-background-spectrum-handle-top',
),
).toBe('clamp(0.42rem, 0%, calc(100% - 0.42rem))');
expect(
hueHandle.style.getPropertyValue(
'--image-canvas-background-hue-handle-left',
),
).toBe(
'clamp(0.39rem, 58.333333333333336%, calc(100% - 0.39rem))',
);
mockElementRect(hueButton, {
left: 0,
top: 0,
width: 100,
height: 20,
});
fireEvent.pointerDown(hueButton, {
pointerId: 1,
buttons: 1,
clientX: 20,
clientY: 10,
});
expect(props.onApplyCanvasBackgroundColor).toHaveBeenCalledWith('#ffffff');
});
it('renders zoom and background settings with callback wiring', () => {
const props = renderPanelDock({
viewport: { x: 0, y: 0, scale: 0.5 },
canvasBackgroundColor: '#ff0000',
canvasBackgroundHexValue: '#ff0000',
isZoomMenuOpen: true,
isBackgroundSettingsOpen: true,
});
expect(
screen.getByRole('button', { name: '当前缩放比例 100%' }),
).toBeTruthy();
fireEvent.click(screen.getByRole('menuitem', { name: '缩放至50%' }));
fireEvent.click(screen.getByRole('menuitem', { name: '缩放至100%' }));
fireEvent.click(screen.getByRole('menuitem', { name: '缩放至200%' }));
fireEvent.click(screen.getByRole('menuitem', { name: '显示画布所有元素' }));
expect(props.onUpdateScaleFromCenter).toHaveBeenCalledWith(0.25);
expect(props.onUpdateScaleFromCenter).toHaveBeenCalledWith(0.5);
expect(props.onUpdateScaleFromCenter).toHaveBeenCalledWith(1);
expect(props.onFitLayers).toHaveBeenCalledTimes(1);
expect(props.onCloseZoomMenu).toHaveBeenCalledTimes(4);
const panel = screen.getByRole('dialog', { name: '画布背景设置' });
expect(panel.querySelector('input[type="color"]')).toBeNull();
fireEvent.click(within(panel).getByRole('button', { name: '暖灰' }));
const spectrumButton = within(panel).getByRole('button', {
name: '画布背景色盘',
});
mockElementRect(spectrumButton, {
left: 0,
top: 0,
width: 100,
height: 100,
});
fireEvent.pointerDown(spectrumButton, {
pointerId: 1,
buttons: 1,
clientX: 50,
clientY: 50,
});
fireEvent.change(within(panel).getByLabelText('画布背景十六进制颜色'), {
target: { value: '#abc' },
});
fireEvent.click(within(panel).getByRole('button', { name: '恢复默认' }));
fireEvent.click(
within(panel).getByRole('button', { name: '关闭画布背景设置' }),
);
expect(props.onApplyCanvasBackgroundColor).toHaveBeenCalledWith('#f3f0ea');
expect(props.onApplyCanvasBackgroundColor).toHaveBeenCalledWith('#804040');
expect(props.onCanvasBackgroundHexChange).toHaveBeenCalledWith('#abc');
expect(props.onApplyCanvasBackgroundColor).toHaveBeenCalledWith('#f8fafc');
expect(props.onToggleBackgroundSettings).toHaveBeenCalledTimes(1);
});
});