Files
gridpilot.gg/apps/website/lib/builders/view-data/RaceDetailViewDataBuilder.test.ts
Marc Mintel 108cfbcd65
Some checks failed
Contract Testing / contract-tests (pull_request) Failing after 5m55s
Contract Testing / contract-snapshot (pull_request) Has been skipped
view data tests
2026-01-22 18:22:08 +01:00

394 lines
11 KiB
TypeScript

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);
});
});
});