view data tests
This commit is contained in:
@@ -0,0 +1,841 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { RaceStewardingViewDataBuilder } from './RaceStewardingViewDataBuilder';
|
||||
|
||||
describe('RaceStewardingViewDataBuilder', () => {
|
||||
describe('happy paths', () => {
|
||||
it('should transform API DTO to RaceStewardingViewData correctly', () => {
|
||||
const apiDto = {
|
||||
race: {
|
||||
id: 'race-123',
|
||||
track: 'Test Track',
|
||||
scheduledAt: '2024-01-01T10:00:00Z',
|
||||
},
|
||||
league: {
|
||||
id: 'league-456',
|
||||
},
|
||||
pendingProtests: [
|
||||
{
|
||||
id: 'protest-1',
|
||||
protestingDriverId: 'driver-1',
|
||||
accusedDriverId: 'driver-2',
|
||||
incident: {
|
||||
lap: 5,
|
||||
description: 'Contact at turn 3',
|
||||
},
|
||||
filedAt: '2024-01-01T10:00:00Z',
|
||||
status: 'pending',
|
||||
proofVideoUrl: 'video-url',
|
||||
decisionNotes: null,
|
||||
},
|
||||
],
|
||||
resolvedProtests: [
|
||||
{
|
||||
id: 'protest-2',
|
||||
protestingDriverId: 'driver-3',
|
||||
accusedDriverId: 'driver-4',
|
||||
incident: {
|
||||
lap: 10,
|
||||
description: 'Contact at turn 5',
|
||||
},
|
||||
filedAt: '2024-01-01T10:00:00Z',
|
||||
status: 'resolved',
|
||||
proofVideoUrl: 'video-url',
|
||||
decisionNotes: 'Penalty applied',
|
||||
},
|
||||
],
|
||||
penalties: [
|
||||
{
|
||||
id: 'penalty-1',
|
||||
driverId: 'driver-5',
|
||||
type: 'time_penalty',
|
||||
value: 5,
|
||||
reason: 'Track limits',
|
||||
notes: 'Warning issued',
|
||||
},
|
||||
],
|
||||
driverMap: {
|
||||
'driver-1': { id: 'driver-1', name: 'Driver 1' },
|
||||
'driver-2': { id: 'driver-2', name: 'Driver 2' },
|
||||
'driver-3': { id: 'driver-3', name: 'Driver 3' },
|
||||
'driver-4': { id: 'driver-4', name: 'Driver 4' },
|
||||
'driver-5': { id: 'driver-5', name: 'Driver 5' },
|
||||
},
|
||||
pendingCount: 1,
|
||||
resolvedCount: 1,
|
||||
penaltiesCount: 1,
|
||||
};
|
||||
|
||||
const result = RaceStewardingViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result).toEqual({
|
||||
race: {
|
||||
id: 'race-123',
|
||||
track: 'Test Track',
|
||||
scheduledAt: '2024-01-01T10:00:00Z',
|
||||
},
|
||||
league: {
|
||||
id: 'league-456',
|
||||
},
|
||||
pendingProtests: [
|
||||
{
|
||||
id: 'protest-1',
|
||||
protestingDriverId: 'driver-1',
|
||||
accusedDriverId: 'driver-2',
|
||||
incident: {
|
||||
lap: 5,
|
||||
description: 'Contact at turn 3',
|
||||
},
|
||||
filedAt: '2024-01-01T10:00:00Z',
|
||||
status: 'pending',
|
||||
proofVideoUrl: 'video-url',
|
||||
decisionNotes: null,
|
||||
},
|
||||
],
|
||||
resolvedProtests: [
|
||||
{
|
||||
id: 'protest-2',
|
||||
protestingDriverId: 'driver-3',
|
||||
accusedDriverId: 'driver-4',
|
||||
incident: {
|
||||
lap: 10,
|
||||
description: 'Contact at turn 5',
|
||||
},
|
||||
filedAt: '2024-01-01T10:00:00Z',
|
||||
status: 'resolved',
|
||||
proofVideoUrl: 'video-url',
|
||||
decisionNotes: 'Penalty applied',
|
||||
},
|
||||
],
|
||||
penalties: [
|
||||
{
|
||||
id: 'penalty-1',
|
||||
driverId: 'driver-5',
|
||||
type: 'time_penalty',
|
||||
value: 5,
|
||||
reason: 'Track limits',
|
||||
notes: 'Warning issued',
|
||||
},
|
||||
],
|
||||
driverMap: {
|
||||
'driver-1': { id: 'driver-1', name: 'Driver 1' },
|
||||
'driver-2': { id: 'driver-2', name: 'Driver 2' },
|
||||
'driver-3': { id: 'driver-3', name: 'Driver 3' },
|
||||
'driver-4': { id: 'driver-4', name: 'Driver 4' },
|
||||
'driver-5': { id: 'driver-5', name: 'Driver 5' },
|
||||
},
|
||||
pendingCount: 1,
|
||||
resolvedCount: 1,
|
||||
penaltiesCount: 1,
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle empty protests and penalties', () => {
|
||||
const apiDto = {
|
||||
race: {
|
||||
id: 'race-456',
|
||||
track: 'Test Track',
|
||||
scheduledAt: '2024-01-01T10:00:00Z',
|
||||
},
|
||||
league: {
|
||||
id: 'league-789',
|
||||
},
|
||||
pendingProtests: [],
|
||||
resolvedProtests: [],
|
||||
penalties: [],
|
||||
driverMap: {},
|
||||
pendingCount: 0,
|
||||
resolvedCount: 0,
|
||||
penaltiesCount: 0,
|
||||
};
|
||||
|
||||
const result = RaceStewardingViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.pendingProtests).toHaveLength(0);
|
||||
expect(result.resolvedProtests).toHaveLength(0);
|
||||
expect(result.penalties).toHaveLength(0);
|
||||
expect(result.pendingCount).toBe(0);
|
||||
expect(result.resolvedCount).toBe(0);
|
||||
expect(result.penaltiesCount).toBe(0);
|
||||
});
|
||||
|
||||
it('should handle multiple protests and penalties', () => {
|
||||
const apiDto = {
|
||||
race: {
|
||||
id: 'race-789',
|
||||
track: 'Test Track',
|
||||
scheduledAt: '2024-01-01T10:00:00Z',
|
||||
},
|
||||
league: {
|
||||
id: 'league-101',
|
||||
},
|
||||
pendingProtests: [
|
||||
{
|
||||
id: 'protest-1',
|
||||
protestingDriverId: 'driver-1',
|
||||
accusedDriverId: 'driver-2',
|
||||
incident: {
|
||||
lap: 5,
|
||||
description: 'Contact at turn 3',
|
||||
},
|
||||
filedAt: '2024-01-01T10:00:00Z',
|
||||
status: 'pending',
|
||||
proofVideoUrl: 'video-url',
|
||||
decisionNotes: null,
|
||||
},
|
||||
{
|
||||
id: 'protest-2',
|
||||
protestingDriverId: 'driver-3',
|
||||
accusedDriverId: 'driver-4',
|
||||
incident: {
|
||||
lap: 10,
|
||||
description: 'Contact at turn 5',
|
||||
},
|
||||
filedAt: '2024-01-01T10:00:00Z',
|
||||
status: 'pending',
|
||||
proofVideoUrl: 'video-url',
|
||||
decisionNotes: null,
|
||||
},
|
||||
],
|
||||
resolvedProtests: [
|
||||
{
|
||||
id: 'protest-3',
|
||||
protestingDriverId: 'driver-5',
|
||||
accusedDriverId: 'driver-6',
|
||||
incident: {
|
||||
lap: 15,
|
||||
description: 'Contact at turn 7',
|
||||
},
|
||||
filedAt: '2024-01-01T10:00:00Z',
|
||||
status: 'resolved',
|
||||
proofVideoUrl: 'video-url',
|
||||
decisionNotes: 'Penalty applied',
|
||||
},
|
||||
],
|
||||
penalties: [
|
||||
{
|
||||
id: 'penalty-1',
|
||||
driverId: 'driver-7',
|
||||
type: 'time_penalty',
|
||||
value: 5,
|
||||
reason: 'Track limits',
|
||||
notes: 'Warning issued',
|
||||
},
|
||||
{
|
||||
id: 'penalty-2',
|
||||
driverId: 'driver-8',
|
||||
type: 'grid_penalty',
|
||||
value: 3,
|
||||
reason: 'Qualifying infringement',
|
||||
notes: null,
|
||||
},
|
||||
],
|
||||
driverMap: {
|
||||
'driver-1': { id: 'driver-1', name: 'Driver 1' },
|
||||
'driver-2': { id: 'driver-2', name: 'Driver 2' },
|
||||
'driver-3': { id: 'driver-3', name: 'Driver 3' },
|
||||
'driver-4': { id: 'driver-4', name: 'Driver 4' },
|
||||
'driver-5': { id: 'driver-5', name: 'Driver 5' },
|
||||
'driver-6': { id: 'driver-6', name: 'Driver 6' },
|
||||
'driver-7': { id: 'driver-7', name: 'Driver 7' },
|
||||
'driver-8': { id: 'driver-8', name: 'Driver 8' },
|
||||
},
|
||||
pendingCount: 2,
|
||||
resolvedCount: 1,
|
||||
penaltiesCount: 2,
|
||||
};
|
||||
|
||||
const result = RaceStewardingViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.pendingProtests).toHaveLength(2);
|
||||
expect(result.resolvedProtests).toHaveLength(1);
|
||||
expect(result.penalties).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('data transformation', () => {
|
||||
it('should preserve all DTO fields in the output', () => {
|
||||
const apiDto = {
|
||||
race: {
|
||||
id: 'race-102',
|
||||
track: 'Test Track',
|
||||
scheduledAt: '2024-01-01T10:00:00Z',
|
||||
},
|
||||
league: {
|
||||
id: 'league-103',
|
||||
},
|
||||
pendingProtests: [
|
||||
{
|
||||
id: 'protest-1',
|
||||
protestingDriverId: 'driver-1',
|
||||
accusedDriverId: 'driver-2',
|
||||
incident: {
|
||||
lap: 5,
|
||||
description: 'Contact at turn 3',
|
||||
},
|
||||
filedAt: '2024-01-01T10:00:00Z',
|
||||
status: 'pending',
|
||||
proofVideoUrl: 'video-url',
|
||||
decisionNotes: null,
|
||||
},
|
||||
],
|
||||
resolvedProtests: [],
|
||||
penalties: [],
|
||||
driverMap: {
|
||||
'driver-1': { id: 'driver-1', name: 'Driver 1' },
|
||||
'driver-2': { id: 'driver-2', name: 'Driver 2' },
|
||||
},
|
||||
pendingCount: 1,
|
||||
resolvedCount: 0,
|
||||
penaltiesCount: 0,
|
||||
};
|
||||
|
||||
const result = RaceStewardingViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.race?.id).toBe(apiDto.race.id);
|
||||
expect(result.race?.track).toBe(apiDto.race.track);
|
||||
expect(result.race?.scheduledAt).toBe(apiDto.race.scheduledAt);
|
||||
expect(result.league?.id).toBe(apiDto.league.id);
|
||||
expect(result.pendingCount).toBe(apiDto.pendingCount);
|
||||
expect(result.resolvedCount).toBe(apiDto.resolvedCount);
|
||||
expect(result.penaltiesCount).toBe(apiDto.penaltiesCount);
|
||||
});
|
||||
|
||||
it('should not modify the input DTO', () => {
|
||||
const apiDto = {
|
||||
race: {
|
||||
id: 'race-104',
|
||||
track: 'Test Track',
|
||||
scheduledAt: '2024-01-01T10:00:00Z',
|
||||
},
|
||||
league: {
|
||||
id: 'league-105',
|
||||
},
|
||||
pendingProtests: [],
|
||||
resolvedProtests: [],
|
||||
penalties: [],
|
||||
driverMap: {},
|
||||
pendingCount: 0,
|
||||
resolvedCount: 0,
|
||||
penaltiesCount: 0,
|
||||
};
|
||||
|
||||
const originalDto = { ...apiDto };
|
||||
RaceStewardingViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(apiDto).toEqual(originalDto);
|
||||
});
|
||||
});
|
||||
|
||||
describe('edge cases', () => {
|
||||
it('should handle null API DTO', () => {
|
||||
const result = RaceStewardingViewDataBuilder.build(null);
|
||||
|
||||
expect(result.race).toBeNull();
|
||||
expect(result.league).toBeNull();
|
||||
expect(result.pendingProtests).toHaveLength(0);
|
||||
expect(result.resolvedProtests).toHaveLength(0);
|
||||
expect(result.penalties).toHaveLength(0);
|
||||
expect(result.driverMap).toEqual({});
|
||||
expect(result.pendingCount).toBe(0);
|
||||
expect(result.resolvedCount).toBe(0);
|
||||
expect(result.penaltiesCount).toBe(0);
|
||||
});
|
||||
|
||||
it('should handle undefined API DTO', () => {
|
||||
const result = RaceStewardingViewDataBuilder.build(undefined);
|
||||
|
||||
expect(result.race).toBeNull();
|
||||
expect(result.league).toBeNull();
|
||||
expect(result.pendingProtests).toHaveLength(0);
|
||||
expect(result.resolvedProtests).toHaveLength(0);
|
||||
expect(result.penalties).toHaveLength(0);
|
||||
expect(result.driverMap).toEqual({});
|
||||
expect(result.pendingCount).toBe(0);
|
||||
expect(result.resolvedCount).toBe(0);
|
||||
expect(result.penaltiesCount).toBe(0);
|
||||
});
|
||||
|
||||
it('should handle race without league', () => {
|
||||
const apiDto = {
|
||||
race: {
|
||||
id: 'race-106',
|
||||
track: 'Test Track',
|
||||
scheduledAt: '2024-01-01T10:00:00Z',
|
||||
},
|
||||
pendingProtests: [],
|
||||
resolvedProtests: [],
|
||||
penalties: [],
|
||||
driverMap: {},
|
||||
pendingCount: 0,
|
||||
resolvedCount: 0,
|
||||
penaltiesCount: 0,
|
||||
};
|
||||
|
||||
const result = RaceStewardingViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.league).toBeNull();
|
||||
});
|
||||
|
||||
it('should handle protests without proof video', () => {
|
||||
const apiDto = {
|
||||
race: {
|
||||
id: 'race-107',
|
||||
track: 'Test Track',
|
||||
scheduledAt: '2024-01-01T10:00:00Z',
|
||||
},
|
||||
league: {
|
||||
id: 'league-108',
|
||||
},
|
||||
pendingProtests: [
|
||||
{
|
||||
id: 'protest-1',
|
||||
protestingDriverId: 'driver-1',
|
||||
accusedDriverId: 'driver-2',
|
||||
incident: {
|
||||
lap: 5,
|
||||
description: 'Contact at turn 3',
|
||||
},
|
||||
filedAt: '2024-01-01T10:00:00Z',
|
||||
status: 'pending',
|
||||
proofVideoUrl: null,
|
||||
decisionNotes: null,
|
||||
},
|
||||
],
|
||||
resolvedProtests: [],
|
||||
penalties: [],
|
||||
driverMap: {
|
||||
'driver-1': { id: 'driver-1', name: 'Driver 1' },
|
||||
'driver-2': { id: 'driver-2', name: 'Driver 2' },
|
||||
},
|
||||
pendingCount: 1,
|
||||
resolvedCount: 0,
|
||||
penaltiesCount: 0,
|
||||
};
|
||||
|
||||
const result = RaceStewardingViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.pendingProtests[0].proofVideoUrl).toBeNull();
|
||||
});
|
||||
|
||||
it('should handle protests without decision notes', () => {
|
||||
const apiDto = {
|
||||
race: {
|
||||
id: 'race-109',
|
||||
track: 'Test Track',
|
||||
scheduledAt: '2024-01-01T10:00:00Z',
|
||||
},
|
||||
league: {
|
||||
id: 'league-110',
|
||||
},
|
||||
pendingProtests: [],
|
||||
resolvedProtests: [
|
||||
{
|
||||
id: 'protest-1',
|
||||
protestingDriverId: 'driver-1',
|
||||
accusedDriverId: 'driver-2',
|
||||
incident: {
|
||||
lap: 5,
|
||||
description: 'Contact at turn 3',
|
||||
},
|
||||
filedAt: '2024-01-01T10:00:00Z',
|
||||
status: 'resolved',
|
||||
proofVideoUrl: 'video-url',
|
||||
decisionNotes: null,
|
||||
},
|
||||
],
|
||||
penalties: [],
|
||||
driverMap: {
|
||||
'driver-1': { id: 'driver-1', name: 'Driver 1' },
|
||||
'driver-2': { id: 'driver-2', name: 'Driver 2' },
|
||||
},
|
||||
pendingCount: 0,
|
||||
resolvedCount: 1,
|
||||
penaltiesCount: 0,
|
||||
};
|
||||
|
||||
const result = RaceStewardingViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.resolvedProtests[0].decisionNotes).toBeNull();
|
||||
});
|
||||
|
||||
it('should handle penalties without notes', () => {
|
||||
const apiDto = {
|
||||
race: {
|
||||
id: 'race-111',
|
||||
track: 'Test Track',
|
||||
scheduledAt: '2024-01-01T10:00:00Z',
|
||||
},
|
||||
league: {
|
||||
id: 'league-112',
|
||||
},
|
||||
pendingProtests: [],
|
||||
resolvedProtests: [],
|
||||
penalties: [
|
||||
{
|
||||
id: 'penalty-1',
|
||||
driverId: 'driver-1',
|
||||
type: 'time_penalty',
|
||||
value: 5,
|
||||
reason: 'Track limits',
|
||||
notes: null,
|
||||
},
|
||||
],
|
||||
driverMap: {
|
||||
'driver-1': { id: 'driver-1', name: 'Driver 1' },
|
||||
},
|
||||
pendingCount: 0,
|
||||
resolvedCount: 0,
|
||||
penaltiesCount: 1,
|
||||
};
|
||||
|
||||
const result = RaceStewardingViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.penalties[0].notes).toBeNull();
|
||||
});
|
||||
|
||||
it('should handle penalties without value', () => {
|
||||
const apiDto = {
|
||||
race: {
|
||||
id: 'race-113',
|
||||
track: 'Test Track',
|
||||
scheduledAt: '2024-01-01T10:00:00Z',
|
||||
},
|
||||
league: {
|
||||
id: 'league-114',
|
||||
},
|
||||
pendingProtests: [],
|
||||
resolvedProtests: [],
|
||||
penalties: [
|
||||
{
|
||||
id: 'penalty-1',
|
||||
driverId: 'driver-1',
|
||||
type: 'disqualification',
|
||||
value: null,
|
||||
reason: 'Technical infringement',
|
||||
notes: null,
|
||||
},
|
||||
],
|
||||
driverMap: {
|
||||
'driver-1': { id: 'driver-1', name: 'Driver 1' },
|
||||
},
|
||||
pendingCount: 0,
|
||||
resolvedCount: 0,
|
||||
penaltiesCount: 1,
|
||||
};
|
||||
|
||||
const result = RaceStewardingViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.penalties[0].value).toBe(0);
|
||||
});
|
||||
|
||||
it('should handle penalties without reason', () => {
|
||||
const apiDto = {
|
||||
race: {
|
||||
id: 'race-115',
|
||||
track: 'Test Track',
|
||||
scheduledAt: '2024-01-01T10:00:00Z',
|
||||
},
|
||||
league: {
|
||||
id: 'league-116',
|
||||
},
|
||||
pendingProtests: [],
|
||||
resolvedProtests: [],
|
||||
penalties: [
|
||||
{
|
||||
id: 'penalty-1',
|
||||
driverId: 'driver-1',
|
||||
type: 'warning',
|
||||
value: 0,
|
||||
reason: null,
|
||||
notes: null,
|
||||
},
|
||||
],
|
||||
driverMap: {
|
||||
'driver-1': { id: 'driver-1', name: 'Driver 1' },
|
||||
},
|
||||
pendingCount: 0,
|
||||
resolvedCount: 0,
|
||||
penaltiesCount: 1,
|
||||
};
|
||||
|
||||
const result = RaceStewardingViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.penalties[0].reason).toBe('');
|
||||
});
|
||||
|
||||
it('should handle different protest statuses', () => {
|
||||
const apiDto = {
|
||||
race: {
|
||||
id: 'race-117',
|
||||
track: 'Test Track',
|
||||
scheduledAt: '2024-01-01T10:00:00Z',
|
||||
},
|
||||
league: {
|
||||
id: 'league-118',
|
||||
},
|
||||
pendingProtests: [
|
||||
{
|
||||
id: 'protest-1',
|
||||
protestingDriverId: 'driver-1',
|
||||
accusedDriverId: 'driver-2',
|
||||
incident: {
|
||||
lap: 5,
|
||||
description: 'Contact at turn 3',
|
||||
},
|
||||
filedAt: '2024-01-01T10:00:00Z',
|
||||
status: 'pending',
|
||||
proofVideoUrl: 'video-url',
|
||||
decisionNotes: null,
|
||||
},
|
||||
],
|
||||
resolvedProtests: [
|
||||
{
|
||||
id: 'protest-2',
|
||||
protestingDriverId: 'driver-3',
|
||||
accusedDriverId: 'driver-4',
|
||||
incident: {
|
||||
lap: 10,
|
||||
description: 'Contact at turn 5',
|
||||
},
|
||||
filedAt: '2024-01-01T10:00:00Z',
|
||||
status: 'resolved',
|
||||
proofVideoUrl: 'video-url',
|
||||
decisionNotes: 'Penalty applied',
|
||||
},
|
||||
{
|
||||
id: 'protest-3',
|
||||
protestingDriverId: 'driver-5',
|
||||
accusedDriverId: 'driver-6',
|
||||
incident: {
|
||||
lap: 15,
|
||||
description: 'Contact at turn 7',
|
||||
},
|
||||
filedAt: '2024-01-01T10:00:00Z',
|
||||
status: 'rejected',
|
||||
proofVideoUrl: 'video-url',
|
||||
decisionNotes: 'Insufficient evidence',
|
||||
},
|
||||
],
|
||||
penalties: [],
|
||||
driverMap: {
|
||||
'driver-1': { id: 'driver-1', name: 'Driver 1' },
|
||||
'driver-2': { id: 'driver-2', name: 'Driver 2' },
|
||||
'driver-3': { id: 'driver-3', name: 'Driver 3' },
|
||||
'driver-4': { id: 'driver-4', name: 'Driver 4' },
|
||||
'driver-5': { id: 'driver-5', name: 'Driver 5' },
|
||||
'driver-6': { id: 'driver-6', name: 'Driver 6' },
|
||||
},
|
||||
pendingCount: 1,
|
||||
resolvedCount: 2,
|
||||
penaltiesCount: 0,
|
||||
};
|
||||
|
||||
const result = RaceStewardingViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.pendingProtests[0].status).toBe('pending');
|
||||
expect(result.resolvedProtests[0].status).toBe('resolved');
|
||||
expect(result.resolvedProtests[1].status).toBe('rejected');
|
||||
});
|
||||
|
||||
it('should handle different penalty types', () => {
|
||||
const apiDto = {
|
||||
race: {
|
||||
id: 'race-119',
|
||||
track: 'Test Track',
|
||||
scheduledAt: '2024-01-01T10:00:00Z',
|
||||
},
|
||||
league: {
|
||||
id: 'league-120',
|
||||
},
|
||||
pendingProtests: [],
|
||||
resolvedProtests: [],
|
||||
penalties: [
|
||||
{
|
||||
id: 'penalty-1',
|
||||
driverId: 'driver-1',
|
||||
type: 'time_penalty',
|
||||
value: 5,
|
||||
reason: 'Track limits',
|
||||
notes: 'Warning issued',
|
||||
},
|
||||
{
|
||||
id: 'penalty-2',
|
||||
driverId: 'driver-2',
|
||||
type: 'grid_penalty',
|
||||
value: 3,
|
||||
reason: 'Qualifying infringement',
|
||||
notes: null,
|
||||
},
|
||||
{
|
||||
id: 'penalty-3',
|
||||
driverId: 'driver-3',
|
||||
type: 'points_deduction',
|
||||
value: 10,
|
||||
reason: 'Dangerous driving',
|
||||
notes: null,
|
||||
},
|
||||
{
|
||||
id: 'penalty-4',
|
||||
driverId: 'driver-4',
|
||||
type: 'disqualification',
|
||||
value: 0,
|
||||
reason: 'Technical infringement',
|
||||
notes: null,
|
||||
},
|
||||
{
|
||||
id: 'penalty-5',
|
||||
driverId: 'driver-5',
|
||||
type: 'warning',
|
||||
value: 0,
|
||||
reason: 'Minor infraction',
|
||||
notes: null,
|
||||
},
|
||||
{
|
||||
id: 'penalty-6',
|
||||
driverId: 'driver-6',
|
||||
type: 'license_points',
|
||||
value: 2,
|
||||
reason: 'Multiple incidents',
|
||||
notes: null,
|
||||
},
|
||||
],
|
||||
driverMap: {
|
||||
'driver-1': { id: 'driver-1', name: 'Driver 1' },
|
||||
'driver-2': { id: 'driver-2', name: 'Driver 2' },
|
||||
'driver-3': { id: 'driver-3', name: 'Driver 3' },
|
||||
'driver-4': { id: 'driver-4', name: 'Driver 4' },
|
||||
'driver-5': { id: 'driver-5', name: 'Driver 5' },
|
||||
'driver-6': { id: 'driver-6', name: 'Driver 6' },
|
||||
},
|
||||
pendingCount: 0,
|
||||
resolvedCount: 0,
|
||||
penaltiesCount: 6,
|
||||
};
|
||||
|
||||
const result = RaceStewardingViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.penalties[0].type).toBe('time_penalty');
|
||||
expect(result.penalties[1].type).toBe('grid_penalty');
|
||||
expect(result.penalties[2].type).toBe('points_deduction');
|
||||
expect(result.penalties[3].type).toBe('disqualification');
|
||||
expect(result.penalties[4].type).toBe('warning');
|
||||
expect(result.penalties[5].type).toBe('license_points');
|
||||
});
|
||||
|
||||
it('should handle empty driver map', () => {
|
||||
const apiDto = {
|
||||
race: {
|
||||
id: 'race-121',
|
||||
track: 'Test Track',
|
||||
scheduledAt: '2024-01-01T10:00:00Z',
|
||||
},
|
||||
league: {
|
||||
id: 'league-122',
|
||||
},
|
||||
pendingProtests: [],
|
||||
resolvedProtests: [],
|
||||
penalties: [],
|
||||
driverMap: {},
|
||||
pendingCount: 0,
|
||||
resolvedCount: 0,
|
||||
penaltiesCount: 0,
|
||||
};
|
||||
|
||||
const result = RaceStewardingViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.driverMap).toEqual({});
|
||||
});
|
||||
|
||||
it('should handle count values from DTO', () => {
|
||||
const apiDto = {
|
||||
race: {
|
||||
id: 'race-123',
|
||||
track: 'Test Track',
|
||||
scheduledAt: '2024-01-01T10:00:00Z',
|
||||
},
|
||||
league: {
|
||||
id: 'league-124',
|
||||
},
|
||||
pendingProtests: [],
|
||||
resolvedProtests: [],
|
||||
penalties: [],
|
||||
driverMap: {},
|
||||
pendingCount: 5,
|
||||
resolvedCount: 10,
|
||||
penaltiesCount: 3,
|
||||
};
|
||||
|
||||
const result = RaceStewardingViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.pendingCount).toBe(5);
|
||||
expect(result.resolvedCount).toBe(10);
|
||||
expect(result.penaltiesCount).toBe(3);
|
||||
});
|
||||
|
||||
it('should calculate counts from arrays when not provided', () => {
|
||||
const apiDto = {
|
||||
race: {
|
||||
id: 'race-125',
|
||||
track: 'Test Track',
|
||||
scheduledAt: '2024-01-01T10:00:00Z',
|
||||
},
|
||||
league: {
|
||||
id: 'league-126',
|
||||
},
|
||||
pendingProtests: [
|
||||
{
|
||||
id: 'protest-1',
|
||||
protestingDriverId: 'driver-1',
|
||||
accusedDriverId: 'driver-2',
|
||||
incident: {
|
||||
lap: 5,
|
||||
description: 'Contact at turn 3',
|
||||
},
|
||||
filedAt: '2024-01-01T10:00:00Z',
|
||||
status: 'pending',
|
||||
proofVideoUrl: 'video-url',
|
||||
decisionNotes: null,
|
||||
},
|
||||
],
|
||||
resolvedProtests: [
|
||||
{
|
||||
id: 'protest-2',
|
||||
protestingDriverId: 'driver-3',
|
||||
accusedDriverId: 'driver-4',
|
||||
incident: {
|
||||
lap: 10,
|
||||
description: 'Contact at turn 5',
|
||||
},
|
||||
filedAt: '2024-01-01T10:00:00Z',
|
||||
status: 'resolved',
|
||||
proofVideoUrl: 'video-url',
|
||||
decisionNotes: 'Penalty applied',
|
||||
},
|
||||
],
|
||||
penalties: [
|
||||
{
|
||||
id: 'penalty-1',
|
||||
driverId: 'driver-5',
|
||||
type: 'time_penalty',
|
||||
value: 5,
|
||||
reason: 'Track limits',
|
||||
notes: 'Warning issued',
|
||||
},
|
||||
],
|
||||
driverMap: {
|
||||
'driver-1': { id: 'driver-1', name: 'Driver 1' },
|
||||
'driver-2': { id: 'driver-2', name: 'Driver 2' },
|
||||
'driver-3': { id: 'driver-3', name: 'Driver 3' },
|
||||
'driver-4': { id: 'driver-4', name: 'Driver 4' },
|
||||
'driver-5': { id: 'driver-5', name: 'Driver 5' },
|
||||
},
|
||||
};
|
||||
|
||||
const result = RaceStewardingViewDataBuilder.build(apiDto);
|
||||
|
||||
expect(result.pendingCount).toBe(1);
|
||||
expect(result.resolvedCount).toBe(1);
|
||||
expect(result.penaltiesCount).toBe(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user