Files
gridpilot.gg/core/racing/domain/entities/penalty/Penalty.test.ts
2026-01-16 21:35:35 +01:00

232 lines
6.9 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import { RacingDomainInvariantError, RacingDomainValidationError } from '../../errors/RacingDomainError';
import { Penalty } from './Penalty';
describe('Penalty', () => {
describe('create', () => {
it('should create a penalty with required fields', () => {
const penalty = Penalty.create({
id: 'penalty-1',
leagueId: 'league-1',
raceId: 'race-1',
driverId: 'driver-1',
type: 'time_penalty',
value: 5,
reason: 'Speeding',
issuedBy: 'steward-1',
});
expect(penalty.id.toString()).toBe('penalty-1');
expect(penalty.leagueId).toBe('league-1');
expect(penalty.raceId).toBe('race-1');
expect(penalty.driverId).toBe('driver-1');
expect(penalty.type).toBe('time_penalty');
expect(penalty.value).toBe(5);
expect(penalty.reason).toBe('Speeding');
expect(penalty.issuedBy).toBe('steward-1');
expect(penalty.status).toBe('pending');
expect(penalty.appliedAt).toBeUndefined();
expect(penalty.notes).toBeUndefined();
});
it('should create a penalty with all fields', () => {
const issuedAt = new Date('2023-01-01');
const appliedAt = new Date('2023-01-02');
const penalty = Penalty.create({
id: 'penalty-1',
leagueId: 'league-1',
raceId: 'race-1',
driverId: 'driver-1',
type: 'disqualification',
reason: 'Unsafe driving',
protestId: 'protest-1',
issuedBy: 'steward-1',
status: 'applied',
issuedAt,
appliedAt,
notes: 'Applied after review',
});
expect(penalty.id.toString()).toBe('penalty-1');
expect(penalty.type).toBe('disqualification');
expect(penalty.value).toBeUndefined();
expect(penalty.protestId).toBe('protest-1');
expect(penalty.status).toBe('applied');
expect(penalty.issuedAt).toEqual(issuedAt);
expect(penalty.appliedAt).toEqual(appliedAt);
expect(penalty.notes).toBe('Applied after review');
});
it('should throw error for invalid id', () => {
expect(() => Penalty.create({
id: '',
leagueId: 'league-1',
raceId: 'race-1',
driverId: 'driver-1',
type: 'time_penalty',
value: 5,
reason: 'Speeding',
issuedBy: 'steward-1',
})).toThrow(RacingDomainValidationError);
});
it('should throw error for invalid type', () => {
expect(() => Penalty.create({
id: 'penalty-1',
leagueId: 'league-1',
raceId: 'race-1',
driverId: 'driver-1',
type: 'invalid_type',
value: 5,
reason: 'Speeding',
issuedBy: 'steward-1',
})).toThrow(RacingDomainValidationError);
});
it('should throw error for missing value on time_penalty', () => {
expect(() => Penalty.create({
id: 'penalty-1',
leagueId: 'league-1',
raceId: 'race-1',
driverId: 'driver-1',
type: 'time_penalty',
reason: 'Speeding',
issuedBy: 'steward-1',
})).toThrow(RacingDomainValidationError);
});
it('should throw error for zero value', () => {
expect(() => Penalty.create({
id: 'penalty-1',
leagueId: 'league-1',
raceId: 'race-1',
driverId: 'driver-1',
type: 'time_penalty',
value: 0,
reason: 'Speeding',
issuedBy: 'steward-1',
})).toThrow(RacingDomainValidationError);
});
});
describe('isPending', () => {
it('should return true for pending status', () => {
const penalty = Penalty.create({
id: 'penalty-1',
leagueId: 'league-1',
raceId: 'race-1',
driverId: 'driver-1',
type: 'warning',
reason: 'Warning',
issuedBy: 'steward-1',
});
expect(penalty.isPending()).toBe(true);
});
it('should return false for applied status', () => {
const penalty = Penalty.create({
id: 'penalty-1',
leagueId: 'league-1',
raceId: 'race-1',
driverId: 'driver-1',
type: 'warning',
reason: 'Warning',
issuedBy: 'steward-1',
status: 'applied',
});
expect(penalty.isPending()).toBe(false);
});
});
describe('markAsApplied', () => {
it('should mark penalty as applied', () => {
const penalty = Penalty.create({
id: 'penalty-1',
leagueId: 'league-1',
raceId: 'race-1',
driverId: 'driver-1',
type: 'warning',
reason: 'Warning',
issuedBy: 'steward-1',
});
const applied = penalty.markAsApplied('Applied successfully');
expect(applied.status).toBe('applied');
expect(applied.appliedAt).toBeInstanceOf(Date);
expect(applied.notes).toBe('Applied successfully');
});
it('should throw error if already applied', () => {
const penalty = Penalty.create({
id: 'penalty-1',
leagueId: 'league-1',
raceId: 'race-1',
driverId: 'driver-1',
type: 'warning',
reason: 'Warning',
issuedBy: 'steward-1',
status: 'applied',
});
expect(() => penalty.markAsApplied()).toThrow(RacingDomainInvariantError);
});
});
describe('overturn', () => {
it('should overturn the penalty', () => {
const penalty = Penalty.create({
id: 'penalty-1',
leagueId: 'league-1',
raceId: 'race-1',
driverId: 'driver-1',
type: 'warning',
reason: 'Warning',
issuedBy: 'steward-1',
});
const overturned = penalty.overturn('Appealed successfully');
expect(overturned.status).toBe('overturned');
expect(overturned.notes).toBe('Appealed successfully');
});
it('should throw error if already overturned', () => {
const penalty = Penalty.create({
id: 'penalty-1',
leagueId: 'league-1',
raceId: 'race-1',
driverId: 'driver-1',
type: 'warning',
reason: 'Warning',
issuedBy: 'steward-1',
status: 'overturned',
});
expect(() => penalty.overturn('Reason')).toThrow(RacingDomainInvariantError);
});
});
describe('getDescription', () => {
it('should return description for time_penalty', () => {
const penalty = Penalty.create({
id: 'penalty-1',
leagueId: 'league-1',
raceId: 'race-1',
driverId: 'driver-1',
type: 'time_penalty',
value: 5,
reason: 'Speeding',
issuedBy: 'steward-1',
});
expect(penalty.getDescription()).toBe('+5s time penalty');
});
it('should return description for disqualification', () => {
const penalty = Penalty.create({
id: 'penalty-1',
leagueId: 'league-1',
raceId: 'race-1',
driverId: 'driver-1',
type: 'disqualification',
reason: 'Unsafe',
issuedBy: 'steward-1',
});
expect(penalty.getDescription()).toBe('Disqualified from race');
});
});
});