import { describe, it, expect } from 'vitest'; import { RaceDetailViewDataBuilder } from './RaceDetailViewDataBuilder'; describe('RaceDetailViewDataBuilder', () => { describe('happy paths', () => { it('should transform API DTO to RaceDetailViewData correctly', () => { const apiDto = { race: { id: 'race-123', track: 'Test Track', car: 'Test Car', scheduledAt: '2024-01-01T10:00:00Z', status: 'scheduled', sessionType: 'race', }, league: { id: 'league-456', name: 'Test League', description: 'Test Description', settings: { maxDrivers: 32, qualifyingFormat: 'Open', }, }, entryList: [ { id: 'driver-1', name: 'Driver 1', avatarUrl: 'avatar-url', country: 'US', rating: 1500, isCurrentUser: false, }, ], registration: { isUserRegistered: false, canRegister: true, }, userResult: { position: 5, startPosition: 10, positionChange: 5, incidents: 2, isClean: false, isPodium: false, ratingChange: 10, }, canReopenRace: false, }; const result = RaceDetailViewDataBuilder.build(apiDto); expect(result).toEqual({ race: { id: 'race-123', track: 'Test Track', car: 'Test Car', scheduledAt: '2024-01-01T10:00:00Z', status: 'scheduled', sessionType: 'race', }, league: { id: 'league-456', name: 'Test League', description: 'Test Description', settings: { maxDrivers: 32, qualifyingFormat: 'Open', }, }, entryList: [ { id: 'driver-1', name: 'Driver 1', avatarUrl: 'avatar-url', country: 'US', rating: 1500, isCurrentUser: false, }, ], registration: { isUserRegistered: false, canRegister: true, }, userResult: { position: 5, startPosition: 10, positionChange: 5, incidents: 2, isClean: false, isPodium: false, ratingChange: 10, }, canReopenRace: false, }); }); it('should handle race without league', () => { const apiDto = { race: { id: 'race-456', track: 'Test Track', car: 'Test Car', scheduledAt: '2024-01-01T10:00:00Z', status: 'scheduled', sessionType: 'race', }, entryList: [], registration: { isUserRegistered: false, canRegister: false, }, canReopenRace: false, }; const result = RaceDetailViewDataBuilder.build(apiDto); expect(result.league).toBeUndefined(); }); it('should handle race without user result', () => { const apiDto = { race: { id: 'race-789', track: 'Test Track', car: 'Test Car', scheduledAt: '2024-01-01T10:00:00Z', status: 'scheduled', sessionType: 'race', }, entryList: [], registration: { isUserRegistered: false, canRegister: false, }, canReopenRace: false, }; const result = RaceDetailViewDataBuilder.build(apiDto); expect(result.userResult).toBeUndefined(); }); it('should handle multiple entries in entry list', () => { const apiDto = { race: { id: 'race-101', track: 'Test Track', car: 'Test Car', scheduledAt: '2024-01-01T10:00:00Z', status: 'scheduled', sessionType: 'race', }, entryList: [ { id: 'driver-1', name: 'Driver 1', avatarUrl: 'avatar-url', country: 'US', rating: 1500, isCurrentUser: false, }, { id: 'driver-2', name: 'Driver 2', avatarUrl: 'avatar-url', country: 'UK', rating: 1600, isCurrentUser: true, }, ], registration: { isUserRegistered: true, canRegister: false, }, canReopenRace: false, }; const result = RaceDetailViewDataBuilder.build(apiDto); expect(result.entryList).toHaveLength(2); }); }); describe('data transformation', () => { it('should preserve all DTO fields in the output', () => { const apiDto = { race: { id: 'race-102', track: 'Test Track', car: 'Test Car', scheduledAt: '2024-01-01T10:00:00Z', status: 'scheduled', sessionType: 'race', }, league: { id: 'league-103', name: 'Test League', description: 'Test Description', settings: { maxDrivers: 32, qualifyingFormat: 'Open', }, }, entryList: [ { id: 'driver-1', name: 'Driver 1', avatarUrl: 'avatar-url', country: 'US', rating: 1500, isCurrentUser: false, }, ], registration: { isUserRegistered: false, canRegister: true, }, userResult: { position: 5, startPosition: 10, positionChange: 5, incidents: 2, isClean: false, isPodium: false, ratingChange: 10, }, canReopenRace: false, }; const result = RaceDetailViewDataBuilder.build(apiDto); expect(result.race.id).toBe(apiDto.race.id); expect(result.race.track).toBe(apiDto.race.track); expect(result.race.car).toBe(apiDto.race.car); expect(result.race.scheduledAt).toBe(apiDto.race.scheduledAt); expect(result.race.status).toBe(apiDto.race.status); expect(result.race.sessionType).toBe(apiDto.race.sessionType); expect(result.league?.id).toBe(apiDto.league.id); expect(result.league?.name).toBe(apiDto.league.name); expect(result.registration.isUserRegistered).toBe(apiDto.registration.isUserRegistered); expect(result.registration.canRegister).toBe(apiDto.registration.canRegister); expect(result.canReopenRace).toBe(apiDto.canReopenRace); }); it('should not modify the input DTO', () => { const apiDto = { race: { id: 'race-104', track: 'Test Track', car: 'Test Car', scheduledAt: '2024-01-01T10:00:00Z', status: 'scheduled', sessionType: 'race', }, entryList: [], registration: { isUserRegistered: false, canRegister: false, }, canReopenRace: false, }; const originalDto = { ...apiDto }; RaceDetailViewDataBuilder.build(apiDto); expect(apiDto).toEqual(originalDto); }); }); describe('edge cases', () => { it('should handle null API DTO', () => { const result = RaceDetailViewDataBuilder.build(null); expect(result.race.id).toBe(''); expect(result.race.track).toBe(''); expect(result.race.car).toBe(''); expect(result.race.scheduledAt).toBe(''); expect(result.race.status).toBe('scheduled'); expect(result.race.sessionType).toBe('race'); expect(result.entryList).toHaveLength(0); expect(result.registration.isUserRegistered).toBe(false); expect(result.registration.canRegister).toBe(false); expect(result.canReopenRace).toBe(false); }); it('should handle undefined API DTO', () => { const result = RaceDetailViewDataBuilder.build(undefined); expect(result.race.id).toBe(''); expect(result.race.track).toBe(''); expect(result.race.car).toBe(''); expect(result.race.scheduledAt).toBe(''); expect(result.race.status).toBe('scheduled'); expect(result.race.sessionType).toBe('race'); expect(result.entryList).toHaveLength(0); expect(result.registration.isUserRegistered).toBe(false); expect(result.registration.canRegister).toBe(false); expect(result.canReopenRace).toBe(false); }); it('should handle race without entry list', () => { const apiDto = { race: { id: 'race-105', track: 'Test Track', car: 'Test Car', scheduledAt: '2024-01-01T10:00:00Z', status: 'scheduled', sessionType: 'race', }, registration: { isUserRegistered: false, canRegister: false, }, canReopenRace: false, }; const result = RaceDetailViewDataBuilder.build(apiDto); expect(result.entryList).toHaveLength(0); }); it('should handle different race statuses', () => { const apiDto = { race: { id: 'race-106', track: 'Test Track', car: 'Test Car', scheduledAt: '2024-01-01T10:00:00Z', status: 'running', sessionType: 'race', }, entryList: [], registration: { isUserRegistered: false, canRegister: false, }, canReopenRace: false, }; const result = RaceDetailViewDataBuilder.build(apiDto); expect(result.race.status).toBe('running'); }); it('should handle different session types', () => { const apiDto = { race: { id: 'race-107', track: 'Test Track', car: 'Test Car', scheduledAt: '2024-01-01T10:00:00Z', status: 'scheduled', sessionType: 'qualifying', }, entryList: [], registration: { isUserRegistered: false, canRegister: false, }, canReopenRace: false, }; const result = RaceDetailViewDataBuilder.build(apiDto); expect(result.race.sessionType).toBe('qualifying'); }); it('should handle canReopenRace true', () => { const apiDto = { race: { id: 'race-108', track: 'Test Track', car: 'Test Car', scheduledAt: '2024-01-01T10:00:00Z', status: 'completed', sessionType: 'race', }, entryList: [], registration: { isUserRegistered: false, canRegister: false, }, canReopenRace: true, }; const result = RaceDetailViewDataBuilder.build(apiDto); expect(result.canReopenRace).toBe(true); }); }); });