import { Race } from './Race'; import { SessionType } from '../value-objects/SessionType'; import { RacingDomainValidationError, RacingDomainInvariantError } from '../errors/RacingDomainError'; describe('Race', () => { describe('create', () => { it('should create a race with required fields', () => { const scheduledAt = new Date('2023-01-01T10:00:00Z'); const race = Race.create({ id: 'race-1', leagueId: 'league-1', scheduledAt, track: 'Monza', car: 'Ferrari SF21', }); expect(race.id).toBe('race-1'); expect(race.leagueId).toBe('league-1'); expect(race.scheduledAt).toEqual(scheduledAt); expect(race.track).toBe('Monza'); expect(race.car).toBe('Ferrari SF21'); expect(race.sessionType).toEqual(SessionType.main()); expect(race.status.toString()).toBe('scheduled'); expect(race.trackId).toBeUndefined(); expect(race.carId).toBeUndefined(); expect(race.strengthOfField).toBeUndefined(); expect(race.registeredCount).toBeUndefined(); expect(race.maxParticipants).toBeUndefined(); }); it('should create a race with all fields', () => { const scheduledAt = new Date('2023-01-01T10:00:00Z'); const race = Race.create({ id: 'race-1', leagueId: 'league-1', scheduledAt, track: 'Monza', trackId: 'track-1', car: 'Ferrari SF21', carId: 'car-1', sessionType: SessionType.qualifying(), status: 'running', strengthOfField: 1500, registeredCount: 20, maxParticipants: 24, }); expect(race.id).toBe('race-1'); expect(race.leagueId).toBe('league-1'); expect(race.scheduledAt).toEqual(scheduledAt); expect(race.track).toBe('Monza'); expect(race.trackId).toBe('track-1'); expect(race.car).toBe('Ferrari SF21'); expect(race.carId).toBe('car-1'); expect(race.sessionType).toEqual(SessionType.qualifying()); expect(race.status.toString()).toBe('running'); expect(race.strengthOfField?.toNumber()).toBe(1500); expect(race.registeredCount?.toNumber()).toBe(20); expect(race.maxParticipants?.toNumber()).toBe(24); }); it('should throw error for invalid id', () => { const scheduledAt = new Date(); expect(() => Race.create({ id: '', leagueId: 'league-1', scheduledAt, track: 'Monza', car: 'Ferrari SF21', })).toThrow(RacingDomainValidationError); }); it('should throw error for invalid leagueId', () => { const scheduledAt = new Date(); expect(() => Race.create({ id: 'race-1', leagueId: '', scheduledAt, track: 'Monza', car: 'Ferrari SF21', })).toThrow(RacingDomainValidationError); }); it('should throw error for invalid scheduledAt', () => { expect(() => Race.create({ id: 'race-1', leagueId: 'league-1', scheduledAt: 'invalid' as unknown as Date, track: 'Monza', car: 'Ferrari SF21', })).toThrow(RacingDomainValidationError); }); it('should throw error for invalid track', () => { const scheduledAt = new Date(); expect(() => Race.create({ id: 'race-1', leagueId: 'league-1', scheduledAt, track: '', car: 'Ferrari SF21', })).toThrow(RacingDomainValidationError); }); it('should throw error for invalid car', () => { const scheduledAt = new Date(); expect(() => Race.create({ id: 'race-1', leagueId: 'league-1', scheduledAt, track: 'Monza', car: '', })).toThrow(RacingDomainValidationError); }); }); describe('start', () => { it('should start a scheduled race', () => { const scheduledAt = new Date(Date.now() + 3600000); // future const race = Race.create({ id: 'race-1', leagueId: 'league-1', scheduledAt, track: 'Monza', car: 'Ferrari SF21', status: 'scheduled', }); const started = race.start(); expect(started.status.toString()).toBe('running'); }); it('should throw error if not scheduled', () => { const scheduledAt = new Date(); const race = Race.create({ id: 'race-1', leagueId: 'league-1', scheduledAt, track: 'Monza', car: 'Ferrari SF21', status: 'running', }); expect(() => race.start()).toThrow(RacingDomainInvariantError); }); }); describe('complete', () => { it('should complete a running race', () => { const scheduledAt = new Date(); const race = Race.create({ id: 'race-1', leagueId: 'league-1', scheduledAt, track: 'Monza', car: 'Ferrari SF21', status: 'running', }); const completed = race.complete(); expect(completed.status.toString()).toBe('completed'); }); it('should throw error if already completed', () => { const scheduledAt = new Date(); const race = Race.create({ id: 'race-1', leagueId: 'league-1', scheduledAt, track: 'Monza', car: 'Ferrari SF21', status: 'completed', }); expect(() => race.complete()).toThrow(RacingDomainInvariantError); }); it('should throw error if cancelled', () => { const scheduledAt = new Date(); const race = Race.create({ id: 'race-1', leagueId: 'league-1', scheduledAt, track: 'Monza', car: 'Ferrari SF21', status: 'cancelled', }); expect(() => race.complete()).toThrow(RacingDomainInvariantError); }); }); describe('cancel', () => { it('should cancel a scheduled race', () => { const scheduledAt = new Date(Date.now() + 3600000); const race = Race.create({ id: 'race-1', leagueId: 'league-1', scheduledAt, track: 'Monza', car: 'Ferrari SF21', status: 'scheduled', }); const cancelled = race.cancel(); expect(cancelled.status.toString()).toBe('cancelled'); }); it('should throw error if completed', () => { const scheduledAt = new Date(); const race = Race.create({ id: 'race-1', leagueId: 'league-1', scheduledAt, track: 'Monza', car: 'Ferrari SF21', status: 'completed', }); expect(() => race.cancel()).toThrow(RacingDomainInvariantError); }); it('should throw error if already cancelled', () => { const scheduledAt = new Date(); const race = Race.create({ id: 'race-1', leagueId: 'league-1', scheduledAt, track: 'Monza', car: 'Ferrari SF21', status: 'cancelled', }); expect(() => race.cancel()).toThrow(RacingDomainInvariantError); }); }); describe('updateField', () => { it('should update strengthOfField and registeredCount', () => { const scheduledAt = new Date(); const race = Race.create({ id: 'race-1', leagueId: 'league-1', scheduledAt, track: 'Monza', car: 'Ferrari SF21', }); const updated = race.updateField(1600, 22); expect(updated.strengthOfField?.toNumber()).toBe(1600); expect(updated.registeredCount?.toNumber()).toBe(22); }); }); describe('isPast', () => { it('should return true for past race', () => { const scheduledAt = new Date(Date.now() - 3600000); // past const race = Race.create({ id: 'race-1', leagueId: 'league-1', scheduledAt, track: 'Monza', car: 'Ferrari SF21', }); expect(race.isPast()).toBe(true); }); it('should return false for future race', () => { const scheduledAt = new Date(Date.now() + 3600000); // future const race = Race.create({ id: 'race-1', leagueId: 'league-1', scheduledAt, track: 'Monza', car: 'Ferrari SF21', }); expect(race.isPast()).toBe(false); }); }); describe('isUpcoming', () => { it('should return true for scheduled future race', () => { const scheduledAt = new Date(Date.now() + 3600000); // future const race = Race.create({ id: 'race-1', leagueId: 'league-1', scheduledAt, track: 'Monza', car: 'Ferrari SF21', status: 'scheduled', }); expect(race.isUpcoming()).toBe(true); }); it('should return false for past scheduled race', () => { const scheduledAt = new Date(Date.now() - 3600000); // past const race = Race.create({ id: 'race-1', leagueId: 'league-1', scheduledAt, track: 'Monza', car: 'Ferrari SF21', status: 'scheduled', }); expect(race.isUpcoming()).toBe(false); }); it('should return false for running race', () => { const scheduledAt = new Date(Date.now() + 3600000); const race = Race.create({ id: 'race-1', leagueId: 'league-1', scheduledAt, track: 'Monza', car: 'Ferrari SF21', status: 'running', }); expect(race.isUpcoming()).toBe(false); }); }); describe('isLive', () => { it('should return true for running race', () => { const scheduledAt = new Date(); const race = Race.create({ id: 'race-1', leagueId: 'league-1', scheduledAt, track: 'Monza', car: 'Ferrari SF21', status: 'running', }); expect(race.isLive()).toBe(true); }); it('should return false for scheduled race', () => { const scheduledAt = new Date(); const race = Race.create({ id: 'race-1', leagueId: 'league-1', scheduledAt, track: 'Monza', car: 'Ferrari SF21', status: 'scheduled', }); expect(race.isLive()).toBe(false); }); }); });