import { describe, it, expect } from 'vitest'; import { LeagueScheduleViewDataBuilder } from './LeagueScheduleViewDataBuilder'; describe('LeagueScheduleViewDataBuilder', () => { describe('happy paths', () => { it('should transform schedule DTO to LeagueScheduleViewData correctly', () => { const now = new Date(); const pastDate = new Date(now.getTime() - 24 * 60 * 60 * 1000); // 1 day ago const futureDate = new Date(now.getTime() + 24 * 60 * 60 * 1000); // 1 day from now const apiDto = { leagueId: 'league-1', races: [ { id: 'race-1', name: 'Past Race', date: pastDate.toISOString(), track: 'Spa', car: 'Porsche 911 GT3', sessionType: 'race', }, { id: 'race-2', name: 'Future Race', date: futureDate.toISOString(), track: 'Monza', car: 'Ferrari 488 GT3', sessionType: 'race', }, ], }; const result = LeagueScheduleViewDataBuilder.build(apiDto, 'driver-1', true); expect(result.leagueId).toBe('league-1'); expect(result.races).toHaveLength(2); expect(result.races[0].id).toBe('race-1'); expect(result.races[0].name).toBe('Past Race'); expect(result.races[0].scheduledAt).toBe(pastDate.toISOString()); expect(result.races[0].track).toBe('Spa'); expect(result.races[0].car).toBe('Porsche 911 GT3'); expect(result.races[0].sessionType).toBe('race'); expect(result.races[0].isPast).toBe(true); expect(result.races[0].isUpcoming).toBe(false); expect(result.races[0].status).toBe('completed'); expect(result.races[0].isUserRegistered).toBe(false); expect(result.races[0].canRegister).toBe(false); expect(result.races[0].canEdit).toBe(true); expect(result.races[0].canReschedule).toBe(true); expect(result.races[1].id).toBe('race-2'); expect(result.races[1].name).toBe('Future Race'); expect(result.races[1].scheduledAt).toBe(futureDate.toISOString()); expect(result.races[1].track).toBe('Monza'); expect(result.races[1].car).toBe('Ferrari 488 GT3'); expect(result.races[1].sessionType).toBe('race'); expect(result.races[1].isPast).toBe(false); expect(result.races[1].isUpcoming).toBe(true); expect(result.races[1].status).toBe('scheduled'); expect(result.races[1].isUserRegistered).toBe(false); expect(result.races[1].canRegister).toBe(true); expect(result.races[1].canEdit).toBe(true); expect(result.races[1].canReschedule).toBe(true); expect(result.currentDriverId).toBe('driver-1'); expect(result.isAdmin).toBe(true); }); it('should handle empty races list', () => { const apiDto = { leagueId: 'league-1', races: [], }; const result = LeagueScheduleViewDataBuilder.build(apiDto); expect(result.leagueId).toBe('league-1'); expect(result.races).toHaveLength(0); }); it('should handle non-admin user', () => { const now = new Date(); const futureDate = new Date(now.getTime() + 24 * 60 * 60 * 1000); const apiDto = { leagueId: 'league-1', races: [ { id: 'race-1', name: 'Future Race', date: futureDate.toISOString(), track: 'Spa', car: 'Porsche 911 GT3', sessionType: 'race', }, ], }; const result = LeagueScheduleViewDataBuilder.build(apiDto, 'driver-1', false); expect(result.races[0].canEdit).toBe(false); expect(result.races[0].canReschedule).toBe(false); }); }); describe('data transformation', () => { it('should preserve all DTO fields in the output', () => { const now = new Date(); const futureDate = new Date(now.getTime() + 24 * 60 * 60 * 1000); const apiDto = { leagueId: 'league-1', races: [ { id: 'race-1', name: 'Test Race', date: futureDate.toISOString(), track: 'Spa', car: 'Porsche 911 GT3', sessionType: 'race', }, ], }; const result = LeagueScheduleViewDataBuilder.build(apiDto); expect(result.leagueId).toBe(apiDto.leagueId); expect(result.races[0].id).toBe(apiDto.races[0].id); expect(result.races[0].name).toBe(apiDto.races[0].name); expect(result.races[0].scheduledAt).toBe(apiDto.races[0].date); expect(result.races[0].track).toBe(apiDto.races[0].track); expect(result.races[0].car).toBe(apiDto.races[0].car); expect(result.races[0].sessionType).toBe(apiDto.races[0].sessionType); }); it('should not modify the input DTO', () => { const now = new Date(); const futureDate = new Date(now.getTime() + 24 * 60 * 60 * 1000); const apiDto = { leagueId: 'league-1', races: [ { id: 'race-1', name: 'Test Race', date: futureDate.toISOString(), track: 'Spa', car: 'Porsche 911 GT3', sessionType: 'race', }, ], }; const originalDto = JSON.parse(JSON.stringify(apiDto)); LeagueScheduleViewDataBuilder.build(apiDto); expect(apiDto).toEqual(originalDto); }); }); describe('edge cases', () => { it('should handle races with missing optional fields', () => { const now = new Date(); const futureDate = new Date(now.getTime() + 24 * 60 * 60 * 1000); const apiDto = { leagueId: 'league-1', races: [ { id: 'race-1', name: 'Test Race', date: futureDate.toISOString(), track: 'Spa', car: 'Porsche 911 GT3', sessionType: 'race', }, ], }; const result = LeagueScheduleViewDataBuilder.build(apiDto); expect(result.races[0].track).toBe('Spa'); expect(result.races[0].car).toBe('Porsche 911 GT3'); expect(result.races[0].sessionType).toBe('race'); }); it('should handle races at exactly the current time', () => { const now = new Date(); const currentRaceDate = new Date(now.getTime()); const apiDto = { leagueId: 'league-1', races: [ { id: 'race-1', name: 'Current Race', date: currentRaceDate.toISOString(), track: 'Spa', car: 'Porsche 911 GT3', sessionType: 'race', }, ], }; const result = LeagueScheduleViewDataBuilder.build(apiDto); // Race at current time should be considered past expect(result.races[0].isPast).toBe(true); expect(result.races[0].isUpcoming).toBe(false); expect(result.races[0].status).toBe('completed'); }); }); });