225 lines
6.2 KiB
TypeScript
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')
|
|
})
|
|
})
|
|
}) |