import { TeamDrivingRaceFactsDto } from '@core/racing/domain/services/TeamDrivingRatingEventFactory'; import type { Logger } from '@core/shared/domain/Logger'; import { beforeEach, describe, expect, it } from 'vitest'; import type { TeamRaceResultsProvider } from '../ports/TeamRaceResultsProvider'; import { TeamRatingFactoryUseCase } from './TeamRatingFactoryUseCase'; // Mock provider class MockTeamRaceResultsProvider implements TeamRaceResultsProvider { private results: TeamDrivingRaceFactsDto | null = null; async getTeamRaceResults(): Promise { return this.results; } setResults(results: TeamDrivingRaceFactsDto | null) { this.results = results; } } // Mock logger const mockLogger: Logger = { info: () => {}, error: () => {}, warn: () => {}, debug: () => {}, }; describe('TeamRatingFactoryUseCase', () => { let useCase: TeamRatingFactoryUseCase; let mockResultsProvider: MockTeamRaceResultsProvider; beforeEach(() => { mockResultsProvider = new MockTeamRaceResultsProvider(); useCase = new TeamRatingFactoryUseCase(mockResultsProvider, mockLogger); }); describe('execute', () => { it('should return error when race results not found', async () => { mockResultsProvider.setResults(null); const result = await useCase.execute({ raceId: 'race-123' }); expect(result.success).toBe(false); expect(result.errors).toContain('Team race results not found'); expect(result.events).toEqual([]); }); it('should return success with no events when results are empty', async () => { mockResultsProvider.setResults({ raceId: 'race-123', teamId: 'team-123', results: [], }); const result = await useCase.execute({ raceId: 'race-123' }); expect(result.success).toBe(true); expect(result.events).toEqual([]); expect(result.errors).toEqual([]); }); it('should create events for single team', async () => { const raceResults: TeamDrivingRaceFactsDto = { raceId: 'race-123', teamId: 'team-123', results: [ { teamId: 'team-123', position: 1, incidents: 0, status: 'finished', fieldSize: 3, strengthOfField: 55, }, ], }; mockResultsProvider.setResults(raceResults); const result = await useCase.execute({ raceId: 'race-123' }); expect(result.success).toBe(true); expect(result.events.length).toBeGreaterThan(0); expect(result.errors).toEqual([]); // Verify events have correct structure const event = result.events[0]; expect(event.teamId).toBe('team-123'); expect(event.source.type).toBe('race'); expect(event.source.id).toBe('race-123'); }); it('should create events for multiple teams', async () => { const raceResults: TeamDrivingRaceFactsDto = { raceId: 'race-123', teamId: 'team-123', results: [ { teamId: 'team-123', position: 1, incidents: 0, status: 'finished', fieldSize: 3, strengthOfField: 55, }, { teamId: 'team-456', position: 2, incidents: 1, status: 'finished', fieldSize: 3, strengthOfField: 55, }, ], }; mockResultsProvider.setResults(raceResults); const result = await useCase.execute({ raceId: 'race-123' }); expect(result.success).toBe(true); expect(result.events.length).toBeGreaterThan(0); // Should have events for both teams const team123Events = result.events.filter(e => e.teamId === 'team-123'); const team456Events = result.events.filter(e => e.teamId === 'team-456'); expect(team123Events.length).toBeGreaterThan(0); expect(team456Events.length).toBeGreaterThan(0); }); it('should handle optional ratings in results', async () => { const raceResults: TeamDrivingRaceFactsDto = { raceId: 'race-123', teamId: 'team-123', results: [ { teamId: 'team-123', position: 1, incidents: 0, status: 'finished', fieldSize: 3, strengthOfField: 65, pace: 85, consistency: 80, teamwork: 90, sportsmanship: 95, }, ], }; mockResultsProvider.setResults(raceResults); const result = await useCase.execute({ raceId: 'race-123' }); expect(result.success).toBe(true); expect(result.events.length).toBeGreaterThan(5); // Should have many events // Verify events include optional rating events const reasonCodes = result.events.map(e => e.reason.code); expect(reasonCodes).toContain('RACE_PACE'); expect(reasonCodes).toContain('RACE_CONSISTENCY'); expect(reasonCodes).toContain('RACE_TEAMWORK'); expect(reasonCodes).toContain('RACE_SPORTSMANSHIP'); }); it('should handle repository errors', async () => { const raceResults: TeamDrivingRaceFactsDto = { raceId: 'race-123', teamId: 'team-123', results: [ { teamId: 'team-123', position: 1, incidents: 0, status: 'finished', fieldSize: 1, strengthOfField: 55, }, ], }; mockResultsProvider.setResults(raceResults); // Mock provider to throw error mockResultsProvider.getTeamRaceResults = async () => { throw new Error('Provider error'); }; const result = await useCase.execute({ raceId: 'race-123' }); expect(result.success).toBe(false); expect(result.errors.length).toBeGreaterThan(0); expect(result.errors[0]).toContain('Provider error'); expect(result.events).toEqual([]); }); it('should handle race with minimal events generated', async () => { const raceResults: TeamDrivingRaceFactsDto = { raceId: 'race-123', teamId: 'team-123', results: [ { teamId: 'team-123', position: 1, incidents: 0, status: 'dns', fieldSize: 1, strengthOfField: 50, }, ], }; mockResultsProvider.setResults(raceResults); const result = await useCase.execute({ raceId: 'race-123' }); expect(result.success).toBe(true); expect(result.events.length).toBeGreaterThan(0); // DNS creates penalty event }); }); describe('createManualEvents', () => { it('should create manual events with source ID', () => { const events = useCase.createManualEvents( 'team-123', 'driving', 5, 'MANUAL_ADJUSTMENT', 'manualAdjustment', 'adjustment-123' ); expect(events).toHaveLength(1); expect(events[0].teamId).toBe('team-123'); expect(events[0].dimension.value).toBe('driving'); expect(events[0].delta.value).toBe(5); expect(events[0].reason.code).toBe('MANUAL_ADJUSTMENT'); expect(events[0].source.type).toBe('manualAdjustment'); expect(events[0].source.id).toBe('adjustment-123'); }); it('should create manual events without source ID', () => { const events = useCase.createManualEvents( 'team-456', 'adminTrust', -3, 'PENALTY', 'penalty' ); expect(events).toHaveLength(1); expect(events[0].teamId).toBe('team-456'); expect(events[0].dimension.value).toBe('adminTrust'); expect(events[0].delta.value).toBe(-3); expect(events[0].reason.code).toBe('PENALTY'); expect(events[0].source.type).toBe('penalty'); expect(events[0].source.id).toBeUndefined(); }); }); });