import { describe, it, expect, vi, Mocked } from 'vitest'; import { RaceService } from './RaceService'; import { RacesApiClient } from '../../api/races/RacesApiClient'; import { RaceDetailViewModel } from '../../view-models/RaceDetailViewModel'; import { RacesPageViewModel } from '../../view-models/RacesPageViewModel'; import { RaceStatsViewModel } from '../../view-models/RaceStatsViewModel'; describe('RaceService', () => { let mockApiClient: Mocked; let service: RaceService; beforeEach(() => { mockApiClient = { getDetail: vi.fn(), getPageData: vi.fn(), getTotal: vi.fn(), } as Mocked; service = new RaceService(mockApiClient); }); describe('getRaceDetail', () => { it('should call apiClient.getDetail and return RaceDetailViewModel', async () => { const raceId = 'race-123'; const driverId = 'driver-456'; const mockDto = { race: { id: raceId, track: 'Test Track' }, league: { id: 'league-1', name: 'Test League' }, entryList: [], registration: { isRegistered: true, canRegister: false }, userResult: null, }; mockApiClient.getDetail.mockResolvedValue(mockDto as any); const result = await service.getRaceDetail(raceId, driverId); expect(mockApiClient.getDetail).toHaveBeenCalledWith(raceId, driverId); expect(result).toBeInstanceOf(RaceDetailViewModel); expect(result.race?.id).toBe(raceId); }); it('should throw error when apiClient.getDetail fails', async () => { const raceId = 'race-123'; const driverId = 'driver-456'; const error = new Error('API call failed'); mockApiClient.getDetail.mockRejectedValue(error); await expect(service.getRaceDetail(raceId, driverId)).rejects.toThrow('API call failed'); }); }); describe('getRacesPageData', () => { it('should call apiClient.getPageData and return RacesPageViewModel with transformed data', async () => { const mockDto = { races: [ { id: 'race-1', track: 'Monza', car: 'Ferrari', scheduledAt: '2023-10-01T10:00:00Z', status: 'upcoming', leagueId: 'league-1', leagueName: 'Test League', }, { id: 'race-2', track: 'Silverstone', car: 'Mercedes', scheduledAt: '2023-09-15T10:00:00Z', status: 'completed', leagueId: 'league-1', leagueName: 'Test League', }, ], }; mockApiClient.getPageData.mockResolvedValue(mockDto as any); const result = await service.getRacesPageData(); expect(mockApiClient.getPageData).toHaveBeenCalled(); expect(result).toBeInstanceOf(RacesPageViewModel); expect(result.upcomingRaces).toHaveLength(1); expect(result.completedRaces).toHaveLength(1); expect(result.totalCount).toBe(2); expect(result.upcomingRaces[0].title).toBe('Monza - Ferrari'); expect(result.completedRaces[0].title).toBe('Silverstone - Mercedes'); }); it('should handle empty races array', async () => { const mockDto = { races: [] }; mockApiClient.getPageData.mockResolvedValue(mockDto as any); const result = await service.getRacesPageData(); expect(result.upcomingRaces).toHaveLength(0); expect(result.completedRaces).toHaveLength(0); expect(result.totalCount).toBe(0); }); it('should throw error when apiClient.getPageData fails', async () => { const error = new Error('API call failed'); mockApiClient.getPageData.mockRejectedValue(error); await expect(service.getRacesPageData()).rejects.toThrow('API call failed'); }); }); describe('getRacesTotal', () => { it('should call apiClient.getTotal and return RaceStatsViewModel', async () => { const mockDto = { totalRaces: 42 }; mockApiClient.getTotal.mockResolvedValue(mockDto as any); const result = await service.getRacesTotal(); expect(mockApiClient.getTotal).toHaveBeenCalled(); expect(result).toBeInstanceOf(RaceStatsViewModel); expect(result.totalRaces).toBe(42); expect(result.formattedTotalRaces).toBe('42'); }); it('should throw error when apiClient.getTotal fails', async () => { const error = new Error('API call failed'); mockApiClient.getTotal.mockRejectedValue(error); await expect(service.getRacesTotal()).rejects.toThrow('API call failed'); }); }); });