import { describe, it, expect, vi, beforeEach } from 'vitest'; import { GetLeagueDriverSeasonStatsUseCase } from './GetLeagueDriverSeasonStatsUseCase'; import type { IStandingRepository } from '../../domain/repositories/IStandingRepository'; import type { IResultRepository } from '../../domain/repositories/IResultRepository'; import type { IPenaltyRepository } from '../../domain/repositories/IPenaltyRepository'; import type { IRaceRepository } from '../../domain/repositories/IRaceRepository'; import type { IDriverRepository } from '../../domain/repositories/IDriverRepository'; import type { ITeamRepository } from '../../domain/repositories/ITeamRepository'; import type { DriverRatingPort } from '../ports/DriverRatingPort'; describe('GetLeagueDriverSeasonStatsUseCase', () => { const mockStandingFindByLeagueId = vi.fn(); const mockResultFindByDriverIdAndLeagueId = vi.fn(); const mockPenaltyFindByRaceId = vi.fn(); const mockRaceFindByLeagueId = vi.fn(); const mockDriverRatingGetRating = vi.fn(); const mockDriverFindById = vi.fn(); const mockTeamFindById = vi.fn(); let useCase: GetLeagueDriverSeasonStatsUseCase; let standingRepository: IStandingRepository; let resultRepository: IResultRepository; let penaltyRepository: IPenaltyRepository; let raceRepository: IRaceRepository; let driverRepository: IDriverRepository; let teamRepository: ITeamRepository; let driverRatingPort: DriverRatingPort; beforeEach(() => { standingRepository = { findByLeagueId: mockStandingFindByLeagueId, findByDriverIdAndLeagueId: vi.fn(), findAll: vi.fn(), save: vi.fn(), saveMany: vi.fn(), delete: vi.fn(), deleteByLeagueId: vi.fn(), exists: vi.fn(), recalculate: vi.fn(), }; resultRepository = { findByDriverIdAndLeagueId: mockResultFindByDriverIdAndLeagueId, }; penaltyRepository = { findByRaceId: mockPenaltyFindByRaceId, }; raceRepository = { findById: vi.fn(), findAll: vi.fn(), findByLeagueId: mockRaceFindByLeagueId, findUpcomingByLeagueId: vi.fn(), findCompletedByLeagueId: vi.fn(), findByStatus: vi.fn(), findByDateRange: vi.fn(), create: vi.fn(), update: vi.fn(), delete: vi.fn(), exists: vi.fn(), }; driverRepository = { findById: mockDriverFindById, }; teamRepository = { findById: mockTeamFindById, }; driverRatingPort = { getRating: mockDriverRatingGetRating, }; useCase = new GetLeagueDriverSeasonStatsUseCase( standingRepository, resultRepository, penaltyRepository, raceRepository, driverRepository, teamRepository, driverRatingPort, ); }); it('should return league driver season stats for given league id', async () => { const params = { leagueId: 'league-1' }; const mockStandings = [ { driverId: 'driver-1', position: 1, points: 100, racesCompleted: 5 }, { driverId: 'driver-2', position: 2, points: 80, racesCompleted: 5 }, ]; const mockRaces = [ { id: 'race-1' }, { id: 'race-2' }, ]; const mockPenalties = [ { driverId: 'driver-1', status: 'applied', type: 'points_deduction', value: 10 }, ]; const mockResults = [{ position: 1 }]; const mockRating = { rating: 1500, ratingChange: 50 }; const mockDriver = { id: 'driver-1', name: 'Driver One', teamId: 'team-1' }; const mockTeam = { id: 'team-1', name: 'Team One' }; standingRepository.findByLeagueId.mockResolvedValue(mockStandings); raceRepository.findByLeagueId.mockResolvedValue(mockRaces); penaltyRepository.findByRaceId.mockImplementation((raceId) => { if (raceId === 'race-1') return Promise.resolve(mockPenalties); return Promise.resolve([]); }); driverRatingPort.getRating.mockReturnValue(mockRating); resultRepository.findByDriverIdAndLeagueId.mockResolvedValue(mockResults); driverRepository.findById.mockImplementation((id) => { if (id === 'driver-1') return Promise.resolve(mockDriver); if (id === 'driver-2') return Promise.resolve({ id: 'driver-2', name: 'Driver Two' }); return Promise.resolve(null); }); teamRepository.findById.mockResolvedValue(mockTeam); const result = await useCase.execute(params); expect(result.isOk()).toBe(true); const output = result.value!; expect(output.leagueId).toBe('league-1'); expect(output.stats).toHaveLength(2); expect(output.stats[0]).toEqual({ leagueId: 'league-1', driverId: 'driver-1', position: 1, driverName: 'Driver One', teamId: 'team-1', teamName: 'Team One', totalPoints: 100, basePoints: 90, penaltyPoints: -10, bonusPoints: 0, pointsPerRace: 20, racesStarted: 1, racesFinished: 1, dnfs: 0, noShows: 1, avgFinish: 1, rating: 1500, ratingChange: 50, }); }); it('should handle no penalties', async () => { const params = { leagueId: 'league-1' }; const mockStandings = [{ driverId: 'driver-1', position: 1, points: 100, racesCompleted: 5 }]; const mockRaces = [{ id: 'race-1' }]; const mockResults = [{ position: 1 }]; const mockRating = { rating: null, ratingChange: null }; const mockDriver = { id: 'driver-1', name: 'Driver One' }; standingRepository.findByLeagueId.mockResolvedValue(mockStandings); raceRepository.findByLeagueId.mockResolvedValue(mockRaces); penaltyRepository.findByRaceId.mockResolvedValue([]); driverRatingPort.getRating.mockReturnValue(mockRating); resultRepository.findByDriverIdAndLeagueId.mockResolvedValue(mockResults); driverRepository.findById.mockResolvedValue(mockDriver); teamRepository.findById.mockResolvedValue(null); const result = await useCase.execute(params); expect(result.isOk()).toBe(true); const output = result.value!; expect(output.stats[0].penaltyPoints).toBe(0); }); });