import { TeamRatingEvent } from '@core/racing/domain/entities/TeamRatingEvent'; import { TeamRatingEventRepository, PaginatedResult } from '@core/racing/domain/repositories/TeamRatingEventRepository'; import { TeamRatingRepository } from '@core/racing/domain/repositories/TeamRatingRepository'; import { TeamDrivingRaceFactsDto } from '@core/racing/domain/services/TeamDrivingRatingEventFactory'; import { TeamRatingEventId } from '@core/racing/domain/value-objects/TeamRatingEventId'; import { afterEach, beforeEach, describe, expect, it } from 'vitest'; import { TeamRating } from '../../domain/value-objects/TeamRating'; import { TeamRaceResultsProvider } from '../ports/TeamRaceResultsProvider'; import { TeamRatingIntegrationAdapter } from './TeamRatingIntegrationAdapter'; // Mock repositories class MockTeamRaceResultsProvider implements TeamRaceResultsProvider { private results: TeamDrivingRaceFactsDto | null = null; async getTeamRaceResults(): Promise { return this.results; } setResults(results: TeamDrivingRaceFactsDto | null) { this.results = results; } } class MockTeamRatingEventRepository implements TeamRatingEventRepository { 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 TeamRatingRepository { private snapshots: Map = new Map(); async findByTeamId(teamId: string): Promise { return this.snapshots.get(teamId) || null; } async save(snapshot: TeamRating): 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 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 mockEventRepo.save = async (event) => { if (event.teamId === 'team-456') { throw new Error('Simulated failure'); } return 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([]); }); }); });