补充画布测试交互事件导入

This commit is contained in:
2026-07-19 18:56:31 +08:00
parent e7279166c9
commit 46db6055fa
@@ -1,6 +1,6 @@
/* @vitest-environment jsdom */
import { act, render, screen } from '@testing-library/react';
import { act, fireEvent, render, screen } from '@testing-library/react';
import {
type PointerEvent as ReactPointerEvent,
useRef,
@@ -309,7 +309,10 @@ function StageInteractionsHarness({
</span>
<span data-testid="layers">
{layers
.map((layer) => `${layer.id}:${layer.x.toFixed(1)},${layer.y.toFixed(1)}`)
.map(
(layer) =>
`${layer.id}:${layer.x.toFixed(1)},${layer.y.toFixed(1)}`,
)
.join('|')}
</span>
<span data-testid="viewport-state">
@@ -323,7 +326,9 @@ function StageInteractionsHarness({
<span data-testid="panning">{String(interaction.isPanning)}</span>
<span data-testid="tool">{interaction.effectiveTool}</span>
<span data-testid="snap">
{interaction.snapGuide?.vertical ?? interaction.snapGuide?.horizontal ?? '-'}
{interaction.snapGuide?.vertical ??
interaction.snapGuide?.horizontal ??
'-'}
</span>
<span data-testid="dialog-position">
{generateDialog?.placeholder
@@ -337,9 +342,7 @@ function StageInteractionsHarness({
{String(generateDialog?.composerOpen ?? false)}
</span>
<span data-testid="clear-count">{clearCount}</span>
<span data-testid="image-menu-close-count">
{imageMenuCloseCount}
</span>
<span data-testid="image-menu-close-count">{imageMenuCloseCount}</span>
<button
type="button"
onClick={() => {
@@ -688,6 +691,86 @@ function StageInteractionsHarness({
>
</button>
<button
type="button"
onClick={(event) => {
interaction.handleLayerPointerDown(
createPointerEvent(event.currentTarget, {
pointerId: 20,
clientX: 40,
clientY: 40,
button: 2,
buttons: 2,
}),
firstLayer,
);
}}
>
</button>
<button
type="button"
onClick={(event) => {
setActiveTool('hand');
interaction.handleLayerPointerDown(
createPointerEvent(event.currentTarget, {
pointerId: 21,
clientX: 40,
clientY: 40,
button: 2,
buttons: 2,
}),
firstLayer,
);
}}
>
</button>
<button
type="button"
onClick={(event) => {
const frameElement = document.createElement('div');
const dialog = asCanvasGenerationDialog(generateDialog);
if (!dialog) {
return;
}
interaction.handleGenerationFramePointerDown(
createPointerEvent(frameElement, {
pointerId: 22,
clientX: 300,
clientY: 200,
button: 2,
buttons: 2,
}),
dialog,
);
}}
>
</button>
<button
type="button"
onClick={(event) => {
setActiveTool('hand');
const frameElement = document.createElement('div');
const dialog = asCanvasGenerationDialog(generateDialog);
if (!dialog) {
return;
}
interaction.handleGenerationFramePointerDown(
createPointerEvent(frameElement, {
pointerId: 23,
clientX: 300,
clientY: 200,
button: 2,
buttons: 2,
}),
dialog,
);
}}
>
</button>
</div>
);
}
@@ -778,7 +861,9 @@ describe('useImageCanvasStageInteractions', () => {
act(() => {
screen.getByRole('button', { name: '直接移动平移' }).click();
});
expect(screen.getByTestId('viewport-state').textContent).toBe('30.0,25.0,1');
expect(screen.getByTestId('viewport-state').textContent).toBe(
'30.0,25.0,1',
);
act(() => {
screen.getByRole('button', { name: '清理交互' }).click();
});
@@ -800,9 +885,7 @@ describe('useImageCanvasStageInteractions', () => {
render(<StageInteractionsHarness />);
act(() => {
screen
.getByRole('button', { name: '直接贴近图层拖生成占位' })
.click();
screen.getByRole('button', { name: '直接贴近图层拖生成占位' }).click();
});
expect(screen.getByTestId('dialog-position').textContent).toBe(
@@ -844,8 +927,9 @@ describe('useImageCanvasStageInteractions', () => {
act(() => {
screen.getByRole('button', { name: '直接追加生成器' }).click();
});
const generationSelectionId =
screen.getByTestId('dialog-selection-id').textContent;
const generationSelectionId = screen.getByTestId(
'dialog-selection-id',
).textContent;
expect(screen.getByTestId('selection').textContent).toBe(
`first:first,${generationSelectionId}`,
);
@@ -921,15 +1005,15 @@ describe('useImageCanvasStageInteractions', () => {
expect(onViewportInteractionEnd).toHaveBeenCalledTimes(2);
});
it('allows middle-button dragging and rejects right-button dragging', () => {
it('allows middle-button dragging and rejects right-button dragging in select, hand, and Space modes', () => {
render(<StageInteractionsHarness />);
const viewport = screen.getByTestId('viewport');
act(() => {
fireEvent(
viewport,
new MouseEvent('pointerdown',{
viewport,
new MouseEvent('pointerdown', {
bubbles: true,
clientX: 100,
clientY: 100,
@@ -942,8 +1026,8 @@ describe('useImageCanvasStageInteractions', () => {
act(() => {
fireEvent(
viewport,
new MouseEvent('pointerup',{
viewport,
new MouseEvent('pointerup', {
bubbles: true,
clientX: 100,
clientY: 100,
@@ -956,8 +1040,49 @@ describe('useImageCanvasStageInteractions', () => {
act(() => {
fireEvent(
viewport,
new MouseEvent('pointerdown',{
viewport,
new MouseEvent('pointerdown', {
bubbles: true,
clientX: 100,
clientY: 100,
button: 2,
buttons: 2,
}),
);
});
expect(screen.getByTestId('panning').textContent).toBe('false');
act(() => {
screen.getByRole('button', { name: '切抓手' }).click();
});
expect(screen.getByTestId('tool').textContent).toBe('hand');
act(() => {
fireEvent(
viewport,
new MouseEvent('pointerdown', {
bubbles: true,
clientX: 100,
clientY: 100,
button: 2,
buttons: 2,
}),
);
});
expect(screen.getByTestId('panning').textContent).toBe('false');
act(() => {
screen.getByRole('button', { name: '松开空格' }).click();
});
act(() => {
screen.getByRole('button', { name: '按住空格' }).click();
});
expect(screen.getByTestId('tool').textContent).toBe('hand');
act(() => {
fireEvent(
viewport,
new MouseEvent('pointerdown', {
bubbles: true,
clientX: 100,
clientY: 100,
@@ -968,4 +1093,83 @@ describe('useImageCanvasStageInteractions', () => {
});
expect(screen.getByTestId('panning').textContent).toBe('false');
});
it('rejects right-click panning on layers in select, hand, and Space modes', () => {
render(<StageInteractionsHarness />);
act(() => {
screen.getByRole('button', { name: '右键选第一层' }).click();
});
expect(screen.getByTestId('panning').textContent).toBe('false');
expect(screen.getByTestId('selection').textContent).toBe('-:');
act(() => {
screen.getByRole('button', { name: '右键抓手模式选第一层' }).click();
});
expect(screen.getByTestId('panning').textContent).toBe('false');
expect(screen.getByTestId('tool').textContent).toBe('hand');
expect(screen.getByTestId('selection').textContent).toBe('-:');
act(() => {
screen.getByRole('button', { name: '松开空格' }).click();
});
act(() => {
screen.getByRole('button', { name: '按住空格' }).click();
});
expect(screen.getByTestId('tool').textContent).toBe('hand');
act(() => {
const layer = screen.getByTestId('layer-first');
fireEvent(
layer,
new MouseEvent('pointerdown', {
bubbles: true,
clientX: 40,
clientY: 40,
button: 2,
buttons: 2,
}),
);
});
expect(screen.getByTestId('panning').textContent).toBe('false');
expect(screen.getByTestId('selection').textContent).toBe('-:');
});
it('rejects right-click panning on generation frames in select, hand, and Space modes', () => {
render(<StageInteractionsHarness />);
act(() => {
screen.getByRole('button', { name: '右键拖生成占位' }).click();
});
expect(screen.getByTestId('panning').textContent).toBe('false');
act(() => {
screen.getByRole('button', { name: '右键抓手模式拖生成占位' }).click();
});
expect(screen.getByTestId('panning').textContent).toBe('false');
expect(screen.getByTestId('tool').textContent).toBe('hand');
act(() => {
screen.getByRole('button', { name: '松开空格' }).click();
});
act(() => {
screen.getByRole('button', { name: '按住空格' }).click();
});
expect(screen.getByTestId('tool').textContent).toBe('hand');
act(() => {
const frame = screen.getByTestId('generation-frame');
fireEvent(
frame,
new MouseEvent('pointerdown', {
bubbles: true,
clientX: 300,
clientY: 200,
button: 2,
buttons: 2,
}),
);
});
expect(screen.getByTestId('panning').textContent).toBe('false');
});
});