import { describe, it, expect, vi, beforeEach } from 'vitest' import { render, screen, fireEvent, waitFor } from '@testing-library/svelte' import DeckPreview from './DeckPreview.svelte' import { auth } from '../lib/stores/auth.js' const mockPush = vi.fn() vi.mock('svelte-spa-router', () => ({ push: (...args) => mockPush(...args), })) vi.mock('../lib/stores/auth.js', () => { const { writable } = require('svelte/store') const store = writable({ user: { id: 'u1' }, loading: false, error: null }) return { auth: { subscribe: store.subscribe, set: store.set } } }) const mockFetchDeckWithQuestions = vi.fn() const mockUserHasDeck = vi.fn() const mockCopyDeckToUser = vi.fn() vi.mock('../lib/api/decks.js', () => ({ fetchDeckWithQuestions: (...args) => mockFetchDeckWithQuestions(...args), userHasDeck: (...args) => mockUserHasDeck(...args), copyDeckToUser: (...args) => mockCopyDeckToUser(...args), })) describe('DeckPreview', () => { beforeEach(() => { vi.clearAllMocks() auth.set({ user: { id: 'u1' }, loading: false, error: null }) mockFetchDeckWithQuestions.mockResolvedValue({ id: 'd1', title: 'Preview Deck', description: 'Desc', published: true, owner_id: 'o1', copied_from_deck_id: null, questions: [{ prompt: 'Q?', answers: ['A'], correct_answer_indices: [0] }], }) mockUserHasDeck.mockResolvedValue(false) }) it('loads and shows deck title', async () => { render(DeckPreview, { props: { params: { id: 'd1' } } }) expect(screen.getByText('Loading deck…')).toBeInTheDocument() await waitFor(() => expect(screen.getByText('Preview Deck')).toBeInTheDocument()) expect(mockFetchDeckWithQuestions).toHaveBeenCalledWith(expect.anything(), 'd1') }) it('shows error when deck not available', async () => { mockFetchDeckWithQuestions.mockResolvedValue({ id: 'd1', title: 'Private', published: false, owner_id: 'o1', questions: [], }) render(DeckPreview, { props: { params: { id: 'd1' } } }) await waitFor(() => expect(screen.getByText('This deck is not available.')).toBeInTheDocument()) }) it('goBack pushes to community for published deck', async () => { render(DeckPreview, { props: { params: { id: 'd1' } } }) await waitFor(() => expect(screen.getByText('Preview Deck')).toBeInTheDocument()) await fireEvent.click(screen.getByRole('button', { name: /Community/ })) expect(mockPush).toHaveBeenCalledWith('/community') }) it('addToMyDecks calls copyDeckToUser', async () => { render(DeckPreview, { props: { params: { id: 'd1' } } }) await waitFor(() => expect(screen.getByText('Preview Deck')).toBeInTheDocument()) const addBtn = screen.getByRole('button', { name: /Add to My decks/i }) mockCopyDeckToUser.mockResolvedValue(undefined) await fireEvent.click(addBtn) await waitFor(() => expect(mockCopyDeckToUser).toHaveBeenCalledWith(expect.anything(), 'd1', 'u1')) }) it('addToMyDecks without userId shows sign in error', async () => { auth.set({ user: null, loading: false, error: null }) render(DeckPreview, { props: { params: { id: 'd1' } } }) await waitFor(() => expect(screen.getByText('Preview Deck')).toBeInTheDocument()) const addBtn = screen.getByRole('button', { name: /Add to My decks/i }) await fireEvent.click(addBtn) expect(screen.getByText(/Sign in to add this deck/)).toBeInTheDocument() }) })