import { describe, it, expect } from 'vitest'; import { ProtestDetailViewDataBuilder } from './ProtestDetailViewDataBuilder'; describe('ProtestDetailViewDataBuilder', () => { describe('happy paths', () => { it('should transform ProtestDetailApiDto to ProtestDetailViewData correctly', () => { const protestDetailApiDto = { id: 'protest-123', leagueId: 'league-456', status: 'pending', submittedAt: '2024-01-01T10:00:00Z', incident: { lap: 5, description: 'Contact at turn 3', }, protestingDriver: { id: 'driver-1', name: 'Driver 1', }, accusedDriver: { id: 'driver-2', name: 'Driver 2', }, race: { id: 'race-1', name: 'Test Race', scheduledAt: '2024-01-01T10:00:00Z', }, penaltyTypes: [ { type: 'time_penalty', label: 'Time Penalty', description: 'Add time to race result', }, ], }; const result = ProtestDetailViewDataBuilder.build(protestDetailApiDto); expect(result).toEqual({ protestId: 'protest-123', leagueId: 'league-456', status: 'pending', submittedAt: '2024-01-01T10:00:00Z', incident: { lap: 5, description: 'Contact at turn 3', }, protestingDriver: { id: 'driver-1', name: 'Driver 1', }, accusedDriver: { id: 'driver-2', name: 'Driver 2', }, race: { id: 'race-1', name: 'Test Race', scheduledAt: '2024-01-01T10:00:00Z', }, penaltyTypes: [ { type: 'time_penalty', label: 'Time Penalty', description: 'Add time to race result', }, ], }); }); it('should handle resolved status', () => { const protestDetailApiDto = { id: 'protest-456', leagueId: 'league-789', status: 'resolved', submittedAt: '2024-01-01T10:00:00Z', incident: { lap: 10, description: 'Contact at turn 5', }, protestingDriver: { id: 'driver-3', name: 'Driver 3', }, accusedDriver: { id: 'driver-4', name: 'Driver 4', }, race: { id: 'race-2', name: 'Test Race 2', scheduledAt: '2024-01-02T10:00:00Z', }, penaltyTypes: [], }; const result = ProtestDetailViewDataBuilder.build(protestDetailApiDto); expect(result.status).toBe('resolved'); }); it('should handle multiple penalty types', () => { const protestDetailApiDto = { id: 'protest-789', leagueId: 'league-101', status: 'pending', submittedAt: '2024-01-01T10:00:00Z', incident: { lap: 15, description: 'Contact at turn 7', }, protestingDriver: { id: 'driver-5', name: 'Driver 5', }, accusedDriver: { id: 'driver-6', name: 'Driver 6', }, race: { id: 'race-3', name: 'Test Race 3', scheduledAt: '2024-01-03T10:00:00Z', }, penaltyTypes: [ { type: 'time_penalty', label: 'Time Penalty', description: 'Add time to race result', }, { type: 'grid_penalty', label: 'Grid Penalty', description: 'Drop grid positions', }, ], }; const result = ProtestDetailViewDataBuilder.build(protestDetailApiDto); expect(result.penaltyTypes).toHaveLength(2); }); }); describe('data transformation', () => { it('should preserve all DTO fields in the output', () => { const protestDetailApiDto = { id: 'protest-101', leagueId: 'league-102', status: 'pending', submittedAt: '2024-01-01T10:00:00Z', incident: { lap: 5, description: 'Contact at turn 3', }, protestingDriver: { id: 'driver-1', name: 'Driver 1', }, accusedDriver: { id: 'driver-2', name: 'Driver 2', }, race: { id: 'race-1', name: 'Test Race', scheduledAt: '2024-01-01T10:00:00Z', }, penaltyTypes: [ { type: 'time_penalty', label: 'Time Penalty', description: 'Add time to race result', }, ], }; const result = ProtestDetailViewDataBuilder.build(protestDetailApiDto); expect(result.protestId).toBe(protestDetailApiDto.id); expect(result.leagueId).toBe(protestDetailApiDto.leagueId); expect(result.status).toBe(protestDetailApiDto.status); expect(result.submittedAt).toBe(protestDetailApiDto.submittedAt); expect(result.incident).toEqual(protestDetailApiDto.incident); expect(result.protestingDriver).toEqual(protestDetailApiDto.protestingDriver); expect(result.accusedDriver).toEqual(protestDetailApiDto.accusedDriver); expect(result.race).toEqual(protestDetailApiDto.race); expect(result.penaltyTypes).toEqual(protestDetailApiDto.penaltyTypes); }); it('should not modify the input DTO', () => { const protestDetailApiDto = { id: 'protest-102', leagueId: 'league-103', status: 'pending', submittedAt: '2024-01-01T10:00:00Z', incident: { lap: 5, description: 'Contact at turn 3', }, protestingDriver: { id: 'driver-1', name: 'Driver 1', }, accusedDriver: { id: 'driver-2', name: 'Driver 2', }, race: { id: 'race-1', name: 'Test Race', scheduledAt: '2024-01-01T10:00:00Z', }, penaltyTypes: [], }; const originalDto = { ...protestDetailApiDto }; ProtestDetailViewDataBuilder.build(protestDetailApiDto); expect(protestDetailApiDto).toEqual(originalDto); }); }); describe('edge cases', () => { it('should handle different status values', () => { const protestDetailApiDto = { id: 'protest-103', leagueId: 'league-104', status: 'rejected', submittedAt: '2024-01-01T10:00:00Z', incident: { lap: 5, description: 'Contact at turn 3', }, protestingDriver: { id: 'driver-1', name: 'Driver 1', }, accusedDriver: { id: 'driver-2', name: 'Driver 2', }, race: { id: 'race-1', name: 'Test Race', scheduledAt: '2024-01-01T10:00:00Z', }, penaltyTypes: [], }; const result = ProtestDetailViewDataBuilder.build(protestDetailApiDto); expect(result.status).toBe('rejected'); }); it('should handle lap 0', () => { const protestDetailApiDto = { id: 'protest-104', leagueId: 'league-105', status: 'pending', submittedAt: '2024-01-01T10:00:00Z', incident: { lap: 0, description: 'Contact at start', }, protestingDriver: { id: 'driver-1', name: 'Driver 1', }, accusedDriver: { id: 'driver-2', name: 'Driver 2', }, race: { id: 'race-1', name: 'Test Race', scheduledAt: '2024-01-01T10:00:00Z', }, penaltyTypes: [], }; const result = ProtestDetailViewDataBuilder.build(protestDetailApiDto); expect(result.incident.lap).toBe(0); }); it('should handle empty description', () => { const protestDetailApiDto = { id: 'protest-105', leagueId: 'league-106', status: 'pending', submittedAt: '2024-01-01T10:00:00Z', incident: { lap: 5, description: '', }, protestingDriver: { id: 'driver-1', name: 'Driver 1', }, accusedDriver: { id: 'driver-2', name: 'Driver 2', }, race: { id: 'race-1', name: 'Test Race', scheduledAt: '2024-01-01T10:00:00Z', }, penaltyTypes: [], }; const result = ProtestDetailViewDataBuilder.build(protestDetailApiDto); expect(result.incident.description).toBe(''); }); }); });