import type { Logger } from '@core/shared/domain/Logger'; import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode'; import { beforeEach, describe, expect, it, vi, type Mock } from 'vitest'; import type { Penalty } from '../../domain/entities/Penalty'; import { RecalculateChampionshipStandingsUseCase, type RecalculateChampionshipStandingsErrorCode, type RecalculateChampionshipStandingsInput } from './RecalculateChampionshipStandingsUseCase'; describe('RecalculateChampionshipStandingsUseCase', () => { let useCase: RecalculateChampionshipStandingsUseCase; let leagueRepository: { findById: Mock }; let seasonRepository: { findById: Mock }; let leagueScoringConfigRepository: { findBySeasonId: Mock }; let raceRepository: { findByLeagueId: Mock }; let resultRepository: { findByRaceId: Mock }; let penaltyRepository: { findByRaceId: Mock }; let championshipStandingRepository: { saveAll: Mock }; let eventScoringService: { scoreSession: Mock }; let championshipAggregator: { aggregate: Mock }; let logger: Logger; beforeEach(() => { leagueRepository = { findById: vi.fn() }; seasonRepository = { findById: vi.fn() }; leagueScoringConfigRepository = { findBySeasonId: vi.fn() }; raceRepository = { findByLeagueId: vi.fn() }; resultRepository = { findByRaceId: vi.fn() }; penaltyRepository = { findByRaceId: vi.fn() }; championshipStandingRepository = { saveAll: vi.fn() }; eventScoringService = { scoreSession: vi.fn() }; championshipAggregator = { aggregate: vi.fn() }; logger = { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn(), } as any; useCase = new RecalculateChampionshipStandingsUseCase(leagueRepository as any, seasonRepository as any, leagueScoringConfigRepository as any, raceRepository as any, resultRepository as any, penaltyRepository as any, championshipStandingRepository as any, eventScoringService as any, championshipAggregator as any, logger); }); it('returns league not found error', async () => { leagueRepository.findById.mockResolvedValue(null); const input: RecalculateChampionshipStandingsInput = { leagueId: 'league-1', seasonId: 'season-1', }; const result = await useCase.execute(input); expect(result.isErr()).toBe(true); const error = result.unwrapErr() as ApplicationErrorCode< RecalculateChampionshipStandingsErrorCode, { message: string } >; expect(error.code).toBe('LEAGUE_NOT_FOUND'); expect(error.details.message).toContain('league-1'); }); it('returns season not found error when season does not exist', async () => { leagueRepository.findById.mockResolvedValue({ id: 'league-1' }); seasonRepository.findById.mockResolvedValue(null); const input: RecalculateChampionshipStandingsInput = { leagueId: 'league-1', seasonId: 'season-1', }; const result = await useCase.execute(input); expect(result.isErr()).toBe(true); const error = result.unwrapErr() as ApplicationErrorCode< RecalculateChampionshipStandingsErrorCode, { message: string } >; expect(error.code).toBe('SEASON_NOT_FOUND'); }); it('returns season not found error when season belongs to different league', async () => { leagueRepository.findById.mockResolvedValue({ id: 'league-1' }); seasonRepository.findById.mockResolvedValue({ id: 'season-1', leagueId: 'other-league' }); const input: RecalculateChampionshipStandingsInput = { leagueId: 'league-1', seasonId: 'season-1', }; const result = await useCase.execute(input); expect(result.isErr()).toBe(true); const error = result.unwrapErr() as ApplicationErrorCode< RecalculateChampionshipStandingsErrorCode, { message: string } >; expect(error.code).toBe('SEASON_NOT_FOUND'); }); it('recalculates standings successfully and returns result', async () => { const league = { id: 'league-1' }; const season = { id: 'season-1', leagueId: 'league-1' }; const championship = { id: 'champ-1', name: 'Champ 1', sessionTypes: ['main'], pointsTableBySessionType: {}, dropScorePolicy: {}, }; const leagueScoringConfig = { championships: [championship] }; const races = [{ id: 'race-1', sessionType: 'race' as const }]; const results: unknown[] = []; const penalties: Penalty[] = []; const standings = [ { participant: { id: 'driver-1' }, position: { toNumber: () => 1 }, totalPoints: { toNumber: () => 25 }, resultsCounted: { toNumber: () => 1 }, resultsDropped: { toNumber: () => 0 }, }, ]; leagueRepository.findById.mockResolvedValue(league); seasonRepository.findById.mockResolvedValue(season); leagueScoringConfigRepository.findBySeasonId.mockResolvedValue(leagueScoringConfig); raceRepository.findByLeagueId.mockResolvedValue(races); resultRepository.findByRaceId.mockResolvedValue(results); penaltyRepository.findByRaceId.mockResolvedValue(penalties); eventScoringService.scoreSession.mockReturnValue({}); championshipAggregator.aggregate.mockReturnValue(standings); championshipStandingRepository.saveAll.mockResolvedValue(undefined); const input: RecalculateChampionshipStandingsInput = { leagueId: 'league-1', seasonId: 'season-1', }; const result = await useCase.execute(input); expect(result.isOk()).toBe(true); const presented = result.unwrap(); expect(presented.leagueId).toBe('league-1'); expect(presented.seasonId).toBe('season-1'); expect(presented.entries).toHaveLength(1); expect(presented.entries[0]).toEqual({ driverId: 'driver-1', teamId: null, position: 1, points: 25, }); }); it('wraps repository failures in REPOSITORY_ERROR', async () => { leagueRepository.findById.mockResolvedValue({ id: 'league-1' }); seasonRepository.findById.mockResolvedValue({ id: 'season-1', leagueId: 'league-1' }); leagueScoringConfigRepository.findBySeasonId.mockImplementation(() => { throw new Error('boom'); }); const input: RecalculateChampionshipStandingsInput = { leagueId: 'league-1', seasonId: 'season-1', }; const result = await useCase.execute(input); expect(result.isErr()).toBe(true); const error = result.unwrapErr() as ApplicationErrorCode< RecalculateChampionshipStandingsErrorCode, { message: string } >; expect(error.code).toBe('REPOSITORY_ERROR'); expect(error.details.message).toContain('boom'); }); });