import { describe, it, expect, vi } from 'vitest'; import { SendPerformanceSummaryUseCase } from './SendPerformanceSummaryUseCase'; import type { INotificationService } from '../../../notifications/application/ports/INotificationService'; import type { IRaceEventRepository } from '../../domain/repositories/IRaceEventRepository'; import type { IResultRepository } from '../../domain/repositories/IResultRepository'; import type { MainRaceCompletedEvent } from '../../domain/events/MainRaceCompleted'; describe('SendPerformanceSummaryUseCase', () => { it('sends performance summary notifications to all participating drivers', async () => { const mockNotificationService = { sendNotification: vi.fn(), } as unknown as INotificationService; const mockRaceEvent = { id: 'race-1', name: 'Test Race', getMainRaceSession: vi.fn().mockReturnValue({ id: 'session-1' }), }; const mockRaceEventRepository = { findById: vi.fn().mockResolvedValue(mockRaceEvent), } as unknown as IRaceEventRepository; const mockResults = [ { driverId: 'driver-1', position: 1, incidents: 0, getPositionChange: vi.fn().mockReturnValue(2), }, { driverId: 'driver-2', position: 2, incidents: 1, getPositionChange: vi.fn().mockReturnValue(-1), }, ]; const mockResultRepository = { findByRaceId: vi.fn().mockResolvedValue(mockResults), } as unknown as IResultRepository; const useCase = new SendPerformanceSummaryUseCase( mockNotificationService, mockRaceEventRepository, mockResultRepository, ); const event: MainRaceCompletedEvent = { eventType: 'MainRaceCompleted', aggregateId: 'race-1', occurredAt: new Date(), eventData: { raceEventId: 'race-1', sessionId: 'session-1', seasonId: 'season-1', leagueId: 'league-1', driverIds: ['driver-1', 'driver-2'], completedAt: new Date(), }, }; const result = await useCase.execute(event); expect(result.isOk()).toBe(true); expect(mockRaceEventRepository.findById).toHaveBeenCalledWith('race-1'); expect(mockResultRepository.findByRaceId).toHaveBeenCalledWith('session-1'); expect(mockNotificationService.sendNotification).toHaveBeenCalledTimes(2); // Check first notification expect(mockNotificationService.sendNotification).toHaveBeenCalledWith( expect.objectContaining({ recipientId: 'driver-1', type: 'race_performance_summary', title: 'Race Complete: Test Race', body: expect.stringContaining('You finished P1 (+2 positions). Clean race! Provisional +35 rating.'), data: expect.objectContaining({ raceEventId: 'race-1', sessionId: 'session-1', leagueId: 'league-1', position: 1, positionChange: 2, incidents: 0, provisionalRatingChange: 35, }), }), ); // Check second notification expect(mockNotificationService.sendNotification).toHaveBeenCalledWith( expect.objectContaining({ recipientId: 'driver-2', type: 'race_performance_summary', title: 'Race Complete: Test Race', body: expect.stringContaining('You finished P2 (-1 positions). 1 incident Provisional +20 rating.'), data: expect.objectContaining({ position: 2, positionChange: -1, incidents: 1, provisionalRatingChange: 20, }), }), ); }); it('skips sending notifications if race event not found', async () => { const mockNotificationService = { sendNotification: vi.fn(), } as unknown as INotificationService; const mockRaceEventRepository = { findById: vi.fn().mockResolvedValue(null), } as unknown as IRaceEventRepository; const mockResultRepository = { findByRaceId: vi.fn(), } as unknown as IResultRepository; const useCase = new SendPerformanceSummaryUseCase( mockNotificationService, mockRaceEventRepository, mockResultRepository, ); const event: MainRaceCompletedEvent = { eventType: 'MainRaceCompleted', aggregateId: 'race-1', occurredAt: new Date(), eventData: { raceEventId: 'race-1', sessionId: 'session-1', seasonId: 'season-1', leagueId: 'league-1', driverIds: ['driver-1'], completedAt: new Date(), }, }; const result = await useCase.execute(event); expect(result.isOk()).toBe(true); expect(mockNotificationService.sendNotification).not.toHaveBeenCalled(); }); });