import { describe, it, expect, beforeEach, vi, Mock } from 'vitest'; import { FileProtestUseCase } from './FileProtestUseCase'; import type { IProtestRepository } from '../../domain/repositories/IProtestRepository'; import type { IRaceRepository } from '../../domain/repositories/IRaceRepository'; import type { ILeagueMembershipRepository } from '../../domain/repositories/ILeagueMembershipRepository'; describe('FileProtestUseCase', () => { let mockProtestRepo: { create: Mock; }; let mockRaceRepo: { findById: Mock; }; let mockLeagueMembershipRepo: { getLeagueMembers: Mock; }; beforeEach(() => { mockProtestRepo = { create: vi.fn(), }; mockRaceRepo = { findById: vi.fn(), }; mockLeagueMembershipRepo = { getLeagueMembers: vi.fn(), }; }); it('should return error when race does not exist', async () => { const useCase = new FileProtestUseCase( mockProtestRepo as unknown as IProtestRepository, mockRaceRepo as unknown as IRaceRepository, mockLeagueMembershipRepo as unknown as ILeagueMembershipRepository, ); mockRaceRepo.findById.mockResolvedValue(null); const result = await useCase.execute({ raceId: 'nonexistent', protestingDriverId: 'driver1', accusedDriverId: 'driver2', incident: { lap: 5, description: 'Collision' }, }); expect(result.isOk()).toBe(false); expect(result.error!.details.message).toBe('Race not found'); }); it('should return error when protesting against self', async () => { const useCase = new FileProtestUseCase( mockProtestRepo as unknown as IProtestRepository, mockRaceRepo as unknown as IRaceRepository, mockLeagueMembershipRepo as unknown as ILeagueMembershipRepository, ); mockRaceRepo.findById.mockResolvedValue({ id: 'race1', leagueId: 'league1' }); const result = await useCase.execute({ raceId: 'race1', protestingDriverId: 'driver1', accusedDriverId: 'driver1', incident: { lap: 5, description: 'Collision' }, }); expect(result.isOk()).toBe(false); expect(result.error!.details.message).toBe('Cannot file a protest against yourself'); }); it('should return error when protesting driver is not an active member', async () => { const useCase = new FileProtestUseCase( mockProtestRepo as unknown as IProtestRepository, mockRaceRepo as unknown as IRaceRepository, mockLeagueMembershipRepo as unknown as ILeagueMembershipRepository, ); mockRaceRepo.findById.mockResolvedValue({ id: 'race1', leagueId: 'league1' }); mockLeagueMembershipRepo.getLeagueMembers.mockResolvedValue([ { driverId: 'driver2', status: 'active' }, ]); const result = await useCase.execute({ raceId: 'race1', protestingDriverId: 'driver1', accusedDriverId: 'driver2', incident: { lap: 5, description: 'Collision' }, }); expect(result.isOk()).toBe(false); expect(result.error!.details.message).toBe('Protesting driver is not an active member of this league'); }); it('should create protest and return protestId on success', async () => { const useCase = new FileProtestUseCase( mockProtestRepo as unknown as IProtestRepository, mockRaceRepo as unknown as IRaceRepository, mockLeagueMembershipRepo as unknown as ILeagueMembershipRepository, ); mockRaceRepo.findById.mockResolvedValue({ id: 'race1', leagueId: 'league1' }); mockLeagueMembershipRepo.getLeagueMembers.mockResolvedValue([ { driverId: 'driver1', status: 'active' }, ]); mockProtestRepo.create.mockResolvedValue(undefined); const result = await useCase.execute({ raceId: 'race1', protestingDriverId: 'driver1', accusedDriverId: 'driver2', incident: { lap: 5, description: 'Collision' }, comment: 'Test comment', proofVideoUrl: 'http://example.com/video', }); expect(result.isOk()).toBe(true); expect(result.value).toEqual({ protestId: expect.any(String), }); expect(mockProtestRepo.create).toHaveBeenCalledWith( expect.objectContaining({ raceId: 'race1', protestingDriverId: 'driver1', accusedDriverId: 'driver2', incident: { lap: 5, description: 'Collision' }, comment: 'Test comment', proofVideoUrl: 'http://example.com/video', status: 'pending', }) ); }); });