import { Standing } from '@core/racing/domain/entities/Standing'; import type { Logger } from '@core/shared/domain/Logger'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import { InMemoryStandingRepository } from './InMemoryStandingRepository'; /* eslint-disable @typescript-eslint/no-explicit-any */ describe('InMemoryStandingRepository', () => { let repository: InMemoryStandingRepository; let mockLogger: Logger; let mockResultRepository: any; let mockRaceRepository: any; let mockLeagueRepository: any; const testPointsSystems: Record> = { 'f1-2024': { 1: 25, 2: 18, 3: 15, 4: 12, 5: 10, 6: 8, 7: 6, 8: 4, 9: 2, 10: 1 }, 'indycar': { 1: 50, 2: 40, 3: 35, 4: 32, 5: 30, 6: 28, 7: 26, 8: 24, 9: 22, 10: 20, 11: 19, 12: 18, 13: 17, 14: 16, 15: 15 } }; beforeEach(() => { mockLogger = { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn(), }; // eslint-disable-next-line @typescript-eslint/no-explicit-any mockResultRepository = { findById: vi.fn(), findAll: vi.fn(), findByRaceId: vi.fn(), findByDriverId: vi.fn(), findByDriverIdAndLeagueId: vi.fn(), create: vi.fn(), createMany: vi.fn(), update: vi.fn(), delete: vi.fn(), deleteByRaceId: vi.fn(), exists: vi.fn(), existsByRaceId: vi.fn(), } as any; // eslint-disable-next-line @typescript-eslint/no-explicit-any mockRaceRepository = { findById: vi.fn(), findAll: vi.fn(), findByLeagueId: vi.fn(), findUpcomingByLeagueId: vi.fn(), findCompletedByLeagueId: vi.fn(), findByStatus: vi.fn(), findByDateRange: vi.fn(), create: vi.fn(), update: vi.fn(), delete: vi.fn(), exists: vi.fn(), } as any; // eslint-disable-next-line @typescript-eslint/no-explicit-any mockLeagueRepository = { findById: vi.fn(), findByOwnerId: vi.fn(), searchByName: vi.fn(), findAll: vi.fn(), create: vi.fn(), update: vi.fn(), delete: vi.fn(), exists: vi.fn(), } as any; repository = new InMemoryStandingRepository( mockLogger, testPointsSystems, mockResultRepository, mockRaceRepository, mockLeagueRepository ); }); const createTestStanding = (leagueId: string, driverId: string, position: number = 1, points: number = 0) => { return Standing.create({ leagueId, driverId, position, points, }); }; describe('constructor', () => { it('should initialize with required parameters', () => { expect(repository).toBeDefined(); expect(mockLogger.info).toHaveBeenCalledWith('InMemoryStandingRepository initialized.'); }); }); describe('findByLeagueId', () => { it('should return standings for the specified league', async () => { const standing1 = createTestStanding('league1', 'driver1', 1, 25); const standing2 = createTestStanding('league1', 'driver2', 2, 18); const standing3 = createTestStanding('league2', 'driver3', 1, 50); await repository.save(standing1); await repository.save(standing2); await repository.save(standing3); const result = await repository.findByLeagueId('league1'); expect(result).toHaveLength(2); expect(result[0]).toEqual(standing1); expect(result[1]).toEqual(standing2); }); it('should return empty array if no standings for league', async () => { const result = await repository.findByLeagueId('nonexistent'); expect(result).toEqual([]); }); it('should sort standings by position then points', async () => { const standing1 = createTestStanding('league1', 'driver1', 2, 18); const standing2 = createTestStanding('league1', 'driver2', 1, 25); await repository.save(standing1); await repository.save(standing2); const result = await repository.findByLeagueId('league1'); expect(result[0]).toEqual(standing2); // position 1 expect(result[1]).toEqual(standing1); // position 2 }); }); describe('findByDriverIdAndLeagueId', () => { it('should return the standing if found', async () => { const standing = createTestStanding('league1', 'driver1'); await repository.save(standing); const result = await repository.findByDriverIdAndLeagueId('driver1', 'league1'); expect(result).toEqual(standing); }); it('should return null if not found', async () => { const result = await repository.findByDriverIdAndLeagueId('driver1', 'league1'); expect(result).toBeNull(); }); }); describe('findAll', () => { it('should return all standings', async () => { const standing1 = createTestStanding('league1', 'driver1'); const standing2 = createTestStanding('league2', 'driver2'); await repository.save(standing1); await repository.save(standing2); const result = await repository.findAll(); expect(result).toHaveLength(2); expect(result).toContain(standing1); expect(result).toContain(standing2); }); }); describe('save', () => { it('should save a new standing', async () => { const standing = createTestStanding('league1', 'driver1'); const result = await repository.save(standing); expect(result).toEqual(standing); expect(mockLogger.info).toHaveBeenCalledWith('Standing for league league1, driver driver1 saved successfully.'); }); it('should update existing standing', async () => { const standing = createTestStanding('league1', 'driver1', 1, 25); await repository.save(standing); const updatedStanding = createTestStanding('league1', 'driver1', 1, 35); const result = await repository.save(updatedStanding); expect(result).toEqual(updatedStanding); }); }); describe('saveMany', () => { it('should save multiple standings', async () => { const standings = [ createTestStanding('league1', 'driver1'), createTestStanding('league1', 'driver2'), ]; const result = await repository.saveMany(standings); expect(result).toEqual(standings); expect(mockLogger.info).toHaveBeenCalledWith('2 standings saved successfully.'); }); }); describe('delete', () => { it('should delete existing standing', async () => { const standing = createTestStanding('league1', 'driver1'); await repository.save(standing); await repository.delete('league1', 'driver1'); const found = await repository.findByDriverIdAndLeagueId('driver1', 'league1'); expect(found).toBeNull(); expect(mockLogger.info).toHaveBeenCalledWith('Standing for league league1, driver driver1 deleted successfully.'); }); it('should log warning if standing not found', async () => { await repository.delete('league1', 'driver1'); expect(mockLogger.warn).toHaveBeenCalledWith('Standing for league league1, driver driver1 not found for deletion.'); }); }); describe('deleteByLeagueId', () => { it('should delete all standings for a league', async () => { const standing1 = createTestStanding('league1', 'driver1'); const standing2 = createTestStanding('league1', 'driver2'); const standing3 = createTestStanding('league2', 'driver3'); await repository.save(standing1); await repository.save(standing2); await repository.save(standing3); await repository.deleteByLeagueId('league1'); const league1Standings = await repository.findByLeagueId('league1'); const league2Standings = await repository.findByLeagueId('league2'); expect(league1Standings).toHaveLength(0); expect(league2Standings).toHaveLength(1); expect(mockLogger.info).toHaveBeenCalledWith('Deleted 2 standings for league id: league1.'); }); }); describe('exists', () => { it('should return true if standing exists', async () => { const standing = createTestStanding('league1', 'driver1'); await repository.save(standing); const result = await repository.exists('league1', 'driver1'); expect(result).toBe(true); }); it('should return false if standing does not exist', async () => { const result = await repository.exists('league1', 'driver1'); expect(result).toBe(false); }); }); describe('recalculate', () => { it('should throw error if repositories are missing', async () => { const repoWithoutDeps = new InMemoryStandingRepository(mockLogger, testPointsSystems); await expect(repoWithoutDeps.recalculate('league1')).rejects.toThrow('Cannot recalculate standings: missing required repositories'); }); it('should throw error if league not found', async () => { mockLeagueRepository.findById.mockResolvedValue(null); await expect(repository.recalculate('nonexistent')).rejects.toThrow('League with ID nonexistent not found'); }); it('should return empty array if no completed races', async () => { const mockLeague = { id: 'league1', settings: { pointsSystem: 'f1-2024', customPoints: null }, }; mockLeagueRepository.findById.mockResolvedValue(mockLeague); mockRaceRepository.findCompletedByLeagueId.mockResolvedValue([]); const result = await repository.recalculate('league1'); expect(result).toEqual([]); }); it('should recalculate standings based on race results', async () => { const mockLeague = { id: 'league1', settings: { pointsSystem: 'f1-2024', customPoints: null }, }; const mockRace = { id: 'race1' }; const mockResult1 = { driverId: 'driver1', position: 1 }; const mockResult2 = { driverId: 'driver2', position: 2 }; mockLeagueRepository.findById.mockResolvedValue(mockLeague); mockRaceRepository.findCompletedByLeagueId.mockResolvedValue([mockRace]); mockResultRepository.findByRaceId.mockResolvedValue([mockResult1, mockResult2]); const result = await repository.recalculate('league1'); expect(result).toHaveLength(2); expect(result[0]?.driverId.toString()).toBe('driver1'); expect(result[0]?.points.toNumber()).toBe(25); // 1st place in f1-2024 expect(result[1]?.driverId.toString()).toBe('driver2'); expect(result[1]?.points.toNumber()).toBe(18); // 2nd place }); it('should use custom points if available', async () => { const customPoints = { 1: 100, 2: 80 }; const mockLeague = { id: 'league1', settings: { pointsSystem: 'f1-2024', customPoints }, }; const mockRace = { id: 'race1' }; const mockResult = { driverId: 'driver1', position: 1 }; mockLeagueRepository.findById.mockResolvedValue(mockLeague); mockRaceRepository.findCompletedByLeagueId.mockResolvedValue([mockRace]); mockResultRepository.findByRaceId.mockResolvedValue([mockResult]); const result = await repository.recalculate('league1'); expect(result[0]?.points.toNumber()).toBe(100); }); }); });