dramaling-vocab-learning/frontend/components/review/__tests__/shared/ConfidenceButtons.test.tsx

225 lines
6.2 KiB
TypeScript

import { describe, it, expect, vi, beforeEach } from 'vitest'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { ConfidenceButtons } from '../../shared/ConfidenceButtons'
describe('ConfidenceButtons', () => {
const mockOnSelect = vi.fn()
beforeEach(() => {
vi.clearAllMocks()
})
describe('基礎渲染', () => {
it('應該渲染所有信心度按鈕', () => {
render(
<ConfidenceButtons
selectedLevel={null}
onSelect={mockOnSelect}
/>
)
expect(screen.getByText('完全不懂')).toBeInTheDocument()
expect(screen.getByText('模糊')).toBeInTheDocument()
expect(screen.getByText('一般')).toBeInTheDocument()
expect(screen.getByText('熟悉')).toBeInTheDocument()
expect(screen.getByText('非常熟悉')).toBeInTheDocument()
})
it('應該正確顯示信心度等級數字', () => {
render(
<ConfidenceButtons
selectedLevel={null}
onSelect={mockOnSelect}
/>
)
for (let i = 1; i <= 5; i++) {
expect(screen.getByText(i.toString())).toBeInTheDocument()
}
})
})
describe('選擇功能', () => {
it('應該在點擊時調用 onSelect 並傳遞正確等級', async () => {
const user = userEvent.setup()
render(
<ConfidenceButtons
selectedLevel={null}
onSelect={mockOnSelect}
/>
)
// 點擊等級 3
const level3Button = screen.getByText('一般').closest('button')
await user.click(level3Button!)
expect(mockOnSelect).toHaveBeenCalledWith(3)
})
it('應該正確處理所有等級的選擇', async () => {
const user = userEvent.setup()
render(
<ConfidenceButtons
selectedLevel={null}
onSelect={mockOnSelect}
/>
)
// 測試所有等級
const levels = ['完全不懂', '模糊', '一般', '熟悉', '非常熟悉']
for (let i = 0; i < levels.length; i++) {
const button = screen.getByText(levels[i]).closest('button')
await user.click(button!)
expect(mockOnSelect).toHaveBeenCalledWith(i + 1)
}
})
})
describe('選中狀態顯示', () => {
it('應該高亮顯示選中的等級', () => {
render(
<ConfidenceButtons
selectedLevel={3}
onSelect={mockOnSelect}
/>
)
const selectedButton = screen.getByText('一般').closest('button')
const unselectedButton = screen.getByText('熟悉').closest('button')
// 選中的按鈕應該有特殊樣式
expect(selectedButton).toHaveClass('ring-2', 'ring-blue-500')
expect(unselectedButton).not.toHaveClass('ring-2', 'ring-blue-500')
})
it('應該在沒有選擇時不高亮任何按鈕', () => {
render(
<ConfidenceButtons
selectedLevel={null}
onSelect={mockOnSelect}
/>
)
const buttons = screen.getAllByRole('button')
buttons.forEach(button => {
expect(button).not.toHaveClass('ring-2', 'ring-blue-500')
})
})
})
describe('禁用狀態', () => {
it('應該在 disabled 為 true 時禁用所有按鈕', () => {
render(
<ConfidenceButtons
selectedLevel={null}
onSelect={mockOnSelect}
disabled={true}
/>
)
const buttons = screen.getAllByRole('button')
buttons.forEach(button => {
expect(button).toBeDisabled()
})
})
it('應該在 disabled 為 false 時啟用所有按鈕', () => {
render(
<ConfidenceButtons
selectedLevel={null}
onSelect={mockOnSelect}
disabled={false}
/>
)
const buttons = screen.getAllByRole('button')
buttons.forEach(button => {
expect(button).not.toBeDisabled()
})
})
it('應該在禁用時不調用 onSelect', async () => {
const user = userEvent.setup()
render(
<ConfidenceButtons
selectedLevel={null}
onSelect={mockOnSelect}
disabled={true}
/>
)
const button = screen.getByText('熟悉').closest('button')
// 嘗試點擊禁用的按鈕
await user.click(button!)
expect(mockOnSelect).not.toHaveBeenCalled()
})
})
describe('顏色主題', () => {
it('應該為不同等級使用不同的顏色主題', () => {
render(
<ConfidenceButtons
selectedLevel={null}
onSelect={mockOnSelect}
/>
)
const level1 = screen.getByText('完全不懂').closest('button')
const level3 = screen.getByText('一般').closest('button')
const level5 = screen.getByText('非常熟悉').closest('button')
// 檢查不同等級有不同的顏色主題
expect(level1).toHaveClass('bg-red-100', 'text-red-700')
expect(level3).toHaveClass('bg-yellow-100', 'text-yellow-700')
expect(level5).toHaveClass('bg-green-100', 'text-green-700')
})
})
describe('可訪問性', () => {
it('應該有正確的 button 角色', () => {
render(
<ConfidenceButtons
selectedLevel={null}
onSelect={mockOnSelect}
/>
)
const buttons = screen.getAllByRole('button')
expect(buttons).toHaveLength(5)
})
it('應該有描述性的文字標籤', () => {
render(
<ConfidenceButtons
selectedLevel={null}
onSelect={mockOnSelect}
/>
)
// 每個按鈕都應該有清楚的文字說明
expect(screen.getByText('完全不懂')).toBeInTheDocument()
expect(screen.getByText('非常熟悉')).toBeInTheDocument()
})
})
describe('自定義 className', () => {
it('應該應用自定義的 className', () => {
const { container } = render(
<ConfidenceButtons
selectedLevel={null}
onSelect={mockOnSelect}
className="custom-class"
/>
)
expect(container.firstChild).toHaveClass('custom-class')
})
})
})