收口前端平台组件库能力
新增 PlatformUiKit 通用弹窗、按钮、状态、空态、媒体、表单和标签等公共组件 迁移结果页、创作工作台、认证入口、RPG 暗色面板和运行态弹窗的重复 UI chrome 补充组件测试、页面回归测试、技术文档和 Hermes 共享决策记录
This commit is contained in:
167
src/components/common/PlatformIconButton.test.tsx
Normal file
167
src/components/common/PlatformIconButton.test.tsx
Normal file
@@ -0,0 +1,167 @@
|
||||
/* @vitest-environment jsdom */
|
||||
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { expect, test } from 'vitest';
|
||||
|
||||
import { PlatformIconButton } from './PlatformIconButton';
|
||||
|
||||
test('renders platform icon button with accessible label and icon chrome', () => {
|
||||
render(
|
||||
<PlatformIconButton
|
||||
label="关闭"
|
||||
icon={<span aria-hidden="true">×</span>}
|
||||
/>,
|
||||
);
|
||||
|
||||
const button = screen.getByRole('button', { name: '关闭' });
|
||||
|
||||
expect(button.className).toContain('platform-icon-button');
|
||||
expect(button.getAttribute('type')).toBe('button');
|
||||
expect(button.textContent).toBe('×');
|
||||
});
|
||||
|
||||
test('keeps local class names and explicit title', () => {
|
||||
render(
|
||||
<PlatformIconButton
|
||||
label="发送"
|
||||
title="发送"
|
||||
icon={<span aria-hidden="true">↑</span>}
|
||||
className="h-11 w-11"
|
||||
/>,
|
||||
);
|
||||
|
||||
const button = screen.getByRole('button', { name: '发送' });
|
||||
|
||||
expect(button.className).toContain('h-11');
|
||||
expect(button.getAttribute('title')).toBe('发送');
|
||||
});
|
||||
|
||||
test('supports floating surface icon action chrome', () => {
|
||||
render(
|
||||
<PlatformIconButton
|
||||
label="更换图片"
|
||||
title="更换图片"
|
||||
variant="surfaceFloating"
|
||||
icon={<span aria-hidden="true">+</span>}
|
||||
className="h-10 w-10"
|
||||
/>,
|
||||
);
|
||||
|
||||
const button = screen.getByRole('button', { name: '更换图片' });
|
||||
|
||||
expect(button.className).toContain('bg-white/94');
|
||||
expect(button.className).toContain('backdrop-blur');
|
||||
expect(button.className).toContain('h-10');
|
||||
expect(button.className).not.toContain('platform-icon-button');
|
||||
});
|
||||
|
||||
test('supports visible short label on floating surface actions', () => {
|
||||
render(
|
||||
<PlatformIconButton
|
||||
label="选择历史图片"
|
||||
title="选择历史图片"
|
||||
variant="surfaceFloating"
|
||||
icon={<span aria-hidden="true">↺</span>}
|
||||
className="gap-1.5 px-3"
|
||||
>
|
||||
<span>历史</span>
|
||||
</PlatformIconButton>,
|
||||
);
|
||||
|
||||
const button = screen.getByRole('button', { name: '选择历史图片' });
|
||||
|
||||
expect(button.textContent).toContain('历史');
|
||||
expect(button.className).toContain('bg-white/94');
|
||||
expect(button.className).toContain('gap-1.5');
|
||||
expect(button.className).toContain('px-3');
|
||||
});
|
||||
|
||||
test('supports dark mini icon action chrome', () => {
|
||||
render(
|
||||
<PlatformIconButton
|
||||
label="字段说明"
|
||||
variant="darkMini"
|
||||
icon={<span aria-hidden="true">?</span>}
|
||||
className="h-4 w-4 text-[10px]"
|
||||
/>,
|
||||
);
|
||||
|
||||
const button = screen.getByRole('button', { name: '字段说明' });
|
||||
|
||||
expect(button.className).toContain('bg-black/55');
|
||||
expect(button.className).toContain('border-white/16');
|
||||
expect(button.className).toContain('hover:bg-black/70');
|
||||
expect(button.className).toContain('h-4');
|
||||
expect(button.textContent).toBe('?');
|
||||
});
|
||||
|
||||
test('supports label child chrome for icon upload controls', () => {
|
||||
const { container } = render(
|
||||
<>
|
||||
<PlatformIconButton
|
||||
asChild="label"
|
||||
htmlFor="reference-image"
|
||||
label="上传参考图"
|
||||
title="上传参考图"
|
||||
icon={<span aria-hidden="true" />}
|
||||
className="h-9 w-9 cursor-pointer"
|
||||
/>
|
||||
<input id="reference-image" type="file" />
|
||||
</>,
|
||||
);
|
||||
|
||||
const input = screen.getByLabelText('上传参考图');
|
||||
const label = container.querySelector('label[for="reference-image"]');
|
||||
|
||||
expect(input.getAttribute('type')).toBe('file');
|
||||
expect(label?.tagName).toBe('LABEL');
|
||||
expect(label?.getAttribute('for')).toBe('reference-image');
|
||||
expect(label?.className).toContain('platform-icon-button');
|
||||
expect(label?.className).toContain('cursor-pointer');
|
||||
expect(label?.getAttribute('title')).toBe('上传参考图');
|
||||
});
|
||||
|
||||
test('supports floating surface label upload controls', () => {
|
||||
const { container } = render(
|
||||
<PlatformIconButton
|
||||
asChild="label"
|
||||
label="上传参考图"
|
||||
variant="surfaceFloating"
|
||||
title="上传参考图"
|
||||
icon={
|
||||
<>
|
||||
<span aria-hidden="true">+</span>
|
||||
<input type="file" />
|
||||
</>
|
||||
}
|
||||
className="h-8 w-8 cursor-pointer"
|
||||
/>,
|
||||
);
|
||||
|
||||
const label = container.querySelector('label');
|
||||
const input = label?.querySelector('input');
|
||||
|
||||
expect(label?.textContent).toContain('上传参考图');
|
||||
expect(input?.getAttribute('type')).toBe('file');
|
||||
expect(label?.className).toContain('bg-white/94');
|
||||
expect(label?.className).toContain('cursor-pointer');
|
||||
});
|
||||
|
||||
test('keeps nested file input associated with the label name', () => {
|
||||
render(
|
||||
<PlatformIconButton
|
||||
asChild="label"
|
||||
label="上传参考图"
|
||||
icon={
|
||||
<>
|
||||
<span aria-hidden="true" />
|
||||
<input type="file" />
|
||||
</>
|
||||
}
|
||||
/>,
|
||||
);
|
||||
|
||||
const input = screen.getByLabelText('上传参考图', { selector: 'input' });
|
||||
|
||||
expect(input.getAttribute('type')).toBe('file');
|
||||
});
|
||||
Reference in New Issue
Block a user