Your Name e4959d584f feat: 完善代理商端业务逻辑与前后端框架
主要更新:
- 更新代理商端文档,明确项目由品牌方分配流程
- 新增Brief配置详情页(已配置)设计稿
- 完善工作台紧急待办中品牌新任务功能
- 整理Pencil设计文件中代理商端页面顺序
- 新增后端FastAPI框架及核心API
- 新增前端Next.js页面和组件库
- 添加.gitignore排除构建和缓存文件

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 19:27:31 +08:00

189 lines
6.5 KiB
TypeScript

/**
* Card 组件测试
* 测试覆盖: Card, CardHeader, CardTitle, CardContent, CardFooter
*/
import { render, screen, fireEvent } from '@testing-library/react';
import { describe, it, expect, vi } from 'vitest';
import { Card, CardHeader, CardTitle, CardContent, CardFooter } from './Card';
describe('Card', () => {
// ==================== 基础渲染测试 ====================
describe('基础渲染', () => {
it('渲染子元素', () => {
render(<Card></Card>);
expect(screen.getByText('卡片内容')).toBeInTheDocument();
});
it('默认使用 default variant 和 mobile padding', () => {
render(<Card data-testid="card"></Card>);
const card = screen.getByTestId('card');
expect(card).toHaveClass('bg-bg-card', 'rounded-card');
});
});
// ==================== Variant 测试 ====================
describe('Variant 样式', () => {
it('default variant 应用基础样式', () => {
render(<Card variant="default">Default</Card>);
const card = screen.getByText('Default').closest('div');
expect(card).toHaveClass('bg-bg-card');
expect(card).not.toHaveClass('shadow-elevated');
});
it('elevated variant 应用阴影样式', () => {
render(<Card variant="elevated">Elevated</Card>);
const card = screen.getByText('Elevated').closest('div');
expect(card).toHaveClass('bg-bg-elevated', 'shadow-elevated');
});
});
// ==================== Padding 测试 ====================
describe('Padding 样式', () => {
it('mobile padding 应用正确样式', () => {
render(<Card padding="mobile">Mobile</Card>);
const card = screen.getByText('Mobile').closest('div');
expect(card).toHaveClass('p-[14px_16px]');
});
it('desktop padding 应用正确样式', () => {
render(<Card padding="desktop">Desktop</Card>);
const card = screen.getByText('Desktop').closest('div');
expect(card).toHaveClass('p-[16px_20px]');
});
it('none padding 应用正确样式', () => {
render(<Card padding="none">No Padding</Card>);
const card = screen.getByText('No Padding').closest('div');
expect(card).toHaveClass('p-0');
});
});
// ==================== Hoverable 测试 ====================
describe('Hoverable 属性', () => {
it('hoverable 应用 hover 样式', () => {
render(<Card hoverable>Hoverable</Card>);
const card = screen.getByText('Hoverable').closest('div');
expect(card).toHaveClass('cursor-pointer', 'transition-all');
});
it('非 hoverable 不应用 hover 样式', () => {
render(<Card>Not Hoverable</Card>);
const card = screen.getByText('Not Hoverable').closest('div');
expect(card).not.toHaveClass('hover:bg-bg-elevated');
});
});
// ==================== onClick 测试 ====================
describe('onClick 事件', () => {
it('点击触发 onClick', () => {
const handleClick = vi.fn();
render(<Card onClick={handleClick}>Clickable</Card>);
fireEvent.click(screen.getByText('Clickable'));
expect(handleClick).toHaveBeenCalledTimes(1);
});
it('有 onClick 时显示 pointer 样式', () => {
const handleClick = vi.fn();
render(<Card onClick={handleClick}>Clickable</Card>);
const card = screen.getByText('Clickable').closest('div');
expect(card).toHaveClass('cursor-pointer');
});
});
// ==================== 自定义 className 测试 ====================
describe('自定义 className', () => {
it('支持自定义 className', () => {
render(<Card className="custom-card">Custom</Card>);
const card = screen.getByText('Custom').closest('div');
expect(card).toHaveClass('custom-card');
});
});
});
describe('CardHeader', () => {
it('渲染子元素', () => {
render(<CardHeader></CardHeader>);
expect(screen.getByText('头部内容')).toBeInTheDocument();
});
it('应用 flex 布局', () => {
render(<CardHeader>Header</CardHeader>);
const header = screen.getByText('Header').closest('div');
expect(header).toHaveClass('flex', 'items-center', 'justify-between');
});
it('支持自定义 className', () => {
render(<CardHeader className="custom-header">Header</CardHeader>);
const header = screen.getByText('Header').closest('div');
expect(header).toHaveClass('custom-header');
});
});
describe('CardTitle', () => {
it('渲染为 h3 标签', () => {
render(<CardTitle></CardTitle>);
expect(screen.getByRole('heading', { level: 3 })).toHaveTextContent('标题');
});
it('应用标题样式', () => {
render(<CardTitle>Title</CardTitle>);
const title = screen.getByRole('heading');
expect(title).toHaveClass('text-section-title', 'text-text-primary', 'font-semibold');
});
it('支持自定义 className', () => {
render(<CardTitle className="custom-title">Title</CardTitle>);
expect(screen.getByRole('heading')).toHaveClass('custom-title');
});
});
describe('CardContent', () => {
it('渲染子元素', () => {
render(<CardContent></CardContent>);
expect(screen.getByText('内容区域')).toBeInTheDocument();
});
it('支持自定义 className', () => {
render(<CardContent className="custom-content">Content</CardContent>);
const content = screen.getByText('Content').closest('div');
expect(content).toHaveClass('custom-content');
});
});
describe('CardFooter', () => {
it('渲染子元素', () => {
render(<CardFooter></CardFooter>);
expect(screen.getByText('页脚内容')).toBeInTheDocument();
});
it('应用边框和间距样式', () => {
render(<CardFooter>Footer</CardFooter>);
const footer = screen.getByText('Footer').closest('div');
expect(footer).toHaveClass('mt-4', 'pt-4', 'border-t', 'border-border-subtle');
});
it('支持自定义 className', () => {
render(<CardFooter className="custom-footer">Footer</CardFooter>);
const footer = screen.getByText('Footer').closest('div');
expect(footer).toHaveClass('custom-footer');
});
});
describe('Card 组合使用', () => {
it('完整卡片结构渲染正确', () => {
render(
<Card>
<CardHeader>
<CardTitle></CardTitle>
</CardHeader>
<CardContent></CardContent>
<CardFooter></CardFooter>
</Card>
);
expect(screen.getByRole('heading', { name: '卡片标题' })).toBeInTheDocument();
expect(screen.getByText('卡片内容')).toBeInTheDocument();
expect(screen.getByText('卡片页脚')).toBeInTheDocument();
});
});