/** * Unit Tests: ELO Recalculation * * Tests the idempotent full recalculation of ELO ratings and player statistics */ /* eslint-disable @typescript-eslint/no-explicit-any */ import { describe, test, expect, beforeEach, mock } from 'bun:test'; import { recalculateAllElo } from '@/lib/elo-utils'; // Mock Prisma client const mockPrisma = { player: { updateMany: mock(async () => ({ count: 0 })), update: mock(async () => ({})), }, eloSnapshot: { deleteMany: mock(async () => ({ count: 0 })), create: mock(async () => ({})), }, partnershipStat: { deleteMany: mock(async () => ({ count: 0 })), findFirst: mock(async () => null), // No existing stats initially update: mock(async () => ({})), create: mock(async () => ({})), }, match: { findMany: mock(async () => []), }, }; describe('recalculateAllElo', () => { beforeEach(() => { mock.clearAllMocks(); }); test('should reset all player stats to zero', async () => { (mockPrisma.match.findMany as any).mockResolvedValue([]); const result = await recalculateAllElo(mockPrisma as any); expect(mockPrisma.player.updateMany).toHaveBeenCalledWith({ data: { currentElo: 1000, gamesPlayed: 0, wins: 0, losses: 0, }, }); expect(result.matchesProcessed).toBe(0); expect(result.playersUpdated).toBe(0); expect(result.partnershipsUpdated).toBe(0); }); test('should delete all existing elo snapshots', async () => { (mockPrisma.match.findMany as any).mockResolvedValue([]); await recalculateAllElo(mockPrisma as any); expect(mockPrisma.eloSnapshot.deleteMany).toHaveBeenCalledWith({}); }); test('should delete all existing partnership stats', async () => { (mockPrisma.match.findMany as any).mockResolvedValue([]); await recalculateAllElo(mockPrisma as any); expect(mockPrisma.partnershipStat.deleteMany).toHaveBeenCalledWith({}); }); test('should return correct result for empty match list', async () => { (mockPrisma.match.findMany as any).mockResolvedValue([]); const result = await recalculateAllElo(mockPrisma as any); expect(result).toEqual({ matchesProcessed: 0, playersUpdated: 0, partnershipsUpdated: 0, }); }); test('should process matches in chronological order', async () => { const mockMatches = [ { id: 1, playedAt: new Date('2024-01-01'), team1P1: { id: 1, name: 'Player 1' }, team1P2: { id: 2, name: 'Player 2' }, team2P1: { id: 3, name: 'Player 3' }, team2P2: { id: 4, name: 'Player 4' }, team1Score: 10, team2Score: 5, }, { id: 2, playedAt: new Date('2024-01-02'), team1P1: { id: 1, name: 'Player 1' }, team1P2: { id: 2, name: 'Player 2' }, team2P1: { id: 5, name: 'Player 5' }, team2P2: { id: 6, name: 'Player 6' }, team1Score: 8, team2Score: 6, }, ]; (mockPrisma.match.findMany as any).mockResolvedValue(mockMatches); await recalculateAllElo(mockPrisma as any); // Should process 2 matches expect(mockPrisma.match.findMany).toHaveBeenCalledWith({ orderBy: { playedAt: 'asc' }, include: { team1P1: true, team1P2: true, team2P1: true, team2P2: true, }, }); }); test('should create elo snapshots for each player in each match', async () => { const mockMatches = [ { id: 1, playedAt: new Date('2024-01-01'), team1P1: { id: 1, name: 'Player 1' }, team1P2: { id: 2, name: 'Player 2' }, team2P1: { id: 3, name: 'Player 3' }, team2P2: { id: 4, name: 'Player 4' }, team1Score: 10, team2Score: 5, }, ]; (mockPrisma.match.findMany as any).mockResolvedValue(mockMatches); await recalculateAllElo(mockPrisma as any); // Should create 4 snapshots (one for each player) expect(mockPrisma.eloSnapshot.create).toHaveBeenCalledTimes(4); }); test('should update player stats after processing matches', async () => { const mockMatches = [ { id: 1, playedAt: new Date('2024-01-01'), team1P1: { id: 1, name: 'Player 1' }, team1P2: { id: 2, name: 'Player 2' }, team2P1: { id: 3, name: 'Player 3' }, team2P2: { id: 4, name: 'Player 4' }, team1Score: 10, team2Score: 5, }, ]; (mockPrisma.match.findMany as any).mockResolvedValue(mockMatches); await recalculateAllElo(mockPrisma as any); // Should update 4 players expect(mockPrisma.player.update).toHaveBeenCalledTimes(4); }); test('should update partnership stats after processing matches', async () => { const mockMatches = [ { id: 1, playedAt: new Date('2024-01-01'), team1P1: { id: 1, name: 'Player 1' }, team1P2: { id: 2, name: 'Player 2' }, team2P1: { id: 3, name: 'Player 3' }, team2P2: { id: 4, name: 'Player 4' }, team1Score: 10, team2Score: 5, }, ]; (mockPrisma.match.findMany as any).mockResolvedValue(mockMatches); await recalculateAllElo(mockPrisma as any); // Should check for existing partnership stats (2 calls) and create new ones (2 calls) expect(mockPrisma.partnershipStat.findFirst).toHaveBeenCalledTimes(2); expect(mockPrisma.partnershipStat.create).toHaveBeenCalledTimes(2); }); });