import { TeamRatingIntegrationAdapter } from './TeamRatingIntegrationAdapter'; import { ITeamRaceResultsProvider } from '../ports/ITeamRaceResultsProvider'; import { ITeamRatingEventRepository } from '@core/racing/domain/repositories/ITeamRatingEventRepository'; import { ITeamRatingRepository } from '@core/racing/domain/repositories/ITeamRatingRepository'; import { TeamDrivingRaceFactsDto } from '@core/racing/domain/services/TeamDrivingRatingEventFactory'; import { TeamRatingEvent } from '@core/racing/domain/entities/TeamRatingEvent'; import { TeamRatingEventId } from '@core/racing/domain/value-objects/TeamRatingEventId'; import { TeamRatingDimensionKey } from '@core/racing/domain/value-objects/TeamRatingDimensionKey'; import { TeamRatingDelta } from '@core/racing/domain/value-objects/TeamRatingDelta'; // Mock repositories class MockTeamRaceResultsProvider implements ITeamRaceResultsProvider { private results: TeamDrivingRaceFactsDto | null = null; async getTeamRaceResults(raceId: string): Promise { return this.results; } setResults(results: TeamDrivingRaceFactsDto | null) { this.results = results; } } class MockTeamRatingEventRepository implements ITeamRatingEventRepository { private events: TeamRatingEvent[] = []; async save(event: TeamRatingEvent): Promise { this.events.push(event); return event; } async findByTeamId(teamId: string): Promise { return this.events.filter(e => e.teamId === teamId); } async findByIds(ids: TeamRatingEventId[]): Promise { return this.events.filter(e => ids.some(id => id.equals(e.id))); } async getAllByTeamId(teamId: string): Promise { return this.events.filter(e => e.teamId === teamId); } async findEventsPaginated(teamId: string): Promise { const events = await this.getAllByTeamId(teamId); return { items: events, total: events.length, limit: 10, offset: 0, hasMore: false, }; } clear() { this.events = []; } } class MockTeamRatingRepository implements ITeamRatingRepository { private snapshots: Map = new Map(); async findByTeamId(teamId: string): Promise { return this.snapshots.get(teamId) || null; } async save(snapshot: any): Promise { this.snapshots.set(snapshot.teamId, snapshot); return snapshot; } clear() { this.snapshots.clear(); } } describe('TeamRatingIntegrationAdapter', () => { let adapter: TeamRatingIntegrationAdapter; let mockResultsProvider: MockTeamRaceResultsProvider; let mockEventRepo: MockTeamRatingEventRepository; let mockRatingRepo: MockTeamRatingRepository; beforeEach(() => { mockResultsProvider = new MockTeamRaceResultsProvider(); mockEventRepo = new MockTeamRatingEventRepository(); mockRatingRepo = new MockTeamRatingRepository(); adapter = new TeamRatingIntegrationAdapter( mockResultsProvider, mockEventRepo, mockRatingRepo ); }); afterEach(() => { mockEventRepo.clear(); mockRatingRepo.clear(); }); describe('recordTeamRatings', () => { it('should return true when no results found', async () => { mockResultsProvider.setResults(null); const result = await adapter.recordTeamRatings('race-123'); expect(result).toBe(true); }); it('should return true when results are empty', async () => { mockResultsProvider.setResults({ raceId: 'race-123', teamId: 'team-123', results: [], }); const result = await adapter.recordTeamRatings('race-123'); expect(result).toBe(true); }); it('should return true when no events generated', async () => { mockResultsProvider.setResults({ raceId: 'race-123', teamId: 'team-123', results: [ { teamId: 'team-123', position: 1, incidents: 0, status: 'dns', fieldSize: 1, strengthOfField: 50, }, ], }); const result = await adapter.recordTeamRatings('race-123'); expect(result).toBe(true); }); it('should record team ratings successfully', 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 adapter.recordTeamRatings('race-123'); expect(result).toBe(true); // Verify events were saved const events1 = await mockEventRepo.getAllByTeamId('team-123'); const events2 = await mockEventRepo.getAllByTeamId('team-456'); expect(events1.length).toBeGreaterThan(0); expect(events2.length).toBeGreaterThan(0); // Verify snapshots were updated const snapshot1 = await mockRatingRepo.findByTeamId('team-123'); const snapshot2 = await mockRatingRepo.findByTeamId('team-456'); expect(snapshot1).toBeDefined(); expect(snapshot2).toBeDefined(); }); it('should return false on error', 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 repository to throw error const originalSave = mockEventRepo.save.bind(mockEventRepo); mockEventRepo.save = async () => { throw new Error('Repository error'); }; const result = await adapter.recordTeamRatings('race-123'); expect(result).toBe(false); }); }); describe('recordTeamRatingsWithDetails', () => { it('should return details for successful recording', 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 adapter.recordTeamRatingsWithDetails('race-123'); expect(result.success).toBe(true); expect(result.eventsCreated).toBeGreaterThan(0); expect(result.teamsUpdated).toContain('team-123'); expect(result.teamsUpdated).toContain('team-456'); expect(result.errors).toEqual([]); }); it('should handle partial failures', async () => { const raceResults: TeamDrivingRaceFactsDto = { raceId: 'race-123', teamId: 'team-123', results: [ { teamId: 'team-123', position: 1, incidents: 0, status: 'finished', fieldSize: 2, strengthOfField: 55, }, { teamId: 'team-456', position: 2, incidents: 0, status: 'finished', fieldSize: 2, strengthOfField: 55, }, ], }; mockResultsProvider.setResults(raceResults); // Mock repository to fail for team-456 const originalSave = mockEventRepo.save.bind(mockEventRepo); mockEventRepo.save = async (event) => { if (event.teamId === 'team-456') { throw new Error('Simulated failure'); } return originalSave(event); }; const result = await adapter.recordTeamRatingsWithDetails('race-123'); expect(result.success).toBe(false); expect(result.teamsUpdated).toContain('team-123'); expect(result.teamsUpdated).not.toContain('team-456'); expect(result.errors.length).toBeGreaterThan(0); expect(result.errors[0]).toContain('team-456'); }); it('should handle empty results', async () => { mockResultsProvider.setResults({ raceId: 'race-123', teamId: 'team-123', results: [], }); const result = await adapter.recordTeamRatingsWithDetails('race-123'); expect(result.success).toBe(true); expect(result.eventsCreated).toBe(0); expect(result.teamsUpdated).toEqual([]); expect(result.errors).toEqual([]); }); it('should handle null results', async () => { mockResultsProvider.setResults(null); const result = await adapter.recordTeamRatingsWithDetails('race-123'); expect(result.success).toBe(true); expect(result.eventsCreated).toBe(0); expect(result.teamsUpdated).toEqual([]); expect(result.errors).toEqual([]); }); }); });