import React from 'react'; import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { describe, it, expect, vi, beforeEach } from 'vitest'; import { Podium } from '../../components/Podium'; import { Player } from '../../types'; vi.mock('framer-motion', () => ({ motion: { div: ({ children, ...props }: React.PropsWithChildren>) =>
{children}
, }, AnimatePresence: ({ children }: React.PropsWithChildren) => <>{children}, })); vi.mock('canvas-confetti', () => ({ default: vi.fn(), })); describe('Podium', () => { const createPlayer = (overrides: Partial = {}): Player => ({ id: 'player-1', name: 'Test Player', score: 100, previousScore: 0, streak: 0, lastAnswerCorrect: null, selectedShape: null, pointsBreakdown: null, isBot: false, avatarSeed: 0.5, color: '#ff0000', ...overrides, }); const defaultPlayers = [ createPlayer({ id: '1', name: 'Alice', score: 300 }), createPlayer({ id: '2', name: 'Bob', score: 200 }), createPlayer({ id: '3', name: 'Charlie', score: 100 }), ]; const mockOnRestart = vi.fn(); beforeEach(() => { vi.clearAllMocks(); }); describe('podium display', () => { it('renders podium title', () => { render(); expect(screen.getByText('Podium')).toBeInTheDocument(); }); it('displays top 3 players on podium', () => { render(); expect(screen.getByText('Alice')).toBeInTheDocument(); expect(screen.getByText('Bob')).toBeInTheDocument(); expect(screen.getByText('Charlie')).toBeInTheDocument(); }); it('shows Play Again button', () => { render(); expect(screen.getByText('Play Again')).toBeInTheDocument(); }); it('calls onRestart when Play Again clicked', async () => { const user = userEvent.setup(); render(); await user.click(screen.getByText('Play Again')); expect(mockOnRestart).toHaveBeenCalled(); }); }); describe('all rankings feature', () => { it('shows All Rankings button', () => { render(); expect(screen.getByText('All Rankings')).toBeInTheDocument(); }); it('opens rankings modal when All Rankings clicked', async () => { const user = userEvent.setup(); render(); await user.click(screen.getByText('All Rankings')); expect(screen.getByText('Final Rankings')).toBeInTheDocument(); }); it('shows all players in rankings modal', async () => { const user = userEvent.setup(); const players = [ createPlayer({ id: '1', name: 'RankAlice', score: 300 }), createPlayer({ id: '2', name: 'RankBob', score: 100 }), createPlayer({ id: '3', name: 'RankCharlie', score: 200 }), createPlayer({ id: '4', name: 'RankDiana', score: 50 }), ]; render(); await user.click(screen.getByText('All Rankings')); const modal = screen.getByText('Final Rankings').parentElement?.parentElement; expect(modal).toHaveTextContent('RankAlice'); expect(modal).toHaveTextContent('RankBob'); expect(modal).toHaveTextContent('RankCharlie'); expect(modal).toHaveTextContent('RankDiana'); }); it('shows rank numbers in modal', async () => { const user = userEvent.setup(); render(); await user.click(screen.getByText('All Rankings')); expect(screen.getByText('1')).toBeInTheDocument(); expect(screen.getByText('2')).toBeInTheDocument(); expect(screen.getByText('3')).toBeInTheDocument(); }); it('shows player scores in modal', async () => { const user = userEvent.setup(); render(); await user.click(screen.getByText('All Rankings')); const modal = screen.getByText('Final Rankings').parentElement?.parentElement; expect(modal).toHaveTextContent('300'); expect(modal).toHaveTextContent('200'); expect(modal).toHaveTextContent('100'); }); it('closes modal when X button clicked', async () => { const user = userEvent.setup(); render(); await user.click(screen.getByText('All Rankings')); expect(screen.getByText('Final Rankings')).toBeInTheDocument(); const modal = screen.getByText('Final Rankings').parentElement; const closeButton = modal?.querySelector('button'); await user.click(closeButton!); expect(screen.queryByText('Final Rankings')).not.toBeInTheDocument(); }); it('modal content does not close when clicking inside', async () => { const user = userEvent.setup(); render(); await user.click(screen.getByText('All Rankings')); expect(screen.getByText('Final Rankings')).toBeInTheDocument(); await user.click(screen.getByText('Final Rankings')); expect(screen.getByText('Final Rankings')).toBeInTheDocument(); }); it('handles many players in rankings', async () => { const user = userEvent.setup(); const manyPlayers = Array.from({ length: 20 }, (_, i) => createPlayer({ id: `${i}`, name: `ManyPlayer${i + 1}`, score: 1000 - i * 50 }) ); render(); await user.click(screen.getByText('All Rankings')); const modal = screen.getByText('Final Rankings').parentElement?.parentElement; expect(modal).toHaveTextContent('ManyPlayer1'); expect(modal).toHaveTextContent('ManyPlayer20'); }); it('handles single player', async () => { const user = userEvent.setup(); const singlePlayer = [createPlayer({ id: '1', name: 'SoloPlayer', score: 500 })]; render(); await user.click(screen.getByText('All Rankings')); const modal = screen.getByText('Final Rankings').parentElement?.parentElement; expect(modal).toHaveTextContent('SoloPlayer'); expect(modal).toHaveTextContent('500'); }); it('handles players with same score', async () => { const user = userEvent.setup(); const tiedPlayers = [ createPlayer({ id: '1', name: 'TiedAlice', score: 200 }), createPlayer({ id: '2', name: 'TiedBob', score: 200 }), createPlayer({ id: '3', name: 'TiedCharlie', score: 200 }), ]; render(); await user.click(screen.getByText('All Rankings')); expect(screen.getByText('Final Rankings')).toBeInTheDocument(); const modal = screen.getByText('Final Rankings').parentElement?.parentElement; expect(modal).toHaveTextContent('TiedAlice'); expect(modal).toHaveTextContent('TiedBob'); expect(modal).toHaveTextContent('TiedCharlie'); }); }); });