Add show rankings
This commit is contained in:
parent
cc30b13383
commit
3655d4d456
2 changed files with 282 additions and 9 deletions
206
tests/components/Podium.test.tsx
Normal file
206
tests/components/Podium.test.tsx
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
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<Record<string, unknown>>) => <div {...props}>{children}</div>,
|
||||
},
|
||||
AnimatePresence: ({ children }: React.PropsWithChildren) => <>{children}</>,
|
||||
}));
|
||||
|
||||
vi.mock('canvas-confetti', () => ({
|
||||
default: vi.fn(),
|
||||
}));
|
||||
|
||||
describe('Podium', () => {
|
||||
const createPlayer = (overrides: Partial<Player> = {}): 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(<Podium players={defaultPlayers} onRestart={mockOnRestart} />);
|
||||
|
||||
expect(screen.getByText('Podium')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('displays top 3 players on podium', () => {
|
||||
render(<Podium players={defaultPlayers} onRestart={mockOnRestart} />);
|
||||
|
||||
expect(screen.getByText('Alice')).toBeInTheDocument();
|
||||
expect(screen.getByText('Bob')).toBeInTheDocument();
|
||||
expect(screen.getByText('Charlie')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows Play Again button', () => {
|
||||
render(<Podium players={defaultPlayers} onRestart={mockOnRestart} />);
|
||||
|
||||
expect(screen.getByText('Play Again')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('calls onRestart when Play Again clicked', async () => {
|
||||
const user = userEvent.setup();
|
||||
render(<Podium players={defaultPlayers} onRestart={mockOnRestart} />);
|
||||
|
||||
await user.click(screen.getByText('Play Again'));
|
||||
|
||||
expect(mockOnRestart).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('all rankings feature', () => {
|
||||
it('shows All Rankings button', () => {
|
||||
render(<Podium players={defaultPlayers} onRestart={mockOnRestart} />);
|
||||
|
||||
expect(screen.getByText('All Rankings')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('opens rankings modal when All Rankings clicked', async () => {
|
||||
const user = userEvent.setup();
|
||||
render(<Podium players={defaultPlayers} onRestart={mockOnRestart} />);
|
||||
|
||||
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(<Podium players={players} onRestart={mockOnRestart} />);
|
||||
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(<Podium players={defaultPlayers} onRestart={mockOnRestart} />);
|
||||
|
||||
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(<Podium players={defaultPlayers} onRestart={mockOnRestart} />);
|
||||
|
||||
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(<Podium players={defaultPlayers} onRestart={mockOnRestart} />);
|
||||
|
||||
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(<Podium players={defaultPlayers} onRestart={mockOnRestart} />);
|
||||
|
||||
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(<Podium players={manyPlayers} onRestart={mockOnRestart} />);
|
||||
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(<Podium players={singlePlayer} onRestart={mockOnRestart} />);
|
||||
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(<Podium players={tiedPlayers} onRestart={mockOnRestart} />);
|
||||
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');
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue