97 lines
3.3 KiB
TypeScript
97 lines
3.3 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import { LeagueStewardingViewModel, type Penalty, type Protest, type RaceWithProtests } 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([]);
|
|
});
|
|
});
|