import { TeamDrivingRatingEventFactory, TeamDrivingRaceFactsDto, TeamDrivingQualifyingFactsDto, TeamDrivingOvertakeFactsDto } from './TeamDrivingRatingEventFactory'; describe('TeamDrivingRatingEventFactory', () => { describe('createFromRaceFinish', () => { it('should create events from race finish data', () => { const events = TeamDrivingRatingEventFactory.createFromRaceFinish({ teamId: 'team-123', position: 1, incidents: 0, status: 'finished', fieldSize: 10, strengthOfField: 55, raceId: 'race-456', }); expect(events.length).toBeGreaterThan(0); expect(events[0].teamId).toBe('team-123'); expect(events[0].dimension.value).toBe('driving'); }); it('should create events for DNS status', () => { const events = TeamDrivingRatingEventFactory.createFromRaceFinish({ teamId: 'team-123', position: 1, incidents: 0, status: 'dns', fieldSize: 10, strengthOfField: 55, raceId: 'race-456', }); expect(events.length).toBeGreaterThan(0); const dnsEvent = events.find(e => e.reason.code === 'RACE_DNS'); expect(dnsEvent).toBeDefined(); expect(dnsEvent?.delta.value).toBeLessThan(0); }); it('should create events for DNF status', () => { const events = TeamDrivingRatingEventFactory.createFromRaceFinish({ teamId: 'team-123', position: 5, incidents: 2, status: 'dnf', fieldSize: 10, strengthOfField: 55, raceId: 'race-456', }); expect(events.length).toBeGreaterThan(0); const dnfEvent = events.find(e => e.reason.code === 'RACE_DNF'); expect(dnfEvent).toBeDefined(); expect(dnfEvent?.delta.value).toBe(-15); }); it('should create events for DSQ status', () => { const events = TeamDrivingRatingEventFactory.createFromRaceFinish({ teamId: 'team-123', position: 5, incidents: 0, status: 'dsq', fieldSize: 10, strengthOfField: 55, raceId: 'race-456', }); expect(events.length).toBeGreaterThan(0); const dsqEvent = events.find(e => e.reason.code === 'RACE_DSQ'); expect(dsqEvent).toBeDefined(); expect(dsqEvent?.delta.value).toBe(-25); }); it('should create events for AFK status', () => { const events = TeamDrivingRatingEventFactory.createFromRaceFinish({ teamId: 'team-123', position: 5, incidents: 0, status: 'afk', fieldSize: 10, strengthOfField: 55, raceId: 'race-456', }); expect(events.length).toBeGreaterThan(0); const afkEvent = events.find(e => e.reason.code === 'RACE_AFK'); expect(afkEvent).toBeDefined(); expect(afkEvent?.delta.value).toBe(-20); }); it('should apply incident penalties', () => { const events = TeamDrivingRatingEventFactory.createFromRaceFinish({ teamId: 'team-123', position: 3, incidents: 5, status: 'finished', fieldSize: 10, strengthOfField: 55, raceId: 'race-456', }); const incidentEvent = events.find(e => e.reason.code === 'RACE_INCIDENTS'); expect(incidentEvent).toBeDefined(); expect(incidentEvent?.delta.value).toBeLessThan(0); }); it('should apply gain bonus for beating higher-rated teams', () => { const events = TeamDrivingRatingEventFactory.createFromRaceFinish({ teamId: 'team-123', position: 1, incidents: 0, status: 'finished', fieldSize: 10, strengthOfField: 65, // High strength raceId: 'race-456', }); const gainEvent = events.find(e => e.reason.code === 'RACE_GAIN_BONUS'); expect(gainEvent).toBeDefined(); expect(gainEvent?.delta.value).toBeGreaterThan(0); expect(gainEvent?.weight).toBe(0.5); }); it('should create pace events when pace is provided', () => { const events = TeamDrivingRatingEventFactory.createFromRaceFinish({ teamId: 'team-123', position: 3, incidents: 0, status: 'finished', fieldSize: 10, strengthOfField: 55, raceId: 'race-456', pace: 80, }); const paceEvent = events.find(e => e.reason.code === 'RACE_PACE'); expect(paceEvent).toBeDefined(); expect(paceEvent?.delta.value).toBeGreaterThan(0); expect(paceEvent?.weight).toBe(0.3); }); it('should create consistency events when consistency is provided', () => { const events = TeamDrivingRatingEventFactory.createFromRaceFinish({ teamId: 'team-123', position: 3, incidents: 0, status: 'finished', fieldSize: 10, strengthOfField: 55, raceId: 'race-456', consistency: 85, }); const consistencyEvent = events.find(e => e.reason.code === 'RACE_CONSISTENCY'); expect(consistencyEvent).toBeDefined(); expect(consistencyEvent?.delta.value).toBeGreaterThan(0); expect(consistencyEvent?.weight).toBe(0.3); }); it('should create teamwork events when teamwork is provided', () => { const events = TeamDrivingRatingEventFactory.createFromRaceFinish({ teamId: 'team-123', position: 3, incidents: 0, status: 'finished', fieldSize: 10, strengthOfField: 55, raceId: 'race-456', teamwork: 90, }); const teamworkEvent = events.find(e => e.reason.code === 'RACE_TEAMWORK'); expect(teamworkEvent).toBeDefined(); expect(teamworkEvent?.delta.value).toBeGreaterThan(0); expect(teamworkEvent?.weight).toBe(0.4); }); it('should create sportsmanship events when sportsmanship is provided', () => { const events = TeamDrivingRatingEventFactory.createFromRaceFinish({ teamId: 'team-123', position: 3, incidents: 0, status: 'finished', fieldSize: 10, strengthOfField: 55, raceId: 'race-456', sportsmanship: 95, }); const sportsmanshipEvent = events.find(e => e.reason.code === 'RACE_SPORTSMANSHIP'); expect(sportsmanshipEvent).toBeDefined(); expect(sportsmanshipEvent?.delta.value).toBeGreaterThan(0); expect(sportsmanshipEvent?.weight).toBe(0.3); }); }); describe('createDrivingEventsFromRace', () => { it('should create events for multiple teams', () => { const raceFacts: TeamDrivingRaceFactsDto = { raceId: 'race-456', teamId: 'team-123', results: [ { teamId: 'team-123', position: 1, incidents: 0, status: 'finished', fieldSize: 3, strengthOfField: 55, }, { teamId: 'team-456', position: 2, incidents: 1, status: 'finished', fieldSize: 3, strengthOfField: 55, }, ], }; const eventsByTeam = TeamDrivingRatingEventFactory.createDrivingEventsFromRace(raceFacts); expect(eventsByTeam.size).toBe(2); expect(eventsByTeam.get('team-123')).toBeDefined(); expect(eventsByTeam.get('team-456')).toBeDefined(); }); it('should handle empty results', () => { const raceFacts: TeamDrivingRaceFactsDto = { raceId: 'race-456', teamId: 'team-123', results: [], }; const eventsByTeam = TeamDrivingRatingEventFactory.createDrivingEventsFromRace(raceFacts); expect(eventsByTeam.size).toBe(0); }); it('should skip teams with no events', () => { const raceFacts: TeamDrivingRaceFactsDto = { raceId: 'race-456', teamId: 'team-123', results: [ { teamId: 'team-123', position: 1, incidents: 0, status: 'finished', fieldSize: 1, strengthOfField: 55, }, ], }; const eventsByTeam = TeamDrivingRatingEventFactory.createDrivingEventsFromRace(raceFacts); expect(eventsByTeam.size).toBe(1); expect(eventsByTeam.get('team-123')?.length).toBeGreaterThan(0); }); it('should handle optional ratings in results', () => { const raceFacts: TeamDrivingRaceFactsDto = { raceId: 'race-456', teamId: 'team-123', results: [ { teamId: 'team-123', position: 1, incidents: 0, status: 'finished', fieldSize: 3, strengthOfField: 65, pace: 85, consistency: 80, teamwork: 90, sportsmanship: 95, }, ], }; const eventsByTeam = TeamDrivingRatingEventFactory.createDrivingEventsFromRace(raceFacts); const events = eventsByTeam.get('team-123')!; expect(events.length).toBeGreaterThan(5); expect(events.find(e => e.reason.code === 'RACE_PACE')).toBeDefined(); expect(events.find(e => e.reason.code === 'RACE_CONSISTENCY')).toBeDefined(); expect(events.find(e => e.reason.code === 'RACE_TEAMWORK')).toBeDefined(); expect(events.find(e => e.reason.code === 'RACE_SPORTSMANSHIP')).toBeDefined(); }); }); describe('createFromQualifying', () => { it('should create qualifying events', () => { const events = TeamDrivingRatingEventFactory.createFromQualifying({ teamId: 'team-123', qualifyingPosition: 3, fieldSize: 10, raceId: 'race-456', }); expect(events.length).toBeGreaterThan(0); expect(events[0].teamId).toBe('team-123'); expect(events[0].dimension.value).toBe('driving'); expect(events[0].reason.code).toBe('RACE_QUALIFYING'); expect(events[0].weight).toBe(0.25); }); }); describe('createDrivingEventsFromQualifying', () => { it('should create events for multiple teams', () => { const qualifyingFacts: TeamDrivingQualifyingFactsDto = { raceId: 'race-456', results: [ { teamId: 'team-123', qualifyingPosition: 1, fieldSize: 10, }, { teamId: 'team-456', qualifyingPosition: 5, fieldSize: 10, }, ], }; const eventsByTeam = TeamDrivingRatingEventFactory.createDrivingEventsFromQualifying(qualifyingFacts); expect(eventsByTeam.size).toBe(2); expect(eventsByTeam.get('team-123')).toBeDefined(); expect(eventsByTeam.get('team-456')).toBeDefined(); }); }); describe('createFromOvertakeStats', () => { it('should create overtake events', () => { const events = TeamDrivingRatingEventFactory.createFromOvertakeStats({ teamId: 'team-123', overtakes: 5, successfulDefenses: 3, raceId: 'race-456', }); expect(events.length).toBeGreaterThan(0); const overtakeEvent = events.find(e => e.reason.code === 'RACE_OVERTAKE'); expect(overtakeEvent).toBeDefined(); expect(overtakeEvent?.delta.value).toBeGreaterThan(0); }); it('should create defense events', () => { const events = TeamDrivingRatingEventFactory.createFromOvertakeStats({ teamId: 'team-123', overtakes: 0, successfulDefenses: 4, raceId: 'race-456', }); const defenseEvent = events.find(e => e.reason.code === 'RACE_DEFENSE'); expect(defenseEvent).toBeDefined(); expect(defenseEvent?.delta.value).toBeGreaterThan(0); }); }); describe('createDrivingEventsFromOvertakes', () => { it('should create events for multiple teams', () => { const overtakeFacts: TeamDrivingOvertakeFactsDto = { raceId: 'race-456', results: [ { teamId: 'team-123', overtakes: 3, successfulDefenses: 2, }, { teamId: 'team-456', overtakes: 1, successfulDefenses: 5, }, ], }; const eventsByTeam = TeamDrivingRatingEventFactory.createDrivingEventsFromOvertakes(overtakeFacts); expect(eventsByTeam.size).toBe(2); expect(eventsByTeam.get('team-123')).toBeDefined(); expect(eventsByTeam.get('team-456')).toBeDefined(); }); }); describe('createFromPenalty', () => { it('should create driving penalty event', () => { const events = TeamDrivingRatingEventFactory.createFromPenalty({ teamId: 'team-123', penaltyType: 'minor', severity: 'low', }); const drivingEvent = events.find(e => e.dimension.value === 'driving'); expect(drivingEvent).toBeDefined(); expect(drivingEvent?.delta.value).toBeLessThan(0); }); it('should create admin trust penalty event', () => { const events = TeamDrivingRatingEventFactory.createFromPenalty({ teamId: 'team-123', penaltyType: 'minor', severity: 'low', }); const adminEvent = events.find(e => e.dimension.value === 'adminTrust'); expect(adminEvent).toBeDefined(); expect(adminEvent?.delta.value).toBeLessThan(0); }); it('should apply severity multipliers', () => { const lowEvents = TeamDrivingRatingEventFactory.createFromPenalty({ teamId: 'team-123', penaltyType: 'major', severity: 'low', }); const highEvents = TeamDrivingRatingEventFactory.createFromPenalty({ teamId: 'team-123', penaltyType: 'major', severity: 'high', }); const lowDelta = lowEvents.find(e => e.dimension.value === 'driving')?.delta.value || 0; const highDelta = highEvents.find(e => e.dimension.value === 'driving')?.delta.value || 0; expect(highDelta).toBeLessThan(lowDelta); }); }); describe('createFromVote', () => { it('should create positive vote event', () => { const events = TeamDrivingRatingEventFactory.createFromVote({ teamId: 'team-123', outcome: 'positive', voteCount: 10, eligibleVoterCount: 15, percentPositive: 80, }); expect(events.length).toBeGreaterThan(0); expect(events[0].dimension.value).toBe('adminTrust'); expect(events[0].delta.value).toBeGreaterThan(0); }); it('should create negative vote event', () => { const events = TeamDrivingRatingEventFactory.createFromVote({ teamId: 'team-123', outcome: 'negative', voteCount: 10, eligibleVoterCount: 15, percentPositive: 20, }); expect(events.length).toBeGreaterThan(0); expect(events[0].dimension.value).toBe('adminTrust'); expect(events[0].delta.value).toBeLessThan(0); }); it('should weight by vote count', () => { const events = TeamDrivingRatingEventFactory.createFromVote({ teamId: 'team-123', outcome: 'positive', voteCount: 20, eligibleVoterCount: 20, percentPositive: 100, }); expect(events[0].weight).toBe(20); }); }); describe('createFromAdminAction', () => { it('should create admin action bonus event', () => { const events = TeamDrivingRatingEventFactory.createFromAdminAction({ teamId: 'team-123', actionType: 'bonus', }); expect(events.length).toBeGreaterThan(0); expect(events[0].dimension.value).toBe('adminTrust'); expect(events[0].delta.value).toBeGreaterThan(0); }); it('should create admin action penalty event', () => { const events = TeamDrivingRatingEventFactory.createFromAdminAction({ teamId: 'team-123', actionType: 'penalty', severity: 'high', }); expect(events.length).toBeGreaterThan(0); expect(events[0].dimension.value).toBe('adminTrust'); expect(events[0].delta.value).toBeLessThan(0); }); it('should create admin warning response event', () => { const events = TeamDrivingRatingEventFactory.createFromAdminAction({ teamId: 'team-123', actionType: 'warning', }); expect(events.length).toBeGreaterThan(0); expect(events[0].dimension.value).toBe('adminTrust'); expect(events[0].delta.value).toBeGreaterThan(0); }); }); });