import { describe, it, expect, beforeEach, vi, type Mock } from 'vitest'; import { GetDriversLeaderboardUseCase, type GetDriversLeaderboardResult, type GetDriversLeaderboardInput, type GetDriversLeaderboardErrorCode, } from './GetDriversLeaderboardUseCase'; import type { IDriverRepository } from '../../domain/repositories/IDriverRepository'; import type { IRankingService } from '../../domain/services/IRankingService'; import type { IDriverStatsService } from '../../domain/services/IDriverStatsService'; import type { Logger } from '@core/shared/application'; import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort'; import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode'; describe('GetDriversLeaderboardUseCase', () => { const mockDriverFindAll = vi.fn(); const mockDriverRepo: IDriverRepository = { findById: vi.fn(), findAll: mockDriverFindAll, create: vi.fn(), update: vi.fn(), delete: vi.fn(), exists: vi.fn(), }; const mockRankingGetAllDriverRankings = vi.fn(); const mockRankingService: IRankingService = { getAllDriverRankings: mockRankingGetAllDriverRankings, }; const mockDriverStatsGetDriverStats = vi.fn(); const mockDriverStatsService: IDriverStatsService = { getDriverStats: mockDriverStatsGetDriverStats, }; const mockGetDriverAvatar = vi.fn(); const mockLogger: Logger = { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn(), }; let output: UseCaseOutputPort & { present: Mock }; beforeEach(() => { vi.clearAllMocks(); output = { present: vi.fn(), } as unknown as UseCaseOutputPort & { present: Mock }; }); it('should return drivers leaderboard data', async () => { const useCase = new GetDriversLeaderboardUseCase( mockDriverRepo, mockRankingService, mockDriverStatsService, mockGetDriverAvatar, mockLogger, output, ); const driver1 = { id: 'driver1', name: { value: 'Driver One' }, country: { value: 'US' } }; const driver2 = { id: 'driver2', name: { value: 'Driver Two' }, country: { value: 'US' } }; const rankings = [ { driverId: 'driver1', rating: 2500, overallRank: 1 }, { driverId: 'driver2', rating: 2400, overallRank: 2 }, ]; const stats1 = { totalRaces: 10, wins: 5, podiums: 7 }; const stats2 = { totalRaces: 8, wins: 3, podiums: 4 }; mockDriverFindAll.mockResolvedValue([driver1, driver2]); mockRankingGetAllDriverRankings.mockReturnValue(rankings); mockDriverStatsGetDriverStats.mockImplementation((id) => { if (id === 'driver1') return stats1; if (id === 'driver2') return stats2; return null; }); mockGetDriverAvatar.mockImplementation((driverId: string) => { if (driverId === 'driver1') return Promise.resolve('avatar-driver1'); if (driverId === 'driver2') return Promise.resolve('avatar-driver2'); return Promise.resolve('avatar-default'); }); const input: GetDriversLeaderboardInput = { leagueId: 'league-1' }; const result = await useCase.execute(input); expect(result.isOk()).toBe(true); expect(result.unwrap()).toBeUndefined(); expect(output.present).toHaveBeenCalledTimes(1); const presented = (output.present as any).mock.calls[0][0] as GetDriversLeaderboardResult; expect(presented).toEqual({ items: [ expect.objectContaining({ driver: driver1, rating: 2500, skillLevel: 'advanced', racesCompleted: 10, wins: 5, podiums: 7, isActive: true, rank: 1, avatarUrl: 'avatar-driver1', }), expect.objectContaining({ driver: driver2, rating: 2400, skillLevel: 'intermediate', racesCompleted: 8, wins: 3, podiums: 4, isActive: true, rank: 2, avatarUrl: 'avatar-driver2', }), ], totalRaces: 18, totalWins: 8, activeCount: 2, }); }); it('should return empty result when no drivers', async () => { const useCase = new GetDriversLeaderboardUseCase( mockDriverRepo, mockRankingService, mockDriverStatsService, mockGetDriverAvatar, mockLogger, output, ); mockDriverFindAll.mockResolvedValue([]); mockRankingGetAllDriverRankings.mockReturnValue([]); const input: GetDriversLeaderboardInput = { leagueId: 'league-1' }; const result = await useCase.execute(input); expect(result.isOk()).toBe(true); expect(result.unwrap()).toBeUndefined(); expect(output.present).toHaveBeenCalledTimes(1); const presented = (output.present as any).mock.calls[0][0] as GetDriversLeaderboardResult; expect(presented).toEqual({ items: [], totalRaces: 0, totalWins: 0, activeCount: 0, }); }); it('should handle drivers without stats', async () => { const useCase = new GetDriversLeaderboardUseCase( mockDriverRepo, mockRankingService, mockDriverStatsService, mockGetDriverAvatar, mockLogger, output, ); const driver1 = { id: 'driver1', name: { value: 'Driver One' }, country: { value: 'US' } }; const rankings = [{ driverId: 'driver1', rating: 2500, overallRank: 1 }]; mockDriverFindAll.mockResolvedValue([driver1]); mockRankingGetAllDriverRankings.mockReturnValue(rankings); mockDriverStatsGetDriverStats.mockReturnValue(null); mockGetDriverAvatar.mockResolvedValue('avatar-driver1'); const input: GetDriversLeaderboardInput = { leagueId: 'league-1' }; const result = await useCase.execute(input); expect(result.isOk()).toBe(true); expect(result.unwrap()).toBeUndefined(); expect(output.present).toHaveBeenCalledTimes(1); const presented = (output.present as any).mock.calls[0][0] as GetDriversLeaderboardResult; expect(presented).toEqual({ items: [ expect.objectContaining({ driver: driver1, rating: 2500, skillLevel: 'advanced', racesCompleted: 0, wins: 0, podiums: 0, isActive: false, rank: 1, avatarUrl: 'avatar-driver1', }), ], totalRaces: 0, totalWins: 0, activeCount: 0, }); }); it('should return error when repository throws', async () => { const useCase = new GetDriversLeaderboardUseCase( mockDriverRepo, mockRankingService, mockDriverStatsService, mockGetDriverAvatar, mockLogger, output, ); const error = new Error('Repository error'); mockDriverFindAll.mockRejectedValue(error); const input: GetDriversLeaderboardInput = { leagueId: 'league-1' }; const result = await useCase.execute(input); expect(result.isErr()).toBe(true); const err = result.unwrapErr(); expect(err.code).toBe('REPOSITORY_ERROR'); expect((err as any).details?.message).toBe('Repository error'); expect(output.present).not.toHaveBeenCalled(); }); });