import type { Logger } from '@core/shared/domain/Logger'; import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import type { RaceRegistrationRepository } from '../../domain/repositories/RaceRegistrationRepository'; import type { RaceRepository } from '../../domain/repositories/RaceRepository'; import { WithdrawFromRaceUseCase, type WithdrawFromRaceErrorCode, type WithdrawFromRaceInput, } from './WithdrawFromRaceUseCase'; describe('WithdrawFromRaceUseCase', () => { let raceRepository: { findById: ReturnType }; let registrationRepository: { isRegistered: ReturnType; withdraw: ReturnType }; let logger: { debug: ReturnType; info: ReturnType; warn: ReturnType; error: ReturnType; }; beforeEach(() => { raceRepository = { findById: vi.fn(), }; registrationRepository = { isRegistered: vi.fn(), withdraw: vi.fn(), }; logger = { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn(), }; }); const createUseCase = () => new WithdrawFromRaceUseCase( raceRepository as unknown as RaceRepository, registrationRepository as unknown as RaceRegistrationRepository, logger as unknown as Logger ); it('withdraws from race successfully', async () => { const race = { id: 'race-1', isUpcoming: vi.fn().mockReturnValue(true), }; raceRepository.findById.mockResolvedValue(race); registrationRepository.isRegistered.mockResolvedValue(true); registrationRepository.withdraw.mockResolvedValue(undefined); const useCase = createUseCase(); const input: WithdrawFromRaceInput = { raceId: 'race-1', driverId: 'driver-1', }; const result = await useCase.execute(input); expect(result.isOk()).toBe(true); const presented = result.unwrap(); expect(presented.status).toBe('withdrawn'); expect(registrationRepository.withdraw).toHaveBeenCalledWith('race-1', 'driver-1'); }); it('returns error when race is not found', async () => { raceRepository.findById.mockResolvedValue(null); const useCase = createUseCase(); const input: WithdrawFromRaceInput = { raceId: 'race-unknown', driverId: 'driver-1', }; const result = await useCase.execute(input); expect(result.isErr()).toBe(true); const error = result.unwrapErr() as ApplicationErrorCode; expect(error.code).toBe('RACE_NOT_FOUND'); expect(error.details?.message).toContain('Race race-unknown not found'); }); it('returns error when registration is not found', async () => { const race = { id: 'race-1', isUpcoming: vi.fn().mockReturnValue(true), }; raceRepository.findById.mockResolvedValue(race); registrationRepository.isRegistered.mockResolvedValue(false); const useCase = createUseCase(); const input: WithdrawFromRaceInput = { raceId: 'race-1', driverId: 'driver-unknown', }; const result = await useCase.execute(input); expect(result.isErr()).toBe(true); const error = result.unwrapErr() as ApplicationErrorCode; expect(error.code).toBe('REGISTRATION_NOT_FOUND'); expect(error.details?.message).toContain('Driver driver-unknown is not registered for race race-1'); }); it('returns error when withdrawal is not allowed', async () => { const race = { id: 'race-1', isUpcoming: vi.fn().mockReturnValue(false), }; raceRepository.findById.mockResolvedValue(race); registrationRepository.isRegistered.mockResolvedValue(true); const useCase = createUseCase(); const input: WithdrawFromRaceInput = { raceId: 'race-1', driverId: 'driver-1', }; const result = await useCase.execute(input); expect(result.isErr()).toBe(true); const error = result.unwrapErr() as ApplicationErrorCode; expect(error.code).toBe('WITHDRAWAL_NOT_ALLOWED'); expect(error.details?.message).toContain('Withdrawal is not allowed for this race'); }); it('wraps repository errors and logs them', async () => { const race = { id: 'race-1', isUpcoming: vi.fn().mockReturnValue(true), }; raceRepository.findById.mockResolvedValue(race); registrationRepository.isRegistered.mockResolvedValue(true); registrationRepository.withdraw.mockRejectedValue(new Error('DB failure')); const useCase = createUseCase(); const input: WithdrawFromRaceInput = { raceId: 'race-1', driverId: 'driver-1', }; const result = await useCase.execute(input); expect(result.isErr()).toBe(true); const error = result.unwrapErr() as ApplicationErrorCode; expect(error.code).toBe('REPOSITORY_ERROR'); expect(error.details?.message).toBe('DB failure'); expect(logger.error).toHaveBeenCalled(); }); });