1ad25e30f8
新增 PlatformUiKit 通用弹窗、按钮、状态、空态、媒体、表单和标签等公共组件 迁移结果页、创作工作台、认证入口、RPG 暗色面板和运行态弹窗的重复 UI chrome 补充组件测试、页面回归测试、技术文档和 Hermes 共享决策记录
232 lines
6.9 KiB
TypeScript
232 lines
6.9 KiB
TypeScript
/* @vitest-environment jsdom */
|
|
|
|
import { render, screen } from '@testing-library/react';
|
|
import userEvent from '@testing-library/user-event';
|
|
import { expect, test, vi } from 'vitest';
|
|
|
|
import { PlatformSubpanel } from './PlatformSubpanel';
|
|
|
|
test('renders platform subpanel shell with section title', () => {
|
|
render(
|
|
<PlatformSubpanel title="作品信息">
|
|
<p>作品名称</p>
|
|
</PlatformSubpanel>,
|
|
);
|
|
|
|
const panel = screen.getByText('作品信息').closest('section');
|
|
|
|
expect(panel?.className).toContain('platform-subpanel');
|
|
expect(panel?.className).toContain('rounded-[1.25rem]');
|
|
expect(panel?.className).toContain('p-4');
|
|
expect(screen.getByText('作品信息').className).toContain('tracking-[0.18em]');
|
|
});
|
|
|
|
test('supports actions, strong title and body class', () => {
|
|
render(
|
|
<PlatformSubpanel
|
|
as="div"
|
|
title="音频"
|
|
titleVariant="strong"
|
|
actions={<button type="button">重置</button>}
|
|
radius="lg"
|
|
padding="lg"
|
|
bodyClassName="mt-3 grid gap-2"
|
|
className="custom-panel"
|
|
>
|
|
<span>上传</span>
|
|
</PlatformSubpanel>,
|
|
);
|
|
|
|
const panel = screen.getByText('音频').closest('div.custom-panel');
|
|
const body = screen.getByText('上传').parentElement;
|
|
|
|
expect(panel?.className).toContain('rounded-[1.35rem]');
|
|
expect(panel?.className).toContain('sm:p-5');
|
|
expect(screen.getByText('音频').className).toContain('font-black');
|
|
expect(screen.getByRole('button', { name: '重置' })).toBeTruthy();
|
|
expect(body?.className).toContain('mt-3 grid gap-2');
|
|
});
|
|
|
|
test('supports extra large platform subpanel radius', () => {
|
|
render(
|
|
<PlatformSubpanel radius="xl" padding="lg">
|
|
方洞面板
|
|
</PlatformSubpanel>,
|
|
);
|
|
|
|
const panel = screen.getByText('方洞面板').closest('section');
|
|
|
|
expect(panel?.className).toContain('rounded-[1.5rem]');
|
|
expect(panel?.className).toContain('sm:p-5');
|
|
});
|
|
|
|
test('passes static element attributes through to the panel shell', () => {
|
|
render(
|
|
<PlatformSubpanel as="aside" aria-label="预览面板" data-testid="preview">
|
|
预览内容
|
|
</PlatformSubpanel>,
|
|
);
|
|
|
|
const panel = screen.getByTestId('preview');
|
|
|
|
expect(panel.tagName).toBe('ASIDE');
|
|
expect(panel.getAttribute('aria-label')).toBe('预览面板');
|
|
expect(panel.className).toContain('platform-subpanel');
|
|
});
|
|
|
|
test('supports flat compact subpanel cards', () => {
|
|
render(
|
|
<PlatformSubpanel
|
|
as="div"
|
|
surface="flat"
|
|
radius="sm"
|
|
padding="sm"
|
|
title="封面"
|
|
actions={<button type="button">选择</button>}
|
|
>
|
|
<span>已绑定</span>
|
|
</PlatformSubpanel>,
|
|
);
|
|
|
|
const panel = screen.getByText('已绑定').closest('div');
|
|
|
|
expect(panel?.className.split(/\s+/u)).not.toContain('platform-subpanel');
|
|
expect(panel?.className).toContain('bg-white/72');
|
|
expect(panel?.className).toContain('rounded-[1rem]');
|
|
expect(panel?.className).toContain('p-3');
|
|
expect(screen.getByRole('button', { name: '选择' })).toBeTruthy();
|
|
});
|
|
|
|
test('supports dark compact subpanel cards', () => {
|
|
render(
|
|
<PlatformSubpanel as="div" surface="dark" radius="xs" padding="xs">
|
|
任务目标
|
|
</PlatformSubpanel>,
|
|
);
|
|
|
|
const panel = screen.getByText('任务目标').closest('div');
|
|
|
|
expect(panel?.className).toContain('border-white/10');
|
|
expect(panel?.className).toContain('bg-black/25');
|
|
expect(panel?.className).toContain('rounded-xl');
|
|
expect(panel?.className).toContain('px-3');
|
|
expect(panel?.className).toContain('py-2.5');
|
|
});
|
|
|
|
test('supports tinted dark information panels', () => {
|
|
const { rerender } = render(
|
|
<PlatformSubpanel as="div" surface="darkSky" radius="lg" padding="md">
|
|
私聊
|
|
</PlatformSubpanel>,
|
|
);
|
|
|
|
let panel = screen.getByText('私聊').closest('div');
|
|
|
|
expect(panel?.className).toContain('border-sky-400/18');
|
|
expect(panel?.className).toContain('bg-sky-500/8');
|
|
expect(panel?.className).toContain('text-sky-50');
|
|
expect(panel?.className).toContain('rounded-[1.35rem]');
|
|
|
|
rerender(
|
|
<PlatformSubpanel as="div" surface="darkEmerald" radius="xs" padding="row">
|
|
队友收束
|
|
</PlatformSubpanel>,
|
|
);
|
|
|
|
panel = screen.getByText('队友收束').closest('div');
|
|
expect(panel?.className).toContain('border-emerald-400/18');
|
|
expect(panel?.className).toContain('bg-emerald-500/8');
|
|
expect(panel?.className).toContain('text-emerald-100/85');
|
|
|
|
rerender(
|
|
<PlatformSubpanel as="div" surface="darkAmber" radius="xs" padding="sm">
|
|
等级
|
|
</PlatformSubpanel>,
|
|
);
|
|
|
|
panel = screen.getByText('等级').closest('div');
|
|
expect(panel?.className).toContain('border-amber-300/18');
|
|
expect(panel?.className).toContain('bg-amber-500/8');
|
|
expect(panel?.className).toContain('text-amber-50');
|
|
|
|
rerender(
|
|
<PlatformSubpanel as="div" surface="darkRose" radius="xs" padding="xs">
|
|
好感度
|
|
</PlatformSubpanel>,
|
|
);
|
|
|
|
panel = screen.getByText('好感度').closest('div');
|
|
expect(panel?.className).toContain('border-rose-300/18');
|
|
expect(panel?.className).toContain('bg-rose-500/8');
|
|
expect(panel?.className).toContain('text-rose-50');
|
|
});
|
|
|
|
test('supports soft tight subpanel rows', () => {
|
|
const { rerender } = render(
|
|
<PlatformSubpanel as="div" surface="soft" radius="sm" padding="tight">
|
|
新增标签
|
|
</PlatformSubpanel>,
|
|
);
|
|
|
|
let panel = screen.getByText('新增标签').closest('div');
|
|
|
|
expect(panel?.className).toContain('bg-white/68');
|
|
expect(panel?.className).toContain('rounded-[1rem]');
|
|
expect(panel?.className).toContain('p-2');
|
|
|
|
rerender(
|
|
<PlatformSubpanel as="div" surface="soft" radius="sm" padding="row">
|
|
已选素材
|
|
</PlatformSubpanel>,
|
|
);
|
|
|
|
panel = screen.getByText('已选素材').closest('div');
|
|
expect(panel?.className).toContain('px-3');
|
|
expect(panel?.className).toContain('py-2');
|
|
});
|
|
|
|
test('supports danger subpanel surface', () => {
|
|
render(
|
|
<PlatformSubpanel surface="danger" padding="none">
|
|
已选卡片
|
|
</PlatformSubpanel>,
|
|
);
|
|
|
|
const panel = screen.getByText('已选卡片').closest('section');
|
|
|
|
expect(panel?.className.split(/\s+/u)).not.toContain('platform-subpanel');
|
|
expect(panel?.className).toContain(
|
|
'border-[var(--platform-button-danger-border)]',
|
|
);
|
|
expect(panel?.className).toContain('bg-[var(--platform-button-danger-fill)]');
|
|
expect(panel?.className).toContain('p-0');
|
|
});
|
|
|
|
test('supports interactive button subpanel cards', async () => {
|
|
const user = userEvent.setup();
|
|
const onClick = vi.fn();
|
|
|
|
render(
|
|
<PlatformSubpanel
|
|
as="button"
|
|
surface="flat"
|
|
radius="sm"
|
|
padding="sm"
|
|
interactive
|
|
onClick={onClick}
|
|
>
|
|
继续
|
|
</PlatformSubpanel>,
|
|
);
|
|
|
|
const button = screen.getByRole('button', { name: '继续' });
|
|
|
|
expect(button.getAttribute('type')).toBe('button');
|
|
expect(button.className).toContain('hover:bg-white');
|
|
expect(button.className).toContain('disabled:cursor-not-allowed');
|
|
|
|
await user.click(button);
|
|
|
|
expect(onClick).toHaveBeenCalledTimes(1);
|
|
});
|