140 lines
5.2 KiB
TypeScript
140 lines
5.2 KiB
TypeScript
import { describe, it, expect, vi, Mocked } from 'vitest';
|
|
import { RaceStewardingService } from './RaceStewardingService';
|
|
import { RacesApiClient } from '@/lib/api/races/RacesApiClient';
|
|
import { ProtestsApiClient } from '@/lib/api/protests/ProtestsApiClient';
|
|
import { PenaltiesApiClient } from '@/lib/api/penalties/PenaltiesApiClient';
|
|
import { RaceStewardingViewModel } from '@/lib/view-models/RaceStewardingViewModel';
|
|
|
|
describe('RaceStewardingService', () => {
|
|
let mockRacesApiClient: Mocked<RacesApiClient>;
|
|
let mockProtestsApiClient: Mocked<ProtestsApiClient>;
|
|
let mockPenaltiesApiClient: Mocked<PenaltiesApiClient>;
|
|
let service: RaceStewardingService;
|
|
|
|
beforeEach(() => {
|
|
mockRacesApiClient = {
|
|
getDetail: vi.fn(),
|
|
} as Mocked<RacesApiClient>;
|
|
|
|
mockProtestsApiClient = {
|
|
getRaceProtests: vi.fn(),
|
|
} as Mocked<ProtestsApiClient>;
|
|
|
|
mockPenaltiesApiClient = {
|
|
getRacePenalties: vi.fn(),
|
|
} as Mocked<PenaltiesApiClient>;
|
|
|
|
service = new RaceStewardingService(mockRacesApiClient, mockProtestsApiClient, mockPenaltiesApiClient);
|
|
});
|
|
|
|
describe('getRaceStewardingData', () => {
|
|
it('should return race stewarding data with all protests and penalties', async () => {
|
|
const raceId = 'race-123';
|
|
const driverId = 'driver-456';
|
|
|
|
const raceDetailDto = {
|
|
race: {
|
|
id: raceId,
|
|
track: 'Monza',
|
|
scheduledAt: '2023-10-01T10:00:00Z',
|
|
status: 'completed',
|
|
},
|
|
league: {
|
|
id: 'league-1',
|
|
name: 'Test League',
|
|
},
|
|
};
|
|
|
|
const protestsDto = {
|
|
protests: [
|
|
{
|
|
id: 'protest-1',
|
|
protestingDriverId: 'driver-1',
|
|
accusedDriverId: 'driver-2',
|
|
incident: { lap: 5, description: 'Contact at turn 1' },
|
|
filedAt: '2023-10-01T10:00:00Z',
|
|
status: 'pending',
|
|
},
|
|
{
|
|
id: 'protest-2',
|
|
protestingDriverId: 'driver-3',
|
|
accusedDriverId: 'driver-4',
|
|
incident: { lap: 10, description: 'Off-track' },
|
|
filedAt: '2023-10-01T10:05:00Z',
|
|
status: 'upheld',
|
|
},
|
|
],
|
|
driverMap: {
|
|
'driver-1': { id: 'driver-1', name: 'Driver 1' },
|
|
'driver-2': { id: 'driver-2', name: 'Driver 2' },
|
|
'driver-3': { id: 'driver-3', name: 'Driver 3' },
|
|
'driver-4': { id: 'driver-4', name: 'Driver 4' },
|
|
},
|
|
};
|
|
|
|
const penaltiesDto = {
|
|
penalties: [
|
|
{ id: 'penalty-1', driverId: 'driver-2', type: 'time', value: 5, reason: 'Incident' },
|
|
{ id: 'penalty-2', driverId: 'driver-4', type: 'grid', value: 3, reason: 'Qualifying incident' },
|
|
],
|
|
driverMap: {
|
|
'driver-2': { id: 'driver-2', name: 'Driver 2' },
|
|
'driver-4': { id: 'driver-4', name: 'Driver 4' },
|
|
},
|
|
};
|
|
|
|
mockRacesApiClient.getDetail.mockResolvedValue(raceDetailDto as any);
|
|
mockProtestsApiClient.getRaceProtests.mockResolvedValue(protestsDto as any);
|
|
mockPenaltiesApiClient.getRacePenalties.mockResolvedValue(penaltiesDto as any);
|
|
|
|
const result = await service.getRaceStewardingData(raceId, driverId);
|
|
|
|
expect(mockRacesApiClient.getDetail).toHaveBeenCalledWith(raceId, driverId);
|
|
expect(mockProtestsApiClient.getRaceProtests).toHaveBeenCalledWith(raceId);
|
|
expect(mockPenaltiesApiClient.getRacePenalties).toHaveBeenCalledWith(raceId);
|
|
|
|
expect(result).toBeInstanceOf(RaceStewardingViewModel);
|
|
expect(result.race).toEqual(raceDetailDto.race);
|
|
expect(result.league).toEqual(raceDetailDto.league);
|
|
expect(result.protests).toHaveLength(2);
|
|
expect(result.penalties).toHaveLength(2);
|
|
expect(result.pendingProtests).toHaveLength(1);
|
|
expect(result.resolvedProtests).toHaveLength(1);
|
|
expect(result.pendingCount).toBe(1);
|
|
expect(result.resolvedCount).toBe(1);
|
|
expect(result.penaltiesCount).toBe(2);
|
|
});
|
|
|
|
it('should handle empty protests and penalties', async () => {
|
|
const raceId = 'race-123';
|
|
const driverId = 'driver-456';
|
|
|
|
const raceDetailDto = {
|
|
race: { id: raceId, track: 'Monza', scheduledAt: '2023-10-01T10:00:00Z', status: 'completed' },
|
|
league: { id: 'league-1', name: 'Test League' },
|
|
};
|
|
|
|
mockRacesApiClient.getDetail.mockResolvedValue(raceDetailDto as any);
|
|
mockProtestsApiClient.getRaceProtests.mockResolvedValue({ protests: [], driverMap: {} } as any);
|
|
mockPenaltiesApiClient.getRacePenalties.mockResolvedValue({ penalties: [], driverMap: {} } as any);
|
|
|
|
const result = await service.getRaceStewardingData(raceId, driverId);
|
|
|
|
expect(result.protests).toHaveLength(0);
|
|
expect(result.penalties).toHaveLength(0);
|
|
expect(result.pendingCount).toBe(0);
|
|
expect(result.resolvedCount).toBe(0);
|
|
expect(result.penaltiesCount).toBe(0);
|
|
});
|
|
|
|
it('should throw error when any API call fails', async () => {
|
|
const raceId = 'race-123';
|
|
const driverId = 'driver-456';
|
|
|
|
const error = new Error('API call failed');
|
|
mockRacesApiClient.getDetail.mockRejectedValue(error);
|
|
|
|
await expect(service.getRaceStewardingData(raceId, driverId)).rejects.toThrow('API call failed');
|
|
});
|
|
});
|
|
}); |