import { describe, it, expect } from 'vitest'; import { LeagueStandingsViewDataBuilder } from './LeagueStandingsViewDataBuilder'; describe('LeagueStandingsViewDataBuilder', () => { describe('happy paths', () => { it('should transform standings DTOs to LeagueStandingsViewData correctly', () => { const standingsDto = { standings: [ { driverId: 'driver-1', driver: { id: 'driver-1', name: 'Alice', iracingId: '11111', country: 'UK', }, points: 1250, position: 1, wins: 5, podiums: 10, races: 15, positionChange: 2, lastRacePoints: 25, droppedRaceIds: ['race-1', 'race-2'], }, { driverId: 'driver-2', driver: { id: 'driver-2', name: 'Bob', iracingId: '22222', country: 'Germany', }, points: 1100, position: 2, wins: 3, podiums: 8, races: 15, positionChange: -1, lastRacePoints: 15, droppedRaceIds: [], }, ], }; const membershipsDto = { members: [ { driverId: 'driver-1', driver: { id: 'driver-1', name: 'Alice', iracingId: '11111', country: 'UK', joinedAt: '2023-06-01T00:00:00.000Z', }, role: 'member', joinedAt: '2023-06-01T00:00:00.000Z', }, { driverId: 'driver-2', driver: { id: 'driver-2', name: 'Bob', iracingId: '22222', country: 'Germany', joinedAt: '2023-07-01T00:00:00.000Z', }, role: 'member', joinedAt: '2023-07-01T00:00:00.000Z', }, ], }; const result = LeagueStandingsViewDataBuilder.build( standingsDto, membershipsDto, 'league-1', false ); expect(result.leagueId).toBe('league-1'); expect(result.isTeamChampionship).toBe(false); expect(result.currentDriverId).toBeNull(); expect(result.isAdmin).toBe(false); expect(result.standings).toHaveLength(2); expect(result.standings[0].driverId).toBe('driver-1'); expect(result.standings[0].position).toBe(1); expect(result.standings[0].totalPoints).toBe(1250); expect(result.standings[0].racesFinished).toBe(15); expect(result.standings[0].racesStarted).toBe(15); expect(result.standings[0].avgFinish).toBeNull(); expect(result.standings[0].penaltyPoints).toBe(0); expect(result.standings[0].bonusPoints).toBe(0); expect(result.standings[0].positionChange).toBe(2); expect(result.standings[0].lastRacePoints).toBe(25); expect(result.standings[0].droppedRaceIds).toEqual(['race-1', 'race-2']); expect(result.standings[0].wins).toBe(5); expect(result.standings[0].podiums).toBe(10); expect(result.standings[1].driverId).toBe('driver-2'); expect(result.standings[1].position).toBe(2); expect(result.standings[1].totalPoints).toBe(1100); expect(result.standings[1].racesFinished).toBe(15); expect(result.standings[1].racesStarted).toBe(15); expect(result.standings[1].avgFinish).toBeNull(); expect(result.standings[1].penaltyPoints).toBe(0); expect(result.standings[1].bonusPoints).toBe(0); expect(result.standings[1].positionChange).toBe(-1); expect(result.standings[1].lastRacePoints).toBe(15); expect(result.standings[1].droppedRaceIds).toEqual([]); expect(result.standings[1].wins).toBe(3); expect(result.standings[1].podiums).toBe(8); expect(result.drivers).toHaveLength(2); expect(result.drivers[0].id).toBe('driver-1'); expect(result.drivers[0].name).toBe('Alice'); expect(result.drivers[0].iracingId).toBe('11111'); expect(result.drivers[0].country).toBe('UK'); expect(result.drivers[0].avatarUrl).toBeNull(); expect(result.drivers[1].id).toBe('driver-2'); expect(result.drivers[1].name).toBe('Bob'); expect(result.drivers[1].iracingId).toBe('22222'); expect(result.drivers[1].country).toBe('Germany'); expect(result.drivers[1].avatarUrl).toBeNull(); expect(result.memberships).toHaveLength(2); expect(result.memberships[0].driverId).toBe('driver-1'); expect(result.memberships[0].leagueId).toBe('league-1'); expect(result.memberships[0].role).toBe('member'); expect(result.memberships[0].joinedAt).toBe('2023-06-01T00:00:00.000Z'); expect(result.memberships[0].status).toBe('active'); expect(result.memberships[1].driverId).toBe('driver-2'); expect(result.memberships[1].leagueId).toBe('league-1'); expect(result.memberships[1].role).toBe('member'); expect(result.memberships[1].joinedAt).toBe('2023-07-01T00:00:00.000Z'); expect(result.memberships[1].status).toBe('active'); }); it('should handle empty standings and memberships', () => { const standingsDto = { standings: [], }; const membershipsDto = { members: [], }; const result = LeagueStandingsViewDataBuilder.build( standingsDto, membershipsDto, 'league-1', false ); expect(result.standings).toHaveLength(0); expect(result.drivers).toHaveLength(0); expect(result.memberships).toHaveLength(0); }); it('should handle team championship mode', () => { const standingsDto = { standings: [ { driverId: 'driver-1', driver: { id: 'driver-1', name: 'Alice', iracingId: '11111', country: 'UK', }, points: 1250, position: 1, wins: 5, podiums: 10, races: 15, positionChange: 2, lastRacePoints: 25, droppedRaceIds: [], }, ], }; const membershipsDto = { members: [], }; const result = LeagueStandingsViewDataBuilder.build( standingsDto, membershipsDto, 'league-1', true ); expect(result.isTeamChampionship).toBe(true); }); }); describe('data transformation', () => { it('should preserve all DTO fields in the output', () => { const standingsDto = { standings: [ { driverId: 'driver-1', driver: { id: 'driver-1', name: 'Alice', iracingId: '11111', country: 'UK', }, points: 1250, position: 1, wins: 5, podiums: 10, races: 15, positionChange: 2, lastRacePoints: 25, droppedRaceIds: ['race-1'], }, ], }; const membershipsDto = { members: [], }; const result = LeagueStandingsViewDataBuilder.build( standingsDto, membershipsDto, 'league-1', false ); expect(result.standings[0].driverId).toBe(standingsDto.standings[0].driverId); expect(result.standings[0].position).toBe(standingsDto.standings[0].position); expect(result.standings[0].totalPoints).toBe(standingsDto.standings[0].points); expect(result.standings[0].racesFinished).toBe(standingsDto.standings[0].races); expect(result.standings[0].racesStarted).toBe(standingsDto.standings[0].races); expect(result.standings[0].positionChange).toBe(standingsDto.standings[0].positionChange); expect(result.standings[0].lastRacePoints).toBe(standingsDto.standings[0].lastRacePoints); expect(result.standings[0].droppedRaceIds).toEqual(standingsDto.standings[0].droppedRaceIds); expect(result.standings[0].wins).toBe(standingsDto.standings[0].wins); expect(result.standings[0].podiums).toBe(standingsDto.standings[0].podiums); expect(result.drivers[0].id).toBe(standingsDto.standings[0].driver.id); expect(result.drivers[0].name).toBe(standingsDto.standings[0].driver.name); expect(result.drivers[0].iracingId).toBe(standingsDto.standings[0].driver.iracingId); expect(result.drivers[0].country).toBe(standingsDto.standings[0].driver.country); }); it('should not modify the input DTOs', () => { const standingsDto = { standings: [ { driverId: 'driver-1', driver: { id: 'driver-1', name: 'Alice', iracingId: '11111', country: 'UK', }, points: 1250, position: 1, wins: 5, podiums: 10, races: 15, positionChange: 2, lastRacePoints: 25, droppedRaceIds: ['race-1'], }, ], }; const membershipsDto = { members: [], }; const originalStandings = JSON.parse(JSON.stringify(standingsDto)); const originalMemberships = JSON.parse(JSON.stringify(membershipsDto)); LeagueStandingsViewDataBuilder.build( standingsDto, membershipsDto, 'league-1', false ); expect(standingsDto).toEqual(originalStandings); expect(membershipsDto).toEqual(originalMemberships); }); }); describe('edge cases', () => { it('should handle standings with missing optional fields', () => { const standingsDto = { standings: [ { driverId: 'driver-1', driver: { id: 'driver-1', name: 'Alice', iracingId: '11111', country: 'UK', }, points: 1250, position: 1, wins: 5, podiums: 10, races: 15, }, ], }; const membershipsDto = { members: [], }; const result = LeagueStandingsViewDataBuilder.build( standingsDto, membershipsDto, 'league-1', false ); expect(result.standings[0].positionChange).toBe(0); expect(result.standings[0].lastRacePoints).toBe(0); expect(result.standings[0].droppedRaceIds).toEqual([]); }); it('should handle standings with missing driver field', () => { const standingsDto = { standings: [ { driverId: 'driver-1', driver: undefined as any, points: 1250, position: 1, wins: 5, podiums: 10, races: 15, positionChange: 2, lastRacePoints: 25, droppedRaceIds: [], }, ], }; const membershipsDto = { members: [], }; const result = LeagueStandingsViewDataBuilder.build( standingsDto, membershipsDto, 'league-1', false ); expect(result.drivers).toHaveLength(0); }); it('should handle duplicate drivers in standings', () => { const standingsDto = { standings: [ { driverId: 'driver-1', driver: { id: 'driver-1', name: 'Alice', iracingId: '11111', country: 'UK', }, points: 1250, position: 1, wins: 5, podiums: 10, races: 15, positionChange: 2, lastRacePoints: 25, droppedRaceIds: [], }, { driverId: 'driver-1', driver: { id: 'driver-1', name: 'Alice', iracingId: '11111', country: 'UK', }, points: 1100, position: 2, wins: 3, podiums: 8, races: 15, positionChange: -1, lastRacePoints: 15, droppedRaceIds: [], }, ], }; const membershipsDto = { members: [], }; const result = LeagueStandingsViewDataBuilder.build( standingsDto, membershipsDto, 'league-1', false ); // Should only have one driver entry expect(result.drivers).toHaveLength(1); expect(result.drivers[0].id).toBe('driver-1'); }); it('should handle members with different roles', () => { const standingsDto = { standings: [ { driverId: 'driver-1', driver: { id: 'driver-1', name: 'Alice', iracingId: '11111', country: 'UK', }, points: 1250, position: 1, wins: 5, podiums: 10, races: 15, positionChange: 2, lastRacePoints: 25, droppedRaceIds: [], }, ], }; const membershipsDto = { members: [ { driverId: 'driver-1', driver: { id: 'driver-1', name: 'Alice', iracingId: '11111', country: 'UK', joinedAt: '2023-06-01T00:00:00.000Z', }, role: 'admin', joinedAt: '2023-06-01T00:00:00.000Z', }, ], }; const result = LeagueStandingsViewDataBuilder.build( standingsDto, membershipsDto, 'league-1', false ); expect(result.memberships[0].role).toBe('admin'); }); }); });