import { describe, it, expect, beforeEach, vi } from 'vitest' import { useReviewDataStore } from '../useReviewDataStore' import { mockDueCards } from '@/lib/mock/reviewMockData' // Mock flashcardsService vi.mock('@/lib/services/flashcards', () => ({ flashcardsService: { getDueFlashcards: vi.fn() } })) // Mock isTestMode vi.mock('@/lib/mock/reviewMockData', async (importOriginal) => { const original: any = await importOriginal() return { ...original, isTestMode: vi.fn(), getMockDueCards: vi.fn(() => mockDueCards) } }) describe('useReviewDataStore', () => { beforeEach(() => { // 重置 store 到初始狀態 useReviewDataStore.getState().resetData() vi.clearAllMocks() }) describe('初始狀態', () => { it('應該有正確的初始值', () => { const state = useReviewDataStore.getState() expect(state.dueCards).toEqual([]) expect(state.showComplete).toBe(false) expect(state.showNoDueCards).toBe(false) expect(state.isLoadingCards).toBe(false) expect(state.loadingError).toBe(null) }) }) describe('loadDueCards 測試模式', () => { beforeEach(() => { vi.mocked(require('@/lib/mock/reviewMockData').isTestMode).mockReturnValue(true) }) it('應該在測試模式下載入 Mock 數據', async () => { const store = useReviewDataStore.getState() await store.loadDueCards() expect(store.dueCards).toEqual(mockDueCards) expect(store.showNoDueCards).toBe(false) expect(store.showComplete).toBe(false) expect(store.isLoadingCards).toBe(false) }) it('應該正確設置載入狀態', async () => { const store = useReviewDataStore.getState() // 開始載入時檢查狀態 const loadPromise = store.loadDueCards() expect(store.isLoadingCards).toBe(true) // 等待完成 await loadPromise expect(store.isLoadingCards).toBe(false) }) it('應該在測試模式下不呼叫真實 API', async () => { const { flashcardsService } = await import('@/lib/services/flashcards') const store = useReviewDataStore.getState() await store.loadDueCards() expect(flashcardsService.getDueFlashcards).not.toHaveBeenCalled() }) }) describe('loadDueCards 正常模式', () => { beforeEach(() => { vi.mocked(require('@/lib/mock/reviewMockData').isTestMode).mockReturnValue(false) }) it('應該成功載入後端數據', async () => { const { flashcardsService } = await import('@/lib/services/flashcards') // 創建符合 Flashcard 類型的 Mock 數據 const mockFlashcard = { id: 'mock-1', word: 'hello', translation: '你好', definition: 'used as a greeting', partOfSpeech: 'interjection', pronunciation: '/həˈloʊ/', example: 'Hello, how are you today?', exampleTranslation: '你好,你今天好嗎?', masteryLevel: 0, timesReviewed: 0, isFavorite: false, nextReviewDate: '2025-10-03T00:00:00Z', // 必填欄位 cefr: 'A1', createdAt: '2024-01-01T00:00:00Z', updatedAt: '2024-01-01T00:00:00Z', exampleImages: [], hasExampleImage: false, primaryImageUrl: undefined } const mockApiResponse = { success: true, data: [mockFlashcard] } vi.mocked(flashcardsService.getDueFlashcards).mockResolvedValue(mockApiResponse) const store = useReviewDataStore.getState() await store.loadDueCards() // 期望轉換後的 ExtendedFlashcard 格式 expect(store.dueCards).toHaveLength(1) expect(store.dueCards[0].word).toBe('hello') expect(store.dueCards[0].synonyms).toEqual([]) // 轉換層添加的預設值 expect(store.showNoDueCards).toBe(false) expect(flashcardsService.getDueFlashcards).toHaveBeenCalledWith(50) }) it('應該處理 API 錯誤', async () => { const { flashcardsService } = await import('@/lib/services/flashcards') vi.mocked(flashcardsService.getDueFlashcards).mockRejectedValue(new Error('API錯誤')) const store = useReviewDataStore.getState() await store.loadDueCards() expect(store.dueCards).toEqual([]) expect(store.showNoDueCards).toBe(true) expect(store.loadingError).toBe('載入詞卡失敗') }) it('應該處理空數據回應', async () => { const { flashcardsService } = await import('@/lib/services/flashcards') const mockApiResponse = { success: true, data: [] } vi.mocked(flashcardsService.getDueFlashcards).mockResolvedValue(mockApiResponse) const store = useReviewDataStore.getState() await store.loadDueCards() expect(store.dueCards).toEqual([]) expect(store.showNoDueCards).toBe(true) }) }) describe('工具方法', () => { beforeEach(() => { const store = useReviewDataStore.getState() store.setDueCards(mockDueCards) }) it('getDueCardsCount 應該返回正確數量', () => { const store = useReviewDataStore.getState() expect(store.getDueCardsCount()).toBe(3) }) it('findCardById 應該找到正確的詞卡', () => { const store = useReviewDataStore.getState() const foundCard = store.findCardById('mock-1') expect(foundCard).toBeDefined() expect(foundCard?.word).toBe('hello') }) it('findCardById 應該在找不到時返回 undefined', () => { const store = useReviewDataStore.getState() const foundCard = store.findCardById('non-existent') expect(foundCard).toBeUndefined() }) }) describe('resetData', () => { it('應該重置所有狀態為初始值', () => { const store = useReviewDataStore.getState() // 設置一些狀態 store.setDueCards(mockDueCards) store.setShowComplete(true) store.setShowNoDueCards(true) store.setLoadingError('錯誤') // 重置 store.resetData() expect(store.dueCards).toEqual([]) expect(store.showComplete).toBe(false) expect(store.showNoDueCards).toBe(false) expect(store.loadingError).toBe(null) expect(store.isLoadingCards).toBe(false) }) }) })