/** * Integration Test: GetDriversLeaderboardUseCase Orchestration * * Tests the orchestration logic of GetDriversLeaderboardUseCase: * - GetDriversLeaderboardUseCase: Retrieves list of drivers with rankings and statistics * - Validates that Use Cases correctly interact with their Ports (Repositories, other Use Cases) * - Uses In-Memory adapters for fast, deterministic testing * * Focus: Business logic orchestration, NOT UI rendering */ import { describe, it, expect, beforeAll, beforeEach } from 'vitest'; import { InMemoryDriverRepository } from '../../../adapters/racing/persistence/inmemory/InMemoryDriverRepository'; import { InMemoryDriverStatsRepository } from '../../../adapters/racing/persistence/inmemory/InMemoryDriverStatsRepository'; import { GetDriversLeaderboardUseCase } from '../../../core/racing/application/use-cases/GetDriversLeaderboardUseCase'; import { RankingUseCase } from '../../../core/racing/application/use-cases/RankingUseCase'; import { DriverStatsUseCase } from '../../../core/racing/application/use-cases/DriverStatsUseCase'; import { Driver } from '../../../core/racing/domain/entities/Driver'; import { Logger } from '../../../core/shared/domain/Logger'; describe('GetDriversLeaderboardUseCase Orchestration', () => { let driverRepository: InMemoryDriverRepository; let driverStatsRepository: InMemoryDriverStatsRepository; let rankingUseCase: RankingUseCase; let driverStatsUseCase: DriverStatsUseCase; let getDriversLeaderboardUseCase: GetDriversLeaderboardUseCase; let mockLogger: Logger; beforeAll(() => { mockLogger = { info: () => {}, debug: () => {}, warn: () => {}, error: () => {}, } as unknown as Logger; driverRepository = new InMemoryDriverRepository(mockLogger); driverStatsRepository = new InMemoryDriverStatsRepository(mockLogger); // RankingUseCase and DriverStatsUseCase are dependencies of GetDriversLeaderboardUseCase rankingUseCase = new RankingUseCase( {} as any, // standingRepository not used in getAllDriverRankings {} as any, // driverRepository not used in getAllDriverRankings driverStatsRepository, mockLogger ); driverStatsUseCase = new DriverStatsUseCase( {} as any, // resultRepository not used in getDriverStats {} as any, // standingRepository not used in getDriverStats driverStatsRepository, mockLogger ); getDriversLeaderboardUseCase = new GetDriversLeaderboardUseCase( driverRepository, rankingUseCase, driverStatsUseCase, mockLogger ); }); beforeEach(() => { driverRepository.clear(); driverStatsRepository.clear(); }); describe('GetDriversLeaderboardUseCase - Success Path', () => { it('should retrieve complete list of drivers with all data', async () => { // Scenario: System has multiple drivers // Given: 3 drivers exist with various data const drivers = [ Driver.create({ id: 'd1', iracingId: '1', name: 'Driver 1', country: 'US' }), Driver.create({ id: 'd2', iracingId: '2', name: 'Driver 2', country: 'UK' }), Driver.create({ id: 'd3', iracingId: '3', name: 'Driver 3', country: 'DE' }), ]; for (const d of drivers) { await driverRepository.create(d); } // And: Each driver has statistics await driverStatsRepository.saveDriverStats('d1', { rating: 2000, totalRaces: 10, wins: 2, podiums: 5, overallRank: 1, safetyRating: 4.5, sportsmanshipRating: 95, dnfs: 0, avgFinish: 3.5, bestFinish: 1, worstFinish: 10, consistency: 85, experienceLevel: 'pro' }); await driverStatsRepository.saveDriverStats('d2', { rating: 1800, totalRaces: 8, wins: 1, podiums: 3, overallRank: 2, safetyRating: 4.0, sportsmanshipRating: 90, dnfs: 1, avgFinish: 5.2, bestFinish: 1, worstFinish: 15, consistency: 75, experienceLevel: 'intermediate' }); await driverStatsRepository.saveDriverStats('d3', { rating: 1500, totalRaces: 5, wins: 0, podiums: 1, overallRank: 3, safetyRating: 3.5, sportsmanshipRating: 80, dnfs: 0, avgFinish: 8.0, bestFinish: 3, worstFinish: 12, consistency: 65, experienceLevel: 'rookie' }); // When: GetDriversLeaderboardUseCase.execute() is called const result = await getDriversLeaderboardUseCase.execute({}); // Then: The result should contain all drivers expect(result.isOk()).toBe(true); const leaderboard = result.unwrap(); expect(leaderboard.items).toHaveLength(3); expect(leaderboard.totalRaces).toBe(23); expect(leaderboard.totalWins).toBe(3); expect(leaderboard.activeCount).toBe(3); // And: Drivers should be sorted by rating (high to low) expect(leaderboard.items[0].driver.id).toBe('d1'); expect(leaderboard.items[1].driver.id).toBe('d2'); expect(leaderboard.items[2].driver.id).toBe('d3'); expect(leaderboard.items[0].rating).toBe(2000); expect(leaderboard.items[1].rating).toBe(1800); expect(leaderboard.items[2].rating).toBe(1500); }); it('should handle empty drivers list', async () => { // Scenario: System has no registered drivers // Given: No drivers exist in the system // When: GetDriversLeaderboardUseCase.execute() is called const result = await getDriversLeaderboardUseCase.execute({}); // Then: The result should contain an empty array expect(result.isOk()).toBe(true); const leaderboard = result.unwrap(); expect(leaderboard.items).toHaveLength(0); expect(leaderboard.totalRaces).toBe(0); expect(leaderboard.totalWins).toBe(0); expect(leaderboard.activeCount).toBe(0); }); it('should correctly identify active drivers', async () => { // Scenario: Some drivers have no races // Given: 2 drivers exist, one with races, one without await driverRepository.create(Driver.create({ id: 'active', iracingId: '1', name: 'Active', country: 'US' })); await driverRepository.create(Driver.create({ id: 'inactive', iracingId: '2', name: 'Inactive', country: 'UK' })); await driverStatsRepository.saveDriverStats('active', { rating: 1500, totalRaces: 1, wins: 0, podiums: 0, overallRank: 1, safetyRating: 3.0, sportsmanshipRating: 70, dnfs: 0, avgFinish: 10, bestFinish: 10, worstFinish: 10, consistency: 50, experienceLevel: 'rookie' }); // No stats for inactive driver or totalRaces = 0 await driverStatsRepository.saveDriverStats('inactive', { rating: 1000, totalRaces: 0, wins: 0, podiums: 0, overallRank: null, safetyRating: 2.5, sportsmanshipRating: 50, dnfs: 0, avgFinish: 0, bestFinish: 0, worstFinish: 0, consistency: 0, experienceLevel: 'rookie' }); // When: GetDriversLeaderboardUseCase.execute() is called const result = await getDriversLeaderboardUseCase.execute({}); // Then: Only one driver should be active const leaderboard = result.unwrap(); expect(leaderboard.activeCount).toBe(1); expect(leaderboard.items.find(i => i.driver.id === 'active')?.isActive).toBe(true); expect(leaderboard.items.find(i => i.driver.id === 'inactive')?.isActive).toBe(false); }); }); describe('GetDriversLeaderboardUseCase - Error Handling', () => { it('should handle repository errors gracefully', async () => { // Scenario: Repository throws error // Given: DriverRepository throws an error during query const originalFindAll = driverRepository.findAll.bind(driverRepository); driverRepository.findAll = async () => { throw new Error('Repository error'); }; // When: GetDriversLeaderboardUseCase.execute() is called const result = await getDriversLeaderboardUseCase.execute({}); // Then: Should return a repository error expect(result.isErr()).toBe(true); const error = result.unwrapErr(); expect(error.code).toBe('REPOSITORY_ERROR'); // Restore original method driverRepository.findAll = originalFindAll; }); }); });