import { describe, it, expect, beforeEach, vi, Mock } from 'vitest'; import { CloseRaceEventStewardingUseCase, type CloseRaceEventStewardingResult } from './CloseRaceEventStewardingUseCase'; import type { IRaceEventRepository } from '../../domain/repositories/IRaceEventRepository'; import type { IRaceRegistrationRepository } from '../../domain/repositories/IRaceRegistrationRepository'; import type { IPenaltyRepository } from '../../domain/repositories/IPenaltyRepository'; import type { DomainEventPublisher } from '@core/shared/domain/DomainEvent'; import type { Logger } from '@core/shared/application'; import { RaceEvent } from '../../domain/entities/RaceEvent'; import { Session } from '../../domain/entities/Session'; import { SessionType } from '../../domain/value-objects/SessionType'; import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort'; describe('CloseRaceEventStewardingUseCase', () => { let useCase: CloseRaceEventStewardingUseCase; let raceEventRepository: { findAwaitingStewardingClose: Mock; update: Mock; }; let raceRegistrationRepository: { getRegisteredDrivers: Mock; }; let penaltyRepository: { findByRaceId: Mock; }; let domainEventPublisher: { publish: Mock; }; let logger: { error: Mock; }; let output: UseCaseOutputPort & { present: Mock }; beforeEach(() => { raceEventRepository = { findAwaitingStewardingClose: vi.fn(), update: vi.fn(), }; raceRegistrationRepository = { getRegisteredDrivers: vi.fn(), }; penaltyRepository = { findByRaceId: vi.fn(), }; domainEventPublisher = { publish: vi.fn(), }; logger = { error: vi.fn(), }; output = { present: vi.fn() } as unknown as UseCaseOutputPort & { present: Mock }; useCase = new CloseRaceEventStewardingUseCase( logger as unknown as Logger, raceEventRepository as unknown as IRaceEventRepository, raceRegistrationRepository as unknown as IRaceRegistrationRepository, penaltyRepository as unknown as IPenaltyRepository, domainEventPublisher as unknown as DomainEventPublisher, output, ); }); it('should close stewarding for expired events successfully', async () => { const raceEvent = RaceEvent.create({ id: 'event-1', seasonId: 'season-1', leagueId: 'league-1', name: 'Test Event', sessions: [ Session.create({ id: 'session-1', raceEventId: 'event-1', sessionType: SessionType.main(), scheduledAt: new Date(), track: 'Test Track', car: 'Test Car', status: 'completed', }), ], status: 'awaiting_stewarding', stewardingClosesAt: new Date(Date.now() - 1000), // expired }); raceEventRepository.findAwaitingStewardingClose.mockResolvedValue([raceEvent]); raceRegistrationRepository.getRegisteredDrivers.mockResolvedValue(['driver-1', 'driver-2']); penaltyRepository.findByRaceId.mockResolvedValue([]); domainEventPublisher.publish.mockResolvedValue(undefined); const result = await useCase.execute({ raceId: 'event-1', closedById: 'admin-1' }); expect(result.isOk()).toBe(true); expect(result.unwrap()).toBeUndefined(); expect(raceEventRepository.findAwaitingStewardingClose).toHaveBeenCalled(); expect(raceEventRepository.update).toHaveBeenCalledWith( expect.objectContaining({ id: 'event-1', status: 'closed' }) ); expect(domainEventPublisher.publish).toHaveBeenCalled(); expect(output.present).toHaveBeenCalledTimes(1); expect(output.present).toHaveBeenCalledWith({ race: expect.objectContaining({ id: 'event-1', status: 'closed' }) }); }); it('should handle no expired events', async () => { raceEventRepository.findAwaitingStewardingClose.mockResolvedValue([]); const result = await useCase.execute({ raceId: 'event-1', closedById: 'admin-1' }); expect(result.isOk()).toBe(true); expect(result.unwrap()).toBeUndefined(); expect(raceEventRepository.update).not.toHaveBeenCalled(); expect(domainEventPublisher.publish).not.toHaveBeenCalled(); expect(output.present).not.toHaveBeenCalled(); }); it('should return error when repository throws', async () => { raceEventRepository.findAwaitingStewardingClose.mockRejectedValue(new Error('DB error')); const result = await useCase.execute({ raceId: 'event-1', closedById: 'admin-1' }); expect(result.isErr()).toBe(true); expect(result.unwrapErr().code).toBe('REPOSITORY_ERROR'); expect((result.unwrapErr() as any).details.message).toContain('DB error'); expect(output.present).not.toHaveBeenCalled(); }); });