Files
Genarrative/src/components/common/PlatformImagePreviewModal.test.tsx
T
k88936 bd4baf66b1
Project CI / Repository checks (pull_request) Successful in 1m18s
Project CI / Backend tests (pull_request) Successful in 3m59s
Project CI / Native shell tests (pull_request) Successful in 10m52s
Project CI / Frontend tests (pull_request) Successful in 4m19s
统一修复Modal Portal主题继承
在UnifiedModal集中解析Portal主题并支持显式覆盖
梳理危险确认、图片预览、报告和工具弹窗的主题边界
修复固定浅色画布弹窗与Agent菜单的主题回归
将相关公共组件测试纳入默认Vitest收集范围
同步Platform UI Kit、画布Agent与共享记忆文档
2026-07-31 20:14:58 +08:00

183 lines
4.7 KiB
TypeScript

/* @vitest-environment jsdom */
import { act, fireEvent, render, screen, waitFor } from '@testing-library/react';
import type React from 'react';
import { expect, test, vi } from 'vitest';
import { PlatformImagePreviewModal } from './PlatformImagePreviewModal';
import { clampPlatformImagePreviewTransform } from './platformImagePreviewModel';
vi.mock('../ResolvedAssetImage', () => ({
ResolvedAssetImage: ({
src,
alt,
className,
style,
draggable,
onLoad,
}: {
src?: string | null;
alt?: string;
className?: string;
style?: React.CSSProperties;
draggable?: boolean;
onLoad?: React.ReactEventHandler<HTMLImageElement>;
}) =>
src ? (
<img
src={src}
alt={alt}
className={className}
style={style}
draggable={draggable}
onLoad={onLoad}
/>
) : null,
}));
test('clamps full-screen image preview zoom and drag within image bounds', () => {
expect(
clampPlatformImagePreviewTransform(
{
scale: 8,
offsetX: 999,
offsetY: -999,
},
{ width: 400, height: 800 },
{ width: 400, height: 400 },
),
).toEqual({
scale: 4,
offsetX: 600,
offsetY: -400,
});
expect(
clampPlatformImagePreviewTransform(
{
scale: 4,
offsetX: -999,
offsetY: 999,
},
{ width: 400, height: 800 },
{ width: 400, height: 400 },
),
).toEqual({
scale: 4,
offsetX: -600,
offsetY: 400,
});
expect(
clampPlatformImagePreviewTransform(
{
scale: 0.25,
offsetX: 80,
offsetY: 80,
},
{ width: 400, height: 800 },
{ width: 400, height: 400 },
),
).toEqual({
scale: 1,
offsetX: 0,
offsetY: 0,
});
});
test('renders full-screen image preview with zoom controls and dark backdrop', () => {
render(
<PlatformImagePreviewModal
open
title="查看关卡图片"
imageSrc="/generated-puzzle-assets/session/level/image.png"
imageAlt="拼图关卡图"
closeLabel="关闭关卡图片预览"
onClose={() => {}}
/>,
);
const dialog = screen.getByRole('dialog', { name: '查看关卡图片' });
expect(dialog.className).toContain('platform-image-preview-modal');
expect(dialog.className).toContain('bg-black');
expect(
dialog.parentElement?.className.includes('!bg-black'),
).toBe(true);
expect(dialog.parentElement?.className).not.toContain('platform-theme--');
expect(screen.getByRole('button', { name: '放大图片' })).toBeTruthy();
expect(screen.getByRole('button', { name: '缩小图片' })).toBeTruthy();
expect(screen.getByRole('button', { name: '重置图片缩放' })).toBeTruthy();
expect(screen.getByAltText('拼图关卡图').getAttribute('draggable')).toBe(
'false',
);
});
test('zooms to at most four times and clamps dragged image position', async () => {
render(
<PlatformImagePreviewModal
open
title="查看关卡图片"
imageSrc="/generated-puzzle-assets/session/level/image.png"
imageAlt="拼图关卡图"
closeLabel="关闭关卡图片预览"
onClose={() => {}}
/>,
);
const stage = screen.getByTestId('platform-image-preview-stage');
Object.defineProperty(stage, 'getBoundingClientRect', {
configurable: true,
value: () => ({
width: 400,
height: 800,
top: 0,
right: 400,
bottom: 800,
left: 0,
x: 0,
y: 0,
toJSON: () => ({}),
}),
});
const image = screen.getByAltText('拼图关卡图') as HTMLImageElement;
Object.defineProperties(image, {
naturalWidth: { configurable: true, value: 400 },
naturalHeight: { configurable: true, value: 400 },
});
await act(async () => {
window.dispatchEvent(new Event('resize'));
fireEvent.load(image);
});
await waitFor(() => {
expect(image.style.width).toBe('400px');
expect(image.style.height).toBe('400px');
});
for (let index = 0; index < 8; index += 1) {
fireEvent.click(screen.getByRole('button', { name: '放大图片' }));
}
await waitFor(() => {
expect(image.style.transform).toContain(
'translate3d(0px, 0px, 0) scale(4)',
);
});
fireEvent.pointerDown(stage, { pointerId: 1, clientX: 200, clientY: 400 });
fireEvent.pointerMove(stage, { pointerId: 1, clientX: 1200, clientY: 1200 });
fireEvent.pointerUp(stage, { pointerId: 1, clientX: 1200, clientY: 1200 });
await waitFor(() => {
const offsetMatch = image.style.transform.match(
/translate3d\((-?\d+)px, (-?\d+)px, 0\) scale\(4\)/u,
);
expect(offsetMatch).not.toBeNull();
expect(Math.abs(Number(offsetMatch?.[1]))).toBe(600);
expect(Math.abs(Number(offsetMatch?.[2]))).toBe(400);
});
});