Files
gridpilot.gg/core/racing/domain/services/TeamDrivingRatingEventFactory.test.ts
2025-12-30 12:25:45 +01:00

512 lines
16 KiB
TypeScript

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);
});
});
});