/** * Unit tests for CalculateTeamContributionUseCase */ import { describe, it, expect, vi, beforeEach } from 'vitest'; import { CalculateTeamContributionUseCase } from './CalculateTeamContributionUseCase'; import { Driver } from '../../../racing/domain/entities/Driver'; import { Race } from '../../../racing/domain/entities/Race'; import { Result } from '../../../racing/domain/entities/result/Result'; import { Rating } from '../../domain/Rating'; const mockRatingRepository = { findByDriverAndRace: vi.fn(), save: vi.fn(), }; const mockDriverRepository = { findById: vi.fn(), }; const mockRaceRepository = { findById: vi.fn(), }; const mockResultRepository = { findByRaceId: vi.fn(), }; describe('CalculateTeamContributionUseCase', () => { let useCase: CalculateTeamContributionUseCase; beforeEach(() => { vi.clearAllMocks(); useCase = new CalculateTeamContributionUseCase({ ratingRepository: mockRatingRepository as any, driverRepository: mockDriverRepository as any, raceRepository: mockRaceRepository as any, resultRepository: mockResultRepository as any, }); }); describe('Scenario 8: Creates rating when missing', () => { it('should create and save a new rating when none exists', async () => { // Given const driverId = 'driver-1'; const raceId = 'race-1'; const points = 25; mockDriverRepository.findById.mockResolvedValue(Driver.create({ id: driverId, iracingId: 'ir-1', name: 'Driver 1', country: 'US' })); mockRaceRepository.findById.mockResolvedValue(Race.create({ id: raceId, leagueId: 'l-1', scheduledAt: new Date(), track: 'Track', car: 'Car' })); mockResultRepository.findByRaceId.mockResolvedValue([ Result.create({ id: 'res-1', raceId, driverId, position: 1, points, incidents: 0, startPosition: 1, fastestLap: 0 }) ]); mockRatingRepository.findByDriverAndRace.mockResolvedValue(null); // When const result = await useCase.execute({ driverId, raceId }); // Then expect(mockRatingRepository.save).toHaveBeenCalled(); const savedRating = mockRatingRepository.save.mock.calls[0][0] as Rating; expect(savedRating.components.teamContribution).toBe(100); // 25/25 * 100 expect(result.teamContribution).toBe(100); }); }); describe('Scenario 9: Updates existing rating', () => { it('should preserve other fields and only update teamContribution', async () => { // Given const driverId = 'driver-1'; const raceId = 'race-1'; const points = 12.5; // 50% contribution const existingRating = Rating.create({ driverId: 'driver-1' as any, // Simplified for test raceId: 'race-1' as any, rating: 1500, components: { resultsStrength: 80, consistency: 70, cleanDriving: 90, racecraft: 75, reliability: 85, teamContribution: 10, // Old value }, timestamp: new Date('2023-01-01') }); mockDriverRepository.findById.mockResolvedValue({ id: driverId } as any); mockRaceRepository.findById.mockResolvedValue({ id: raceId } as any); mockResultRepository.findByRaceId.mockResolvedValue([ { driverId: { toString: () => driverId }, points } as any ]); mockRatingRepository.findByDriverAndRace.mockResolvedValue(existingRating); // When const result = await useCase.execute({ driverId, raceId }); // Then expect(mockRatingRepository.save).toHaveBeenCalled(); const savedRating = mockRatingRepository.save.mock.calls[0][0] as Rating; // Check preserved fields expect(savedRating.rating).toBe(1500); expect(savedRating.components.resultsStrength).toBe(80); // Check updated field expect(savedRating.components.teamContribution).toBe(50); // 12.5/25 * 100 expect(result.teamContribution).toBe(50); }); }); });