Files
Genarrative/src/components/common/SquareImageCropModal.test.tsx
T
kdletters 071faa482c 统一 Rust 与 TypeScript 格式化门禁
纳入 AGC Cargo workspace 的统一 rustfmt 检查与格式化入口

完成项目 TypeScript/Prettier 与 Rust 全量格式化

修复 Pingora expected executable 门禁的空白敏感误报

同步开发运维文档与 AGC skill pack 格式化忽略规则
2026-09-01 16:28:34 +08:00

123 lines
3.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* @vitest-environment jsdom */
import { fireEvent, render, screen } from '@testing-library/react';
import { expect, test, vi } from 'vitest';
import { SquareImageCropModal } from './SquareImageCropModal';
function renderSquareImageCropModal(
overrideProps: Partial<Parameters<typeof SquareImageCropModal>[0]> = {},
) {
const onCropRectChange = vi.fn();
const onClose = vi.fn();
const onSubmit = vi.fn();
render(
<SquareImageCropModal
source="data:image/png;base64,preview"
imageSize={{ width: 800, height: 600 }}
cropRect={{ x: 100, y: 0, size: 600 }}
labels={{
title: '裁剪拼图图片',
close: '关闭拼图图片裁剪',
editor: '拼图图片裁剪操作区',
previewAlt: '拼图图片裁剪预览',
cancel: '取消',
submit: '应用',
saving: '裁剪中',
}}
onCropRectChange={onCropRectChange}
onClose={onClose}
onSubmit={onSubmit}
{...overrideProps}
/>,
);
return { onCropRectChange, onClose, onSubmit };
}
test('reuses unified modal shell while keeping crop close semantics disabled on backdrop and escape', () => {
const { onClose } = renderSquareImageCropModal();
const dialog = screen.getByRole('dialog', { name: '裁剪拼图图片' });
fireEvent.click(dialog.parentElement as HTMLElement);
fireEvent.keyDown(window, { key: 'Escape' });
expect(onClose).not.toHaveBeenCalled();
expect(
screen.getByRole('button', { name: '关闭拼图图片裁剪' }).className,
).toContain('platform-profile-icon-button');
expect(
screen.getByRole('button', { name: '关闭拼图图片裁剪' }).textContent,
).toContain('×');
});
test('keeps shared footer actions and saving disabled state', () => {
const { onClose, onSubmit } = renderSquareImageCropModal({ isSaving: true });
const cancelButton = screen.getByRole('button', { name: '取消' });
const submitButton = screen.getByRole('button', { name: '裁剪中' });
expect(cancelButton.className).toContain('platform-button--secondary');
expect(submitButton.hasAttribute('disabled')).toBe(true);
fireEvent.click(cancelButton);
fireEvent.click(submitButton);
expect(onClose).toHaveBeenCalledTimes(1);
expect(onSubmit).not.toHaveBeenCalled();
});
test('keeps pointer drag flow wired through the crop surface', () => {
const { onCropRectChange } = renderSquareImageCropModal();
const preview = screen.getByLabelText('拼图图片裁剪操作区');
const moveHandle = preview.querySelector('[class*="cursor-grab"]');
expect(moveHandle).toBeTruthy();
Object.defineProperty(preview, 'getBoundingClientRect', {
value: () => ({
width: 400,
height: 300,
top: 0,
left: 0,
right: 400,
bottom: 300,
x: 0,
y: 0,
toJSON: () => ({}),
}),
});
const setPointerCapture = vi.fn();
const releasePointerCapture = vi.fn();
Object.defineProperty(moveHandle as HTMLDivElement, 'setPointerCapture', {
value: setPointerCapture,
});
Object.defineProperty(moveHandle as HTMLDivElement, 'releasePointerCapture', {
value: releasePointerCapture,
});
fireEvent.pointerDown(moveHandle as Element, {
pointerId: 1,
clientX: 100,
clientY: 80,
});
fireEvent.pointerMove(moveHandle as Element, {
pointerId: 1,
clientX: 140,
clientY: 120,
});
fireEvent.pointerUp(moveHandle as Element, {
pointerId: 1,
});
expect(setPointerCapture).toHaveBeenCalledTimes(1);
expect(releasePointerCapture).toHaveBeenCalledTimes(1);
expect(onCropRectChange).toHaveBeenCalledTimes(1);
expect(onCropRectChange.mock.calls[0]?.[0]).toMatchObject({
size: 600,
});
});