185 lines
6.2 KiB
TypeScript
185 lines
6.2 KiB
TypeScript
/**
|
||
* ProBadge 组件单元测试
|
||
*
|
||
* 测试 ProBadge 组件的尺寸变体和主题支持
|
||
*
|
||
* **Feature: free-version-ui-restrictions**
|
||
* **Property 3: ProBadge 尺寸变体**
|
||
* **Property 4: ProBadge 主题支持**
|
||
* **Validates: Requirements 4.2, 4.3**
|
||
*
|
||
* @jest-environment jsdom
|
||
*/
|
||
|
||
import React from 'react'
|
||
import { render, screen } from '@testing-library/react'
|
||
import '@testing-library/jest-dom'
|
||
import ProBadge, { ProBadgeSize } from '../ProBadge'
|
||
|
||
// Mock useTheme hook
|
||
const mockUseTheme = jest.fn()
|
||
jest.mock('@/lib/ui-styles', () => ({
|
||
useTheme: () => mockUseTheme(),
|
||
cn: (...classes: (string | boolean | undefined)[]) =>
|
||
classes.filter(Boolean).join(' '),
|
||
}))
|
||
|
||
describe('ProBadge 组件', () => {
|
||
beforeEach(() => {
|
||
mockUseTheme.mockReturnValue('light')
|
||
})
|
||
|
||
describe('基础渲染', () => {
|
||
it('应该正确渲染 PRO 文字', () => {
|
||
render(<ProBadge />)
|
||
expect(screen.getByText('PRO')).toBeInTheDocument()
|
||
})
|
||
|
||
it('应该有正确的 data-testid', () => {
|
||
render(<ProBadge />)
|
||
expect(screen.getByTestId('pro-badge')).toBeInTheDocument()
|
||
})
|
||
|
||
it('应该使用默认的 small 尺寸', () => {
|
||
render(<ProBadge />)
|
||
const badge = screen.getByTestId('pro-badge')
|
||
expect(badge).toHaveAttribute('data-size', 'small')
|
||
})
|
||
|
||
it('应该应用自定义 className', () => {
|
||
render(<ProBadge className="custom-class" />)
|
||
const badge = screen.getByTestId('pro-badge')
|
||
expect(badge.className).toContain('custom-class')
|
||
})
|
||
})
|
||
|
||
/**
|
||
* Property 3: ProBadge 尺寸变体
|
||
* *For any* 有效的尺寸参数 (xs, small, medium, large),ProBadge 组件必须使用对应的尺寸样式渲染
|
||
* **Feature: free-version-ui-restrictions, Property 3: ProBadge Size Variants**
|
||
* **Validates: Requirements 4.2**
|
||
*/
|
||
describe('Property 3: ProBadge 尺寸变体', () => {
|
||
const sizes: ProBadgeSize[] = ['xs', 'small', 'medium', 'large']
|
||
|
||
const sizeExpectations: Record<ProBadgeSize, { textClass: string; paddingClass: string }> = {
|
||
xs: { textClass: 'text-[8px]', paddingClass: 'px-1' },
|
||
small: { textClass: 'text-[10px]', paddingClass: 'px-1.5' },
|
||
medium: { textClass: 'text-xs', paddingClass: 'px-2' },
|
||
large: { textClass: 'text-sm', paddingClass: 'px-2.5' },
|
||
}
|
||
|
||
sizes.forEach((size) => {
|
||
it(`应该正确渲染 ${size} 尺寸`, () => {
|
||
render(<ProBadge size={size} />)
|
||
const badge = screen.getByTestId('pro-badge')
|
||
expect(badge).toHaveAttribute('data-size', size)
|
||
})
|
||
|
||
it(`${size} 尺寸应该有正确的文字大小类`, () => {
|
||
render(<ProBadge size={size} />)
|
||
const badge = screen.getByTestId('pro-badge')
|
||
expect(badge.className).toContain(sizeExpectations[size].textClass)
|
||
})
|
||
|
||
it(`${size} 尺寸应该有正确的内边距类`, () => {
|
||
render(<ProBadge size={size} />)
|
||
const badge = screen.getByTestId('pro-badge')
|
||
expect(badge.className).toContain(sizeExpectations[size].paddingClass)
|
||
})
|
||
})
|
||
|
||
it('不同尺寸应该产生不同的样式', () => {
|
||
const { rerender } = render(<ProBadge size="small" />)
|
||
const smallBadge = screen.getByTestId('pro-badge')
|
||
const smallClassName = smallBadge.className
|
||
|
||
rerender(<ProBadge size="large" />)
|
||
const largeBadge = screen.getByTestId('pro-badge')
|
||
const largeClassName = largeBadge.className
|
||
|
||
expect(smallClassName).not.toBe(largeClassName)
|
||
})
|
||
})
|
||
|
||
/**
|
||
* Property 4: ProBadge 主题支持
|
||
* *For any* 主题 (light 或 dark),ProBadge 组件必须以适当的对比度和可见性渲染
|
||
* **Feature: free-version-ui-restrictions, Property 4: ProBadge Theme Support**
|
||
* **Validates: Requirements 4.3**
|
||
*/
|
||
describe('Property 4: ProBadge 主题支持', () => {
|
||
it('浅色主题应该有正确的阴影样式', () => {
|
||
mockUseTheme.mockReturnValue('light')
|
||
render(<ProBadge />)
|
||
const badge = screen.getByTestId('pro-badge')
|
||
expect(badge.className).toContain('bg-slate-100')
|
||
})
|
||
|
||
it('深色主题应该有正确的阴影样式', () => {
|
||
mockUseTheme.mockReturnValue('dark')
|
||
render(<ProBadge />)
|
||
const badge = screen.getByTestId('pro-badge')
|
||
expect(badge.className).toContain('bg-slate-800')
|
||
})
|
||
|
||
it('两种主题都应该有中性色背景', () => {
|
||
mockUseTheme.mockReturnValue('light')
|
||
const { rerender } = render(<ProBadge />)
|
||
let badge = screen.getByTestId('pro-badge')
|
||
expect(badge.className).toContain('bg-slate-100')
|
||
expect(badge.className).toContain('text-slate-700')
|
||
|
||
mockUseTheme.mockReturnValue('dark')
|
||
rerender(<ProBadge />)
|
||
badge = screen.getByTestId('pro-badge')
|
||
expect(badge.className).toContain('bg-slate-800')
|
||
expect(badge.className).toContain('text-slate-200')
|
||
})
|
||
|
||
it('两种主题都应该有清晰文字', () => {
|
||
mockUseTheme.mockReturnValue('light')
|
||
const { rerender } = render(<ProBadge />)
|
||
let badge = screen.getByTestId('pro-badge')
|
||
expect(badge.className).toContain('text-slate-700')
|
||
|
||
mockUseTheme.mockReturnValue('dark')
|
||
rerender(<ProBadge />)
|
||
badge = screen.getByTestId('pro-badge')
|
||
expect(badge.className).toContain('text-slate-200')
|
||
})
|
||
})
|
||
|
||
describe('视觉样式', () => {
|
||
it('应该有圆角样式', () => {
|
||
render(<ProBadge />)
|
||
const badge = screen.getByTestId('pro-badge')
|
||
expect(badge.className).toContain('rounded-full')
|
||
})
|
||
|
||
it('应该有中性色背景', () => {
|
||
render(<ProBadge />)
|
||
const badge = screen.getByTestId('pro-badge')
|
||
expect(badge.className).toContain('bg-slate-100')
|
||
})
|
||
|
||
it('应该有阴影效果', () => {
|
||
render(<ProBadge />)
|
||
const badge = screen.getByTestId('pro-badge')
|
||
expect(badge.className).toContain('shadow-sm')
|
||
})
|
||
|
||
it('应该是 inline-flex 以便内联使用', () => {
|
||
render(<ProBadge />)
|
||
const badge = screen.getByTestId('pro-badge')
|
||
expect(badge.className).toContain('inline-flex')
|
||
})
|
||
|
||
it('应该有加粗字体', () => {
|
||
render(<ProBadge />)
|
||
const badge = screen.getByTestId('pro-badge')
|
||
expect(badge.className).toContain('font-semibold')
|
||
})
|
||
})
|
||
})
|