542 lines
15 KiB
TypeScript
542 lines
15 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { LeagueStandingsViewDataBuilder } from '../../../apps/website/lib/builders/view-data/LeagueStandingsViewDataBuilder';
|
|
import type { LeagueStandingDTO } from '../../../apps/website/lib/types/generated/LeagueStandingDTO';
|
|
import type { LeagueMemberDTO } from '../../../apps/website/lib/types/generated/LeagueMemberDTO';
|
|
|
|
describe('LeagueStandingsViewDataBuilder', () => {
|
|
const mockStandings: LeagueStandingDTO[] = [
|
|
{
|
|
driverId: 'driver-1',
|
|
driver: {
|
|
id: 'driver-1',
|
|
name: 'John Doe',
|
|
iracingId: '12345',
|
|
country: 'US',
|
|
joinedAt: '2024-01-01T00:00:00Z',
|
|
},
|
|
points: 150,
|
|
position: 1,
|
|
wins: 3,
|
|
podiums: 5,
|
|
races: 10,
|
|
positionChange: 0,
|
|
lastRacePoints: 25,
|
|
droppedRaceIds: ['race-1', 'race-2'],
|
|
},
|
|
{
|
|
driverId: 'driver-2',
|
|
driver: {
|
|
id: 'driver-2',
|
|
name: 'Jane Smith',
|
|
iracingId: '67890',
|
|
country: 'UK',
|
|
joinedAt: '2024-01-02T00:00:00Z',
|
|
},
|
|
points: 120,
|
|
position: 2,
|
|
wins: 2,
|
|
podiums: 4,
|
|
races: 10,
|
|
positionChange: 1,
|
|
lastRacePoints: 18,
|
|
droppedRaceIds: ['race-3'],
|
|
},
|
|
{
|
|
driverId: 'driver-3',
|
|
driver: {
|
|
id: 'driver-3',
|
|
name: 'Bob Wilson',
|
|
iracingId: '11111',
|
|
country: 'CA',
|
|
joinedAt: '2024-01-03T00:00:00Z',
|
|
},
|
|
points: 90,
|
|
position: 3,
|
|
wins: 1,
|
|
podiums: 3,
|
|
races: 10,
|
|
positionChange: -1,
|
|
lastRacePoints: 12,
|
|
droppedRaceIds: [],
|
|
},
|
|
];
|
|
|
|
const mockMemberships: LeagueMemberDTO[] = [
|
|
{
|
|
driverId: 'driver-1',
|
|
driver: {
|
|
id: 'driver-1',
|
|
name: 'John Doe',
|
|
iracingId: '12345',
|
|
country: 'US',
|
|
joinedAt: '2024-01-01T00:00:00Z',
|
|
},
|
|
role: 'member',
|
|
joinedAt: '2024-01-01T00:00:00Z',
|
|
},
|
|
{
|
|
driverId: 'driver-2',
|
|
driver: {
|
|
id: 'driver-2',
|
|
name: 'Jane Smith',
|
|
iracingId: '67890',
|
|
country: 'UK',
|
|
joinedAt: '2024-01-02T00:00:00Z',
|
|
},
|
|
role: 'member',
|
|
joinedAt: '2024-01-02T00:00:00Z',
|
|
},
|
|
];
|
|
|
|
describe('build()', () => {
|
|
it('should transform standings correctly', () => {
|
|
const result = LeagueStandingsViewDataBuilder.build(
|
|
{ standings: mockStandings },
|
|
{ members: mockMemberships },
|
|
'league-123'
|
|
);
|
|
|
|
expect(result.leagueId).toBe('league-123');
|
|
expect(result.standings).toHaveLength(3);
|
|
|
|
// Check first standing
|
|
expect(result.standings[0].driverId).toBe('driver-1');
|
|
expect(result.standings[0].position).toBe(1);
|
|
expect(result.standings[0].totalPoints).toBe(150);
|
|
expect(result.standings[0].racesFinished).toBe(10);
|
|
expect(result.standings[0].racesStarted).toBe(10);
|
|
expect(result.standings[0].positionChange).toBe(0);
|
|
expect(result.standings[0].lastRacePoints).toBe(25);
|
|
expect(result.standings[0].droppedRaceIds).toEqual(['race-1', 'race-2']);
|
|
expect(result.standings[0].wins).toBe(3);
|
|
expect(result.standings[0].podiums).toBe(5);
|
|
});
|
|
|
|
it('should calculate position change correctly', () => {
|
|
const result = LeagueStandingsViewDataBuilder.build(
|
|
{ standings: mockStandings },
|
|
{ members: mockMemberships },
|
|
'league-123'
|
|
);
|
|
|
|
expect(result.standings[0].positionChange).toBe(0); // No change
|
|
expect(result.standings[1].positionChange).toBe(1); // Moved up
|
|
expect(result.standings[2].positionChange).toBe(-1); // Moved down
|
|
});
|
|
|
|
it('should map last race points correctly', () => {
|
|
const result = LeagueStandingsViewDataBuilder.build(
|
|
{ standings: mockStandings },
|
|
{ members: mockMemberships },
|
|
'league-123'
|
|
);
|
|
|
|
expect(result.standings[0].lastRacePoints).toBe(25);
|
|
expect(result.standings[1].lastRacePoints).toBe(18);
|
|
expect(result.standings[2].lastRacePoints).toBe(12);
|
|
});
|
|
|
|
it('should handle dropped race IDs correctly', () => {
|
|
const result = LeagueStandingsViewDataBuilder.build(
|
|
{ standings: mockStandings },
|
|
{ members: mockMemberships },
|
|
'league-123'
|
|
);
|
|
|
|
expect(result.standings[0].droppedRaceIds).toEqual(['race-1', 'race-2']);
|
|
expect(result.standings[1].droppedRaceIds).toEqual(['race-3']);
|
|
expect(result.standings[2].droppedRaceIds).toEqual([]);
|
|
});
|
|
|
|
it('should calculate championship stats (wins, podiums)', () => {
|
|
const result = LeagueStandingsViewDataBuilder.build(
|
|
{ standings: mockStandings },
|
|
{ members: mockMemberships },
|
|
'league-123'
|
|
);
|
|
|
|
expect(result.standings[0].wins).toBe(3);
|
|
expect(result.standings[0].podiums).toBe(5);
|
|
expect(result.standings[1].wins).toBe(2);
|
|
expect(result.standings[1].podiums).toBe(4);
|
|
expect(result.standings[2].wins).toBe(1);
|
|
expect(result.standings[2].podiums).toBe(3);
|
|
});
|
|
|
|
it('should extract driver metadata correctly', () => {
|
|
const result = LeagueStandingsViewDataBuilder.build(
|
|
{ standings: mockStandings },
|
|
{ members: mockMemberships },
|
|
'league-123'
|
|
);
|
|
|
|
expect(result.drivers).toHaveLength(3);
|
|
|
|
// Check first driver
|
|
expect(result.drivers[0].id).toBe('driver-1');
|
|
expect(result.drivers[0].name).toBe('John Doe');
|
|
expect(result.drivers[0].iracingId).toBe('12345');
|
|
expect(result.drivers[0].country).toBe('US');
|
|
});
|
|
|
|
it('should convert memberships correctly', () => {
|
|
const result = LeagueStandingsViewDataBuilder.build(
|
|
{ standings: mockStandings },
|
|
{ members: mockMemberships },
|
|
'league-123'
|
|
);
|
|
|
|
expect(result.memberships).toHaveLength(2);
|
|
|
|
// Check first membership
|
|
expect(result.memberships[0].driverId).toBe('driver-1');
|
|
expect(result.memberships[0].leagueId).toBe('league-123');
|
|
expect(result.memberships[0].role).toBe('member');
|
|
expect(result.memberships[0].status).toBe('active');
|
|
});
|
|
|
|
it('should handle empty standings', () => {
|
|
const result = LeagueStandingsViewDataBuilder.build(
|
|
{ standings: [] },
|
|
{ members: mockMemberships },
|
|
'league-123'
|
|
);
|
|
|
|
expect(result.standings).toHaveLength(0);
|
|
expect(result.drivers).toHaveLength(0);
|
|
});
|
|
|
|
it('should handle empty memberships', () => {
|
|
const result = LeagueStandingsViewDataBuilder.build(
|
|
{ standings: mockStandings },
|
|
{ members: [] },
|
|
'league-123'
|
|
);
|
|
|
|
expect(result.memberships).toHaveLength(0);
|
|
});
|
|
|
|
it('should handle missing driver objects in standings', () => {
|
|
const standingsWithMissingDriver: LeagueStandingDTO[] = [
|
|
{
|
|
driverId: 'driver-1',
|
|
driver: {
|
|
id: 'driver-1',
|
|
name: 'John Doe',
|
|
iracingId: '12345',
|
|
country: 'US',
|
|
joinedAt: '2024-01-01T00:00:00Z',
|
|
},
|
|
points: 150,
|
|
position: 1,
|
|
wins: 3,
|
|
podiums: 5,
|
|
races: 10,
|
|
positionChange: 0,
|
|
lastRacePoints: 25,
|
|
droppedRaceIds: [],
|
|
},
|
|
{
|
|
driverId: 'driver-2',
|
|
driver: {
|
|
id: 'driver-2',
|
|
name: 'Jane Smith',
|
|
iracingId: '67890',
|
|
country: 'UK',
|
|
joinedAt: '2024-01-02T00:00:00Z',
|
|
},
|
|
points: 120,
|
|
position: 2,
|
|
wins: 2,
|
|
podiums: 4,
|
|
races: 10,
|
|
positionChange: 1,
|
|
lastRacePoints: 18,
|
|
droppedRaceIds: [],
|
|
},
|
|
];
|
|
|
|
const result = LeagueStandingsViewDataBuilder.build(
|
|
{ standings: standingsWithMissingDriver },
|
|
{ members: mockMemberships },
|
|
'league-123'
|
|
);
|
|
|
|
expect(result.drivers).toHaveLength(2);
|
|
expect(result.drivers[0].id).toBe('driver-1');
|
|
expect(result.drivers[1].id).toBe('driver-2');
|
|
});
|
|
|
|
it('should handle standings with missing positionChange', () => {
|
|
const standingsWithoutPositionChange: LeagueStandingDTO[] = [
|
|
{
|
|
driverId: 'driver-1',
|
|
driver: {
|
|
id: 'driver-1',
|
|
name: 'John Doe',
|
|
iracingId: '12345',
|
|
country: 'US',
|
|
joinedAt: '2024-01-01T00:00:00Z',
|
|
},
|
|
points: 150,
|
|
position: 1,
|
|
wins: 3,
|
|
podiums: 5,
|
|
races: 10,
|
|
positionChange: undefined as any,
|
|
lastRacePoints: 25,
|
|
droppedRaceIds: [],
|
|
},
|
|
];
|
|
|
|
const result = LeagueStandingsViewDataBuilder.build(
|
|
{ standings: standingsWithoutPositionChange },
|
|
{ members: mockMemberships },
|
|
'league-123'
|
|
);
|
|
|
|
expect(result.standings[0].positionChange).toBe(0);
|
|
});
|
|
|
|
it('should handle standings with missing lastRacePoints', () => {
|
|
const standingsWithoutLastRacePoints: LeagueStandingDTO[] = [
|
|
{
|
|
driverId: 'driver-1',
|
|
driver: {
|
|
id: 'driver-1',
|
|
name: 'John Doe',
|
|
iracingId: '12345',
|
|
country: 'US',
|
|
joinedAt: '2024-01-01T00:00:00Z',
|
|
},
|
|
points: 150,
|
|
position: 1,
|
|
wins: 3,
|
|
podiums: 5,
|
|
races: 10,
|
|
positionChange: 0,
|
|
lastRacePoints: undefined as any,
|
|
droppedRaceIds: [],
|
|
},
|
|
];
|
|
|
|
const result = LeagueStandingsViewDataBuilder.build(
|
|
{ standings: standingsWithoutLastRacePoints },
|
|
{ members: mockMemberships },
|
|
'league-123'
|
|
);
|
|
|
|
expect(result.standings[0].lastRacePoints).toBe(0);
|
|
});
|
|
|
|
it('should handle standings with missing droppedRaceIds', () => {
|
|
const standingsWithoutDroppedRaceIds: LeagueStandingDTO[] = [
|
|
{
|
|
driverId: 'driver-1',
|
|
driver: {
|
|
id: 'driver-1',
|
|
name: 'John Doe',
|
|
iracingId: '12345',
|
|
country: 'US',
|
|
joinedAt: '2024-01-01T00:00:00Z',
|
|
},
|
|
points: 150,
|
|
position: 1,
|
|
wins: 3,
|
|
podiums: 5,
|
|
races: 10,
|
|
positionChange: 0,
|
|
lastRacePoints: 25,
|
|
droppedRaceIds: undefined as any,
|
|
},
|
|
];
|
|
|
|
const result = LeagueStandingsViewDataBuilder.build(
|
|
{ standings: standingsWithoutDroppedRaceIds },
|
|
{ members: mockMemberships },
|
|
'league-123'
|
|
);
|
|
|
|
expect(result.standings[0].droppedRaceIds).toEqual([]);
|
|
});
|
|
|
|
it('should handle standings with missing wins', () => {
|
|
const standingsWithoutWins: LeagueStandingDTO[] = [
|
|
{
|
|
driverId: 'driver-1',
|
|
driver: {
|
|
id: 'driver-1',
|
|
name: 'John Doe',
|
|
iracingId: '12345',
|
|
country: 'US',
|
|
joinedAt: '2024-01-01T00:00:00Z',
|
|
},
|
|
points: 150,
|
|
position: 1,
|
|
wins: undefined as any,
|
|
podiums: 5,
|
|
races: 10,
|
|
positionChange: 0,
|
|
lastRacePoints: 25,
|
|
droppedRaceIds: [],
|
|
},
|
|
];
|
|
|
|
const result = LeagueStandingsViewDataBuilder.build(
|
|
{ standings: standingsWithoutWins },
|
|
{ members: mockMemberships },
|
|
'league-123'
|
|
);
|
|
|
|
expect(result.standings[0].wins).toBe(0);
|
|
});
|
|
|
|
it('should handle standings with missing podiums', () => {
|
|
const standingsWithoutPodiums: LeagueStandingDTO[] = [
|
|
{
|
|
driverId: 'driver-1',
|
|
driver: {
|
|
id: 'driver-1',
|
|
name: 'John Doe',
|
|
iracingId: '12345',
|
|
country: 'US',
|
|
joinedAt: '2024-01-01T00:00:00Z',
|
|
},
|
|
points: 150,
|
|
position: 1,
|
|
wins: 3,
|
|
podiums: undefined as any,
|
|
races: 10,
|
|
positionChange: 0,
|
|
lastRacePoints: 25,
|
|
droppedRaceIds: [],
|
|
},
|
|
];
|
|
|
|
const result = LeagueStandingsViewDataBuilder.build(
|
|
{ standings: standingsWithoutPodiums },
|
|
{ members: mockMemberships },
|
|
'league-123'
|
|
);
|
|
|
|
expect(result.standings[0].podiums).toBe(0);
|
|
});
|
|
|
|
it('should handle team championship mode', () => {
|
|
const result = LeagueStandingsViewDataBuilder.build(
|
|
{ standings: mockStandings },
|
|
{ members: mockMemberships },
|
|
'league-123',
|
|
true
|
|
);
|
|
|
|
expect(result.isTeamChampionship).toBe(true);
|
|
});
|
|
|
|
it('should handle non-team championship mode by default', () => {
|
|
const result = LeagueStandingsViewDataBuilder.build(
|
|
{ standings: mockStandings },
|
|
{ members: mockMemberships },
|
|
'league-123'
|
|
);
|
|
|
|
expect(result.isTeamChampionship).toBe(false);
|
|
});
|
|
|
|
it('should handle standings with zero points', () => {
|
|
const standingsWithZeroPoints: LeagueStandingDTO[] = [
|
|
{
|
|
driverId: 'driver-1',
|
|
driver: {
|
|
id: 'driver-1',
|
|
name: 'John Doe',
|
|
iracingId: '12345',
|
|
country: 'US',
|
|
joinedAt: '2024-01-01T00:00:00Z',
|
|
},
|
|
points: 0,
|
|
position: 1,
|
|
wins: 0,
|
|
podiums: 0,
|
|
races: 10,
|
|
positionChange: 0,
|
|
lastRacePoints: 0,
|
|
droppedRaceIds: [],
|
|
},
|
|
];
|
|
|
|
const result = LeagueStandingsViewDataBuilder.build(
|
|
{ standings: standingsWithZeroPoints },
|
|
{ members: mockMemberships },
|
|
'league-123'
|
|
);
|
|
|
|
expect(result.standings[0].totalPoints).toBe(0);
|
|
expect(result.standings[0].wins).toBe(0);
|
|
expect(result.standings[0].podiums).toBe(0);
|
|
});
|
|
|
|
it('should handle standings with negative position change', () => {
|
|
const standingsWithNegativeChange: LeagueStandingDTO[] = [
|
|
{
|
|
driverId: 'driver-1',
|
|
driver: {
|
|
id: 'driver-1',
|
|
name: 'John Doe',
|
|
iracingId: '12345',
|
|
country: 'US',
|
|
joinedAt: '2024-01-01T00:00:00Z',
|
|
},
|
|
points: 150,
|
|
position: 1,
|
|
wins: 3,
|
|
podiums: 5,
|
|
races: 10,
|
|
positionChange: -2,
|
|
lastRacePoints: 25,
|
|
droppedRaceIds: [],
|
|
},
|
|
];
|
|
|
|
const result = LeagueStandingsViewDataBuilder.build(
|
|
{ standings: standingsWithNegativeChange },
|
|
{ members: mockMemberships },
|
|
'league-123'
|
|
);
|
|
|
|
expect(result.standings[0].positionChange).toBe(-2);
|
|
});
|
|
|
|
it('should handle standings with positive position change', () => {
|
|
const standingsWithPositiveChange: LeagueStandingDTO[] = [
|
|
{
|
|
driverId: 'driver-1',
|
|
driver: {
|
|
id: 'driver-1',
|
|
name: 'John Doe',
|
|
iracingId: '12345',
|
|
country: 'US',
|
|
joinedAt: '2024-01-01T00:00:00Z',
|
|
},
|
|
points: 150,
|
|
position: 1,
|
|
wins: 3,
|
|
podiums: 5,
|
|
races: 10,
|
|
positionChange: 3,
|
|
lastRacePoints: 25,
|
|
droppedRaceIds: [],
|
|
},
|
|
];
|
|
|
|
const result = LeagueStandingsViewDataBuilder.build(
|
|
{ standings: standingsWithPositiveChange },
|
|
{ members: mockMemberships },
|
|
'league-123'
|
|
);
|
|
|
|
expect(result.standings[0].positionChange).toBe(3);
|
|
});
|
|
});
|
|
});
|