Files
gridpilot.gg/apps/website/lib/view-models/LeagueStewardingViewModel.test.ts
2025-12-20 00:31:31 +01:00

97 lines
3.3 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import { LeagueStewardingViewModel, type RaceWithProtests, type Protest, type Penalty } from './LeagueStewardingViewModel';
const createProtest = (id: string, status: string): Protest => ({
id,
protestingDriverId: `pd-${id}`,
accusedDriverId: `ad-${id}`,
incident: { lap: 1, description: 'Test incident' },
filedAt: '2024-01-01T21:00:00Z',
status,
});
const createPenalty = (id: string): Penalty => ({
id,
driverId: `d-${id}`,
type: 'time',
value: 5,
reason: 'Test penalty',
});
const createRaceWithProtests = (id: string, pendingCount: number, resolvedCount: number, penaltiesCount: number): RaceWithProtests => ({
race: {
id,
track: 'Spa-Francorchamps',
scheduledAt: new Date('2024-01-01T20:00:00Z'),
},
pendingProtests: Array.from({ length: pendingCount }, (_, index) => createProtest(`${id}-pending-${index + 1}`, 'pending')),
resolvedProtests: Array.from({ length: resolvedCount }, (_, index) => createProtest(`${id}-resolved-${index + 1}`, 'upheld')),
penalties: Array.from({ length: penaltiesCount }, (_, index) => createPenalty(`${id}-pen-${index + 1}`)),
});
describe('LeagueStewardingViewModel', () => {
it('aggregates totals across all races', () => {
const races: RaceWithProtests[] = [
createRaceWithProtests('race-1', 2, 1, 1),
createRaceWithProtests('race-2', 1, 3, 2),
createRaceWithProtests('race-3', 0, 0, 0),
];
const driverMap = {
d1: { id: 'd1', name: 'Driver 1' },
d2: { id: 'd2', name: 'Driver 2' },
};
const viewModel = new LeagueStewardingViewModel(races, driverMap);
expect(viewModel.totalPending).toBe(3);
expect(viewModel.totalResolved).toBe(4);
expect(viewModel.totalPenalties).toBe(3);
});
it('filters races into pending and history buckets', () => {
const races: RaceWithProtests[] = [
createRaceWithProtests('race-1', 2, 0, 0), // pending only
createRaceWithProtests('race-2', 0, 3, 0), // history only (resolved)
createRaceWithProtests('race-3', 0, 0, 2), // history only (penalties)
createRaceWithProtests('race-4', 0, 0, 0), // no activity
];
const viewModel = new LeagueStewardingViewModel(races, {});
const pendingIds = viewModel.pendingRaces.map(r => r.race.id).sort();
const historyIds = viewModel.historyRaces.map(r => r.race.id).sort();
expect(pendingIds).toEqual(['race-1']);
expect(historyIds).toEqual(['race-2', 'race-3']);
});
it('exposes all drivers as a flat array', () => {
const races: RaceWithProtests[] = [createRaceWithProtests('race-1', 0, 0, 0)];
const driverMap = {
d1: { id: 'd1', name: 'Driver 1', avatarUrl: 'avatar-1.png' },
d2: { id: 'd2', name: 'Driver 2', iracingId: 'ir-2' },
};
const viewModel = new LeagueStewardingViewModel(races, driverMap);
expect(viewModel.allDrivers).toHaveLength(2);
expect(viewModel.allDrivers).toEqual([
driverMap.d1,
driverMap.d2,
]);
});
it('handles an empty dataset gracefully', () => {
const viewModel = new LeagueStewardingViewModel([], {});
expect(viewModel.totalPending).toBe(0);
expect(viewModel.totalResolved).toBe(0);
expect(viewModel.totalPenalties).toBe(0);
expect(viewModel.pendingRaces).toEqual([]);
expect(viewModel.historyRaces).toEqual([]);
expect(viewModel.allDrivers).toEqual([]);
});
});