import { DomainEventPublisher } from '@core/shared/domain/DomainEvent'; import type { Logger } from '@core/shared/domain/Logger'; import { beforeEach, describe, expect, it, Mock, vi } from 'vitest'; import { RaceEvent } from '../../domain/entities/RaceEvent'; import { Session } from '../../domain/entities/Session'; import { PenaltyRepository } from '../../domain/repositories/PenaltyRepository'; import { RaceEventRepository } from '../../domain/repositories/RaceEventRepository'; import { RaceRegistrationRepository } from '../../domain/repositories/RaceRegistrationRepository'; import { SessionType } from '../../domain/value-objects/SessionType'; import { CloseRaceEventStewardingUseCase } from './CloseRaceEventStewardingUseCase'; describe('CloseRaceEventStewardingUseCase', () => { let useCase: CloseRaceEventStewardingUseCase; let raceEventRepository: { findAwaitingStewardingClose: Mock; findById: Mock; update: Mock; }; let raceRegistrationRepository: { getRegisteredDrivers: Mock; }; let penaltyRepository: { findByRaceId: Mock; }; let domainEventPublisher: { publish: Mock; }; let logger: { error: Mock; }; beforeEach(() => { raceEventRepository = { findAwaitingStewardingClose: vi.fn(), findById: vi.fn(), update: vi.fn(), }; raceRegistrationRepository = { getRegisteredDrivers: vi.fn(), }; penaltyRepository = { findByRaceId: vi.fn(), }; domainEventPublisher = { publish: vi.fn(), }; logger = { error: vi.fn(), }; useCase = new CloseRaceEventStewardingUseCase(logger as unknown as Logger, raceEventRepository as unknown as RaceEventRepository, raceRegistrationRepository as unknown as RaceRegistrationRepository, penaltyRepository as unknown as PenaltyRepository, domainEventPublisher as unknown as DomainEventPublisher); }); 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]); raceEventRepository.findById.mockResolvedValue(raceEvent.closeStewarding()); 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); const presented = result.unwrap(); expect(raceEventRepository.findAwaitingStewardingClose).toHaveBeenCalled(); expect(raceEventRepository.update).toHaveBeenCalledWith( expect.objectContaining({ status: 'closed' }) ); expect(domainEventPublisher.publish).toHaveBeenCalled(); expect(presented.race.id).toBe('event-1'); expect(presented.race.status).toBe('closed'); }); it('should return error when no expired events', async () => { raceEventRepository.findAwaitingStewardingClose.mockResolvedValue([]); const result = await useCase.execute({ raceId: 'event-1', closedById: 'admin-1' }); expect(result.isErr()).toBe(true); expect(result.unwrapErr().code).toBe('RACE_NOT_FOUND'); expect(raceEventRepository.update).not.toHaveBeenCalled(); expect(domainEventPublisher.publish).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); const err = result.unwrapErr(); expect(err.code).toBe('REPOSITORY_ERROR'); if ('details' in err && err.details && typeof err.details === 'object' && 'message' in err.details) { expect(err.details.message).toContain('DB error'); } }); });