新增 PlatformUiKit 通用弹窗、按钮、状态、空态、媒体、表单和标签等公共组件 迁移结果页、创作工作台、认证入口、RPG 暗色面板和运行态弹窗的重复 UI chrome 补充组件测试、页面回归测试、技术文档和 Hermes 共享决策记录
226 lines
6.7 KiB
TypeScript
226 lines
6.7 KiB
TypeScript
/* @vitest-environment jsdom */
|
|
|
|
import { fireEvent, render, screen } from '@testing-library/react';
|
|
import { expect, test, vi } from 'vitest';
|
|
|
|
import { PlatformUploadPreviewCard } from './PlatformUploadPreviewCard';
|
|
|
|
vi.mock('../ResolvedAssetImage', () => ({
|
|
ResolvedAssetImage: ({
|
|
src,
|
|
alt,
|
|
className,
|
|
}: {
|
|
src?: string | null;
|
|
alt?: string;
|
|
className?: string;
|
|
}) => <img src={src ?? ''} alt={alt} className={className} />,
|
|
}));
|
|
|
|
test('renders uploaded image preview with shared chrome', () => {
|
|
render(
|
|
<PlatformUploadPreviewCard
|
|
imageSrc="data:image/png;base64,abc"
|
|
imageAlt="反馈凭证预览"
|
|
removeLabel="移除上传凭证"
|
|
onRemove={vi.fn()}
|
|
/>,
|
|
);
|
|
|
|
const image = screen.getByRole('img', { name: '反馈凭证预览' });
|
|
const removeButton = screen.getByRole('button', { name: '移除上传凭证' });
|
|
|
|
expect(image.getAttribute('src')).toBe('data:image/png;base64,abc');
|
|
expect(image.className).toContain('object-cover');
|
|
expect(removeButton.getAttribute('type')).toBe('button');
|
|
expect(removeButton.className).toContain('bg-black/55');
|
|
});
|
|
|
|
test('calls remove handler from preview action', () => {
|
|
const onRemove = vi.fn();
|
|
|
|
render(
|
|
<PlatformUploadPreviewCard
|
|
imageSrc="/preview.png"
|
|
imageAlt="上传图片预览"
|
|
removeLabel="移除图片"
|
|
onRemove={onRemove}
|
|
/>,
|
|
);
|
|
|
|
fireEvent.click(screen.getByRole('button', { name: '移除图片' }));
|
|
|
|
expect(onRemove).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
test('supports preview action with resolved asset image', () => {
|
|
const onPreview = vi.fn();
|
|
|
|
render(
|
|
<PlatformUploadPreviewCard
|
|
imageSrc="/generated/reference.png"
|
|
imageAlt="参考图"
|
|
previewLabel="预览参考图 1"
|
|
removeLabel="移除参考图"
|
|
onPreview={onPreview}
|
|
resolveAsset
|
|
/>,
|
|
);
|
|
|
|
const previewButton = screen.getByRole('button', { name: '预览参考图 1' });
|
|
fireEvent.click(previewButton);
|
|
|
|
expect(screen.getByRole('img', { name: '参考图' }).getAttribute('src')).toBe(
|
|
'/generated/reference.png',
|
|
);
|
|
expect(onPreview).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
test('can render preview-only cards without remove action', () => {
|
|
render(
|
|
<PlatformUploadPreviewCard
|
|
imageSrc="/preview.png"
|
|
imageAlt="上传图片预览"
|
|
removeLabel="移除图片"
|
|
/>,
|
|
);
|
|
|
|
expect(screen.getByRole('img', { name: '上传图片预览' })).toBeTruthy();
|
|
expect(screen.queryByRole('button', { name: '移除图片' })).toBeNull();
|
|
});
|
|
|
|
test('supports captioned preview cards for reference images', () => {
|
|
const onPreview = vi.fn();
|
|
|
|
render(
|
|
<PlatformUploadPreviewCard
|
|
imageSrc="/reference.png"
|
|
imageAlt=""
|
|
caption="草莓"
|
|
previewLabel="预览参考图 草莓"
|
|
removeLabel="移除参考图 草莓"
|
|
onPreview={onPreview}
|
|
onRemove={vi.fn()}
|
|
className="w-full rounded-[1rem]"
|
|
imageShellClassName="ring-1"
|
|
captionClassName="pr-9"
|
|
/>,
|
|
);
|
|
|
|
const previewButton = screen.getByRole('button', {
|
|
name: '预览参考图 草莓',
|
|
});
|
|
|
|
fireEvent.click(previewButton);
|
|
|
|
const previewImage = previewButton.querySelector('img');
|
|
|
|
expect(screen.getByText('草莓').className).toContain('pr-9');
|
|
expect(previewImage?.parentElement?.className).toContain('ring-1');
|
|
expect(onPreview).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
test('supports inline selected upload preview rows', () => {
|
|
const onRemove = vi.fn();
|
|
|
|
render(
|
|
<PlatformUploadPreviewCard
|
|
layout="inline"
|
|
imageSrc="/reference.png"
|
|
imageAlt="创作参考图"
|
|
caption="森林参考图.png"
|
|
removeLabel="移除参考图"
|
|
onRemove={onRemove}
|
|
className="mt-3"
|
|
removeButtonProps={{ title: '移除参考图' }}
|
|
/>,
|
|
);
|
|
|
|
const image = screen.getByRole('img', { name: '创作参考图' });
|
|
const row = image.closest('div')?.parentElement;
|
|
const removeButton = screen.getByRole('button', { name: '移除参考图' });
|
|
|
|
expect(row?.className).toContain('flex items-center gap-3');
|
|
expect(row?.className).toContain('bg-white/68');
|
|
expect(row?.className).toContain('px-3');
|
|
expect(row?.className).toContain('py-2');
|
|
expect(row?.className).toContain('mt-3');
|
|
expect(screen.getByText('森林参考图.png').className).toContain('truncate');
|
|
expect(removeButton.className).toContain('platform-icon-button');
|
|
expect(removeButton.getAttribute('title')).toBe('移除参考图');
|
|
|
|
fireEvent.click(removeButton);
|
|
|
|
expect(onRemove).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
test('supports editor dark inline selected upload preview rows', () => {
|
|
render(
|
|
<PlatformUploadPreviewCard
|
|
layout="inline"
|
|
surface="editorDark"
|
|
imageSrc="/reference.png"
|
|
imageAlt="封面参考图"
|
|
caption="已载入封面参考图"
|
|
removeLabel="移除封面参考图"
|
|
onRemove={vi.fn()}
|
|
imageShellClassName="!h-16 !w-24 rounded-xl"
|
|
/>,
|
|
);
|
|
|
|
const image = screen.getByRole('img', { name: '封面参考图' });
|
|
const imageShell = image.parentElement;
|
|
const row = imageShell?.parentElement;
|
|
const caption = screen.getByText('已载入封面参考图');
|
|
const removeButton = screen.getByRole('button', { name: '移除封面参考图' });
|
|
|
|
expect(row?.className).toContain('border-white/10');
|
|
expect(row?.className).toContain('bg-black/25');
|
|
expect(imageShell?.className).toContain('bg-black/30');
|
|
expect(imageShell?.className).toContain('!w-24');
|
|
expect(caption.className).toContain('text-zinc-300');
|
|
expect(removeButton.className).toContain('bg-black/55');
|
|
});
|
|
|
|
test('keeps disabled remove action inert', () => {
|
|
const onRemove = vi.fn();
|
|
|
|
render(
|
|
<PlatformUploadPreviewCard
|
|
imageSrc="/preview.png"
|
|
imageAlt="上传图片预览"
|
|
removeLabel="移除图片"
|
|
onRemove={onRemove}
|
|
disabled
|
|
/>,
|
|
);
|
|
|
|
const removeButton = screen.getByRole('button', { name: '移除图片' });
|
|
fireEvent.click(removeButton);
|
|
|
|
expect(removeButton).toHaveProperty('disabled', true);
|
|
expect(removeButton.className).toContain('disabled:cursor-not-allowed');
|
|
expect(onRemove).not.toHaveBeenCalled();
|
|
});
|
|
|
|
test('supports local size, image and remove button classes', () => {
|
|
render(
|
|
<PlatformUploadPreviewCard
|
|
imageSrc="/preview.png"
|
|
imageAlt="上传图片预览"
|
|
removeLabel="移除图片"
|
|
onRemove={vi.fn()}
|
|
className="h-20 w-20"
|
|
imageClassName="object-top"
|
|
removeButtonProps={{ className: 'right-2 top-2' }}
|
|
/>,
|
|
);
|
|
|
|
const image = screen.getByRole('img', { name: '上传图片预览' });
|
|
const removeButton = screen.getByRole('button', { name: '移除图片' });
|
|
|
|
expect(image.parentElement?.className).toContain('h-20');
|
|
expect(image.className).toContain('object-top');
|
|
expect(removeButton.className).toContain('right-2');
|
|
});
|