import { describe, expect, it } from 'vitest'; import { RaceStewardingViewModel } from './RaceStewardingViewModel'; const createRaceStewardingDto = () => ({ raceDetail: { race: { id: 'race-1', track: 'Spa-Francorchamps', scheduledAt: '2024-01-01T20:00:00Z', status: 'completed', }, league: { id: 'league-1', name: 'Test League', }, }, protests: { protests: [ { id: 'p1', protestingDriverId: 'd1', accusedDriverId: 'd2', incident: { lap: 1, description: 'Turn 1 divebomb' }, filedAt: '2024-01-01T21:00:00Z', status: 'pending', }, { id: 'p2', protestingDriverId: 'd3', accusedDriverId: 'd4', incident: { lap: 5, description: 'Blocking' }, filedAt: '2024-01-01T21:05:00Z', status: 'under_review', }, { id: 'p3', protestingDriverId: 'd5', accusedDriverId: 'd6', incident: { lap: 10, description: 'Contact' }, filedAt: '2024-01-01T21:10:00Z', status: 'upheld', }, { id: 'p4', protestingDriverId: 'd7', accusedDriverId: 'd8', incident: { lap: 12, description: 'Off-track overtake' }, filedAt: '2024-01-01T21:15:00Z', status: 'dismissed', }, { id: 'p5', protestingDriverId: 'd9', accusedDriverId: 'd10', incident: { lap: 15, description: 'Withdrawn protest' }, filedAt: '2024-01-01T21:20:00Z', status: 'withdrawn', }, ], driverMap: { d1: { id: 'd1', name: 'Driver 1' }, d2: { id: 'd2', name: 'Driver 2' }, }, }, penalties: { penalties: [ { id: 'pen1', driverId: 'd2', type: 'time', value: 5, reason: 'Avoidable contact', }, { id: 'pen2', driverId: 'd3', type: 'points', value: 2, reason: 'Reckless driving', }, ], driverMap: { d3: { id: 'd3', name: 'Driver 3' }, d4: { id: 'd4', name: 'Driver 4' }, }, }, }); describe('RaceStewardingViewModel', () => { it('maps core race, league, protests, penalties and driver map', () => { const dto = createRaceStewardingDto(); const viewModel = new RaceStewardingViewModel(dto as any); expect(viewModel.race).toEqual(dto.raceDetail.race); expect(viewModel.league).toEqual(dto.raceDetail.league); expect(viewModel.protests).toEqual(dto.protests.protests); expect(viewModel.penalties).toEqual(dto.penalties.penalties); expect(viewModel.driverMap).toEqual({ ...dto.protests.driverMap, ...dto.penalties.driverMap, }); }); it('derives pending and resolved protest buckets and counts', () => { const dto = createRaceStewardingDto(); const viewModel = new RaceStewardingViewModel(dto as any); const pendingIds = viewModel.pendingProtests.map(p => p.id); const resolvedIds = viewModel.resolvedProtests.map(p => p.id); expect(pendingIds.sort()).toEqual(['p1', 'p2']); expect(resolvedIds.sort()).toEqual(['p3', 'p4', 'p5']); expect(viewModel.pendingCount).toBe(2); expect(viewModel.resolvedCount).toBe(3); }); it('derives penalties count from penalties list', () => { const dto = createRaceStewardingDto(); const viewModel = new RaceStewardingViewModel(dto as any); expect(viewModel.penaltiesCount).toBe(2); }); it('handles empty protests and penalties gracefully', () => { const dto = createRaceStewardingDto(); dto.protests.protests = []; dto.penalties.penalties = []; const viewModel = new RaceStewardingViewModel(dto as any); expect(viewModel.pendingProtests).toEqual([]); expect(viewModel.resolvedProtests).toEqual([]); expect(viewModel.pendingCount).toBe(0); expect(viewModel.resolvedCount).toBe(0); expect(viewModel.penaltiesCount).toBe(0); }); });