225 lines
6.3 KiB
TypeScript
225 lines
6.3 KiB
TypeScript
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
|
import { useTestResultStore } from '../useTestResultStore'
|
|
|
|
// Mock flashcardsService
|
|
const mockFlashcardsService = {
|
|
recordTestCompletion: vi.fn()
|
|
}
|
|
|
|
vi.mock('@/lib/services/flashcards', () => ({
|
|
flashcardsService: mockFlashcardsService
|
|
}))
|
|
|
|
// Mock isTestMode
|
|
vi.mock('@/lib/mock/reviewMockData', () => ({
|
|
isTestMode: vi.fn()
|
|
}))
|
|
|
|
describe('useTestResultStore', () => {
|
|
beforeEach(() => {
|
|
// 重置 store
|
|
useTestResultStore.getState().resetScore()
|
|
vi.clearAllMocks()
|
|
})
|
|
|
|
describe('初始狀態', () => {
|
|
it('應該有正確的初始值', () => {
|
|
const state = useTestResultStore.getState()
|
|
|
|
expect(state.score).toEqual({ correct: 0, total: 0 })
|
|
expect(state.isRecordingResult).toBe(false)
|
|
expect(state.recordingError).toBe(null)
|
|
})
|
|
})
|
|
|
|
describe('updateScore', () => {
|
|
it('應該正確更新正確答案分數', () => {
|
|
const store = useTestResultStore.getState()
|
|
|
|
store.updateScore(true)
|
|
expect(store.score).toEqual({ correct: 1, total: 1 })
|
|
|
|
store.updateScore(true)
|
|
expect(store.score).toEqual({ correct: 2, total: 2 })
|
|
})
|
|
|
|
it('應該正確更新錯誤答案分數', () => {
|
|
const store = useTestResultStore.getState()
|
|
|
|
store.updateScore(false)
|
|
expect(store.score).toEqual({ correct: 0, total: 1 })
|
|
|
|
store.updateScore(true)
|
|
expect(store.score).toEqual({ correct: 1, total: 2 })
|
|
})
|
|
})
|
|
|
|
describe('recordTestResult 測試模式', () => {
|
|
beforeEach(() => {
|
|
vi.mocked(require('@/lib/mock/reviewMockData').isTestMode).mockReturnValue(true)
|
|
})
|
|
|
|
it('應該在測試模式下跳過 API 呼叫', async () => {
|
|
const store = useTestResultStore.getState()
|
|
|
|
const result = await store.recordTestResult({
|
|
flashcardId: 'mock-1',
|
|
testType: 'flip-memory',
|
|
isCorrect: true,
|
|
userAnswer: 'test',
|
|
confidenceLevel: 4
|
|
})
|
|
|
|
expect(result).toBe(true)
|
|
expect(mockFlashcardsService.recordTestCompletion).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('應該正確設置錄製狀態', async () => {
|
|
const store = useTestResultStore.getState()
|
|
|
|
// 開始錄製時檢查狀態
|
|
const recordPromise = store.recordTestResult({
|
|
flashcardId: 'mock-1',
|
|
testType: 'flip-memory',
|
|
isCorrect: true
|
|
})
|
|
|
|
expect(store.isRecordingResult).toBe(true)
|
|
|
|
// 等待完成
|
|
await recordPromise
|
|
expect(store.isRecordingResult).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('recordTestResult 正常模式', () => {
|
|
beforeEach(() => {
|
|
vi.mocked(require('@/lib/mock/reviewMockData').isTestMode).mockReturnValue(false)
|
|
})
|
|
|
|
it('應該成功記錄測驗結果', async () => {
|
|
mockFlashcardsService.recordTestCompletion.mockResolvedValue({
|
|
success: true
|
|
})
|
|
|
|
const store = useTestResultStore.getState()
|
|
const testParams = {
|
|
flashcardId: 'mock-1',
|
|
testType: 'flip-memory' as any,
|
|
isCorrect: true,
|
|
userAnswer: 'hello',
|
|
confidenceLevel: 4,
|
|
responseTimeMs: 2000
|
|
}
|
|
|
|
const result = await store.recordTestResult(testParams)
|
|
|
|
expect(result).toBe(true)
|
|
expect(mockFlashcardsService.recordTestCompletion).toHaveBeenCalledWith(testParams)
|
|
})
|
|
|
|
it('應該處理 API 失敗', async () => {
|
|
mockFlashcardsService.recordTestCompletion.mockResolvedValue({
|
|
success: false,
|
|
error: 'API錯誤'
|
|
})
|
|
|
|
const store = useTestResultStore.getState()
|
|
|
|
const result = await store.recordTestResult({
|
|
flashcardId: 'mock-1',
|
|
testType: 'flip-memory',
|
|
isCorrect: true
|
|
})
|
|
|
|
expect(result).toBe(false)
|
|
expect(store.recordingError).toBe('記錄測驗結果失敗')
|
|
})
|
|
|
|
it('應該處理網路異常', async () => {
|
|
mockFlashcardsService.recordTestCompletion.mockRejectedValue(
|
|
new Error('Network error')
|
|
)
|
|
|
|
const store = useTestResultStore.getState()
|
|
|
|
const result = await store.recordTestResult({
|
|
flashcardId: 'mock-1',
|
|
testType: 'flip-memory',
|
|
isCorrect: true
|
|
})
|
|
|
|
expect(result).toBe(false)
|
|
expect(store.recordingError).toBe('記錄測驗結果異常')
|
|
})
|
|
|
|
it('應該設置預設 responseTimeMs', async () => {
|
|
mockFlashcardsService.recordTestCompletion.mockResolvedValue({
|
|
success: true
|
|
})
|
|
|
|
const store = useTestResultStore.getState()
|
|
|
|
await store.recordTestResult({
|
|
flashcardId: 'mock-1',
|
|
testType: 'flip-memory',
|
|
isCorrect: true
|
|
})
|
|
|
|
expect(mockFlashcardsService.recordTestCompletion).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
responseTimeMs: 2000
|
|
})
|
|
)
|
|
})
|
|
})
|
|
|
|
describe('統計方法', () => {
|
|
beforeEach(() => {
|
|
const store = useTestResultStore.getState()
|
|
// 設置一些分數數據
|
|
store.updateScore(true) // 1/1
|
|
store.updateScore(true) // 2/2
|
|
store.updateScore(false) // 2/3
|
|
store.updateScore(true) // 3/4
|
|
})
|
|
|
|
it('getAccuracyPercentage 應該計算正確的準確率', () => {
|
|
const store = useTestResultStore.getState()
|
|
|
|
const accuracy = store.getAccuracyPercentage()
|
|
expect(accuracy).toBe(75) // 3/4 = 75%
|
|
})
|
|
|
|
it('getTotalAttempts 應該返回總嘗試次數', () => {
|
|
const store = useTestResultStore.getState()
|
|
|
|
const total = store.getTotalAttempts()
|
|
expect(total).toBe(4)
|
|
})
|
|
|
|
it('應該在無嘗試時返回 0%', () => {
|
|
const store = useTestResultStore.getState()
|
|
store.resetScore()
|
|
|
|
expect(store.getAccuracyPercentage()).toBe(0)
|
|
expect(store.getTotalAttempts()).toBe(0)
|
|
})
|
|
})
|
|
|
|
describe('resetScore', () => {
|
|
it('應該重置分數和錯誤狀態', () => {
|
|
const store = useTestResultStore.getState()
|
|
|
|
// 設置一些狀態
|
|
store.updateScore(true)
|
|
store.setRecordingError('某個錯誤')
|
|
|
|
// 重置
|
|
store.resetScore()
|
|
|
|
expect(store.score).toEqual({ correct: 0, total: 0 })
|
|
expect(store.recordingError).toBe(null)
|
|
})
|
|
})
|
|
}) |