import { describe, it, expect, beforeEach, vi, Mock } from 'vitest'; import { CompleteRaceUseCase, type CompleteRaceInput, type CompleteRaceResult } from './CompleteRaceUseCase'; import type { IRaceRepository } from '../../domain/repositories/IRaceRepository'; import type { IRaceRegistrationRepository } from '../../domain/repositories/IRaceRegistrationRepository'; import type { IResultRepository } from '../../domain/repositories/IResultRepository'; import type { IStandingRepository } from '../../domain/repositories/IStandingRepository'; describe('CompleteRaceUseCase', () => { let useCase: CompleteRaceUseCase; let raceRepository: { findById: Mock; update: Mock; }; let raceRegistrationRepository: { getRegisteredDrivers: Mock; }; let resultRepository: { create: Mock; }; let standingRepository: { findByDriverIdAndLeagueId: Mock; save: Mock; }; let getDriverRating: Mock; let output: { present: Mock }; beforeEach(() => { raceRepository = { findById: vi.fn(), update: vi.fn(), }; raceRegistrationRepository = { getRegisteredDrivers: vi.fn(), }; resultRepository = { create: vi.fn(), }; standingRepository = { findByDriverIdAndLeagueId: vi.fn(), save: vi.fn(), }; getDriverRating = vi.fn(); output = { present: vi.fn() }; useCase = new CompleteRaceUseCase(raceRepository as unknown as IRaceRepository, raceRegistrationRepository as unknown as IRaceRegistrationRepository, resultRepository as unknown as IResultRepository, standingRepository as unknown as IStandingRepository, getDriverRating); }); it('should complete race successfully when race exists and has registered drivers', async () => { const command: CompleteRaceInput = { raceId: 'race-1', }; const mockRace = { id: 'race-1', leagueId: 'league-1', status: 'scheduled', complete: vi.fn().mockReturnValue({ id: 'race-1', status: 'completed' }), }; raceRepository.findById.mockResolvedValue(mockRace); raceRegistrationRepository.getRegisteredDrivers.mockResolvedValue(['driver-1', 'driver-2']); getDriverRating.mockImplementation((input) => { if (input.driverId === 'driver-1') return Promise.resolve({ rating: 1600, ratingChange: null }); if (input.driverId === 'driver-2') return Promise.resolve({ rating: 1500, ratingChange: null }); return Promise.resolve({ rating: null, ratingChange: null }); }); resultRepository.create.mockResolvedValue(undefined); standingRepository.findByDriverIdAndLeagueId.mockResolvedValue(null); standingRepository.save.mockResolvedValue(undefined); raceRepository.update.mockResolvedValue(undefined); const result = await useCase.execute(command); expect(result.isOk()).toBe(true); expect(result.unwrap()).toBeUndefined(); expect(raceRepository.findById).toHaveBeenCalledWith('race-1'); expect(raceRegistrationRepository.getRegisteredDrivers).toHaveBeenCalledWith('race-1'); expect(getDriverRating).toHaveBeenCalledTimes(2); expect(resultRepository.create).toHaveBeenCalledTimes(2); expect(standingRepository.save).toHaveBeenCalledTimes(2); expect(mockRace.complete).toHaveBeenCalled(); expect(raceRepository.update).toHaveBeenCalledWith({ id: 'race-1', status: 'completed' }); }); it('should return error when race does not exist', async () => { const command: CompleteRaceInput = { raceId: 'race-1', }; raceRepository.findById.mockResolvedValue(null); const result = await useCase.execute(command); expect(result.isErr()).toBe(true); expect(result.unwrapErr().code).toBe('RACE_NOT_FOUND'); }); it('should return error when no registered drivers', async () => { const command: CompleteRaceInput = { raceId: 'race-1', }; const mockRace = { id: 'race-1', leagueId: 'league-1', status: 'scheduled', complete: vi.fn(), }; raceRepository.findById.mockResolvedValue(mockRace); raceRegistrationRepository.getRegisteredDrivers.mockResolvedValue([]); const result = await useCase.execute(command); expect(result.isErr()).toBe(true); expect(result.unwrapErr().code).toBe('NO_REGISTERED_DRIVERS'); }); it('should return error when repository throws', async () => { const command: CompleteRaceInput = { raceId: 'race-1', }; const mockRace = { id: 'race-1', leagueId: 'league-1', status: 'scheduled', complete: vi.fn().mockReturnValue({ id: 'race-1', status: 'completed' }), }; raceRepository.findById.mockResolvedValue(mockRace); raceRegistrationRepository.getRegisteredDrivers.mockResolvedValue(['driver-1']); getDriverRating.mockResolvedValue({ rating: 1600, ratingChange: null }); resultRepository.create.mockRejectedValue(new Error('DB error')); const result = await useCase.execute(command); expect(result.isErr()).toBe(true); const error = result.unwrapErr(); expect(error.code).toBe('REPOSITORY_ERROR'); expect(error.details?.message).toBe('DB error'); }); });