Files
Genarrative/src/components/common/PlatformSegmentedTabs.test.tsx
kdletters 94122583ac 收口前端平台组件能力
新增 PlatformAsyncStatePanel 统一 profile 异步状态骨架
扩展 PlatformSegmentedTabs 支持滚动 tab 并接入创作入口与发现页
统一 PixelCloseButton 复用 PlatformModalCloseButton 像素关闭能力
抽取平台入口泥点前置提示弹层并收紧阻断语义
补充组件收口文档与共享决策记录
2026-06-11 01:06:31 +08:00

193 lines
5.8 KiB
TypeScript

/* @vitest-environment jsdom */
import { fireEvent, render, screen } from '@testing-library/react';
import { expect, test, vi } from 'vitest';
import { PlatformSegmentedTabs } from './PlatformSegmentedTabs';
const ITEMS = [
{ id: 'work', label: '作品信息' },
{ id: 'levels', label: '拼图关卡' },
] as const;
test('renders platform segmented tabs with pressed state', () => {
const onChange = vi.fn();
render(
<PlatformSegmentedTabs
items={ITEMS}
activeId="work"
onChange={onChange}
className="mb-3"
/>,
);
const workTab = screen.getByRole('button', { name: '作品信息' });
const levelsTab = screen.getByRole('button', { name: '拼图关卡' });
expect(workTab.getAttribute('aria-pressed')).toBe('true');
expect(levelsTab.getAttribute('aria-pressed')).toBe('false');
expect(workTab.className).toContain('bg-white');
expect(levelsTab.className).toContain('hover:bg-white/60');
expect(workTab.closest('div')?.className).toContain('grid-cols-2');
expect(workTab.closest('div')?.className).toContain('mb-3');
fireEvent.click(levelsTab);
expect(onChange).toHaveBeenCalledWith('levels');
});
test('supports compact responsive columns and truncated labels', () => {
render(
<PlatformSegmentedTabs
items={[
{ id: 'profile', label: '作品' },
{ id: 'world', label: '世界' },
{ id: 'opening', label: '开场' },
]}
activeId="profile"
onChange={vi.fn()}
columns="threeToSix"
gap="sm"
radius="md"
size="compact"
truncateLabels
/>,
);
const profileTab = screen.getByRole('button', { name: '作品' });
const label = profileTab.querySelector('span');
expect(profileTab.closest('div')?.className).toContain('grid-cols-3');
expect(profileTab.closest('div')?.className).toContain('sm:grid-cols-6');
expect(profileTab.closest('div')?.className).toContain('gap-1');
expect(profileTab.className).toContain('rounded-[0.8rem]');
expect(profileTab.className).toContain('text-xs');
expect(label?.className).toContain('truncate');
});
test('respects disabled items and custom item classes', () => {
const onChange = vi.fn();
render(
<PlatformSegmentedTabs
items={[
{ id: 'single', label: '单关卡' },
{ id: 'multi', label: '多关卡', disabled: true },
]}
activeId="single"
onChange={onChange}
itemClassName={(item, active) =>
item.id === 'single' && active ? 'data-active-token' : null
}
/>,
);
const singleTab = screen.getByRole('button', { name: '单关卡' });
const multiTab = screen.getByRole('button', { name: '多关卡' });
expect(singleTab.className).toContain('data-active-token');
expect(multiTab).toHaveProperty('disabled', true);
fireEvent.click(multiTab);
expect(onChange).not.toHaveBeenCalled();
});
test('supports bare four-column choice tabs with tone variants', () => {
render(
<PlatformSegmentedTabs
items={[
{ id: 'easy', label: '轻松' },
{ id: 'standard', label: '标准' },
{ id: 'advanced', label: '进阶' },
{ id: 'hardcore', label: '硬核' },
]}
activeId="advanced"
onChange={vi.fn()}
columns="four"
size="choice"
surface="transparent"
tone="rose"
frame="bare"
/>,
);
const advancedTab = screen.getByRole('button', { name: '进阶' });
const standardTab = screen.getByRole('button', { name: '标准' });
const tabGrid = advancedTab.closest('div');
expect(tabGrid?.className).toContain('grid-cols-4');
expect(tabGrid?.className).toContain('border-0');
expect(tabGrid?.className).toContain('p-0');
expect(tabGrid?.className).toContain('bg-transparent');
expect(advancedTab.className).toContain('rounded-[0.9rem]');
expect(advancedTab.className).toContain('bg-[linear-gradient');
expect(standardTab.className).toContain('bg-white/76');
});
test('supports auth-style tab semantics with underline tone', () => {
const onChange = vi.fn();
render(
<PlatformSegmentedTabs
items={[
{ id: 'phone', label: '短信登录' },
{ id: 'password', label: '密码登录' },
]}
activeId="phone"
onChange={onChange}
columns="one"
frame="bare"
surface="transparent"
tone="underline"
size="tab"
semantics="tabs"
ariaLabel="登录方式"
/>,
);
const tablist = screen.getByRole('tablist', { name: '登录方式' });
const phoneTab = screen.getByRole('tab', { name: '短信登录' });
const passwordTab = screen.getByRole('tab', { name: '密码登录' });
expect(tablist.className).toContain('grid-cols-1');
expect(phoneTab.getAttribute('aria-selected')).toBe('true');
expect(phoneTab.getAttribute('aria-pressed')).toBeNull();
expect(phoneTab.className).toContain('h-12');
expect(phoneTab.querySelector('span.absolute')).toBeTruthy();
expect(passwordTab.getAttribute('aria-selected')).toBe('false');
fireEvent.click(passwordTab);
expect(onChange).toHaveBeenCalledWith('password');
});
test('supports scroll layout for horizontal tabs', () => {
render(
<PlatformSegmentedTabs
items={[
{ id: 'recent', label: '最近创作' },
{ id: 'rpg', label: '文字冒险' },
{ id: 'jump-hop', label: '跳一跳' },
]}
activeId="recent"
onChange={vi.fn()}
layout="scroll"
semantics="tabs"
ariaLabel="创作入口页签"
frame="bare"
surface="transparent"
className="pb-1"
/>,
);
const tablist = screen.getByRole('tablist', { name: '创作入口页签' });
expect(tablist.className).toContain('flex');
expect(tablist.className).toContain('overflow-x-auto');
expect(tablist.className).toContain('scrollbar-hide');
expect(tablist.className).not.toContain('grid-cols-2');
expect(tablist.className).toContain('pb-1');
});