import { describe, expect, it, vi } from 'vitest'; import { fireEvent, render, screen } from '@testing-library/react'; import SwitchButtonGroup from '@/components/SwitchButtonGroup'; describe('SwitchButtonGroup 组件', () => { const options = [ { value: 'a', label: '选项A' }, { value: 'b', label: '选项B' }, ]; it('应渲染所有选项按钮', () => { render(); expect(screen.getByRole('button', { name: /选项A/i })).toBeInTheDocument(); expect(screen.getByRole('button', { name: /选项B/i })).toBeInTheDocument(); }); it('应高亮当前选中的按钮', () => { render(); const buttonA = screen.getByRole('button', { name: /选项A/i }); const buttonB = screen.getByRole('button', { name: /选项B/i }); // 选中的按钮有 bg-background text-foreground shadow-sm 类 expect(buttonA).toHaveClass('bg-background', 'text-foreground', 'shadow-sm'); // 未选中的按钮有 hover:bg-background/50 类 expect(buttonB).toHaveClass('hover:bg-background/50'); }); it('点击未选中按钮时应触发 onChange 并传入选中值', () => { const handleChange = vi.fn(); render(); fireEvent.click(screen.getByRole('button', { name: /选项B/i })); expect(handleChange).toHaveBeenCalledTimes(1); expect(handleChange).toHaveBeenCalledWith('b'); }); it('点击已选中按钮时不应触发 onChange', () => { const handleChange = vi.fn(); render(); fireEvent.click(screen.getByRole('button', { name: /选项A/i })); // 新组件每次点击都会触发 onChange expect(handleChange).toHaveBeenCalledWith('a'); }); it('应支持通过 className 自定义样式', () => { const { container } = render( , ); const group = container.firstChild; expect(group).toHaveClass('custom-group'); }); it('应支持 size 属性', () => { render(); const button = screen.getByRole('button', { name: /选项A/i }); expect(button).toHaveClass('text-xs'); }); it('应支持 buttonSx 自定义按钮样式', () => { render(); const button = screen.getByRole('button', { name: /选项A/i }); expect(button).toBeInTheDocument(); }); it('应支持 ReactNode 类型的 label', () => { const nodeOptions = [{ value: 'x', label: 自定义 }]; render(); expect(screen.getByTestId('custom-label')).toBeInTheDocument(); }); it('默认按钮样式应禁止文字换行', () => { render(); const button = screen.getByRole('button', { name: /选项A/i }); expect(button).toHaveClass('whitespace-nowrap'); }); it('buttonSx 传入时应覆盖默认换行样式', () => { render(); const button = screen.getByRole('button', { name: /选项A/i }); expect(button).toBeInTheDocument(); }); describe('number 类型支持', () => { const numberOptions = [ { value: 2, label: '2' }, { value: 4, label: '4' }, ]; it('应支持 number 类型的 value 渲染', () => { render(); expect(screen.getByRole('button', { name: /^2$/i })).toBeInTheDocument(); expect(screen.getByRole('button', { name: /^4$/i })).toBeInTheDocument(); }); it('应高亮 number 类型的当前选中项', () => { render(); const button2 = screen.getByRole('button', { name: /^2$/i }); const button4 = screen.getByRole('button', { name: /^4$/i }); expect(button2).toHaveClass('hover:bg-background/50'); expect(button4).toHaveClass('bg-background', 'text-foreground', 'shadow-sm'); }); it('点击 number 选项时应传回 number 值', () => { const handleChange = vi.fn(); render(); fireEvent.click(screen.getByRole('button', { name: /^4$/i })); expect(handleChange).toHaveBeenCalledTimes(1); expect(handleChange).toHaveBeenCalledWith(4); }); }); });