Files
gridpilot.gg/core/identity/domain/services/RatingEventFactory.test.ts
2026-01-16 19:46:49 +01:00

489 lines
14 KiB
TypeScript

import { RaceFactsDto, RatingEventFactory } from './RatingEventFactory';
describe('RatingEventFactory', () => {
describe('createFromRaceFinish', () => {
it('should create events from race finish data', () => {
const events = RatingEventFactory.createFromRaceFinish({
userId: 'user-123',
raceId: 'race-456',
position: 3,
totalDrivers: 10,
startPosition: 5,
incidents: 1,
fieldStrength: 2500,
status: 'finished',
});
expect(events.length).toBeGreaterThan(0);
const event = events[0];
expect(event).toBeDefined();
if (event) {
expect(event.userId).toBe('user-123');
expect(event.source.type).toBe('race');
expect(event.source.id).toBe('race-456');
}
});
it('should create events for DNS status', () => {
const events = RatingEventFactory.createFromRaceFinish({
userId: 'user-123',
raceId: 'race-456',
position: 10,
totalDrivers: 10,
startPosition: 5,
incidents: 0,
fieldStrength: 2500,
status: 'dns',
});
expect(events.length).toBeGreaterThan(0);
const dnsEvent = events.find(e => e.reason.code.includes('DNS'));
expect(dnsEvent).toBeDefined();
});
it('should create events for DNF status', () => {
const events = RatingEventFactory.createFromRaceFinish({
userId: 'user-123',
raceId: 'race-456',
position: 10,
totalDrivers: 10,
startPosition: 5,
incidents: 2,
fieldStrength: 2500,
status: 'dnf',
});
expect(events.length).toBeGreaterThan(0);
const dnfEvent = events.find(e => e.reason.code.includes('DNF'));
expect(dnfEvent).toBeDefined();
});
it('should create events for DSQ status', () => {
const events = RatingEventFactory.createFromRaceFinish({
userId: 'user-123',
raceId: 'race-456',
position: 10,
totalDrivers: 10,
startPosition: 5,
incidents: 5,
fieldStrength: 2500,
status: 'dsq',
});
expect(events.length).toBeGreaterThan(0);
const dsqEvent = events.find(e => e.reason.code.includes('DSQ'));
expect(dsqEvent).toBeDefined();
});
it('should create events for AFK status', () => {
const events = RatingEventFactory.createFromRaceFinish({
userId: 'user-123',
raceId: 'race-456',
position: 10,
totalDrivers: 10,
startPosition: 5,
incidents: 0,
fieldStrength: 2500,
status: 'afk',
});
expect(events.length).toBeGreaterThan(0);
const afkEvent = events.find(e => e.reason.code.includes('AFK'));
expect(afkEvent).toBeDefined();
});
});
describe('createDrivingEventsFromRace', () => {
it('should create events for single driver with good performance', () => {
const raceFacts: RaceFactsDto = {
raceId: 'race-123',
results: [
{
userId: 'user-123',
startPos: 5,
finishPos: 2,
incidents: 0,
status: 'finished',
sof: 2500,
},
],
};
const eventsByUser = RatingEventFactory.createDrivingEventsFromRace(raceFacts);
expect(eventsByUser.has('user-123')).toBe(true);
const events = eventsByUser.get('user-123')!;
expect(events.length).toBeGreaterThan(0);
const performanceEvent = events.find(e => e.reason.code === 'DRIVING_FINISH_STRENGTH_GAIN');
expect(performanceEvent).toBeDefined();
expect(performanceEvent?.delta.value).toBeGreaterThan(0);
});
it('should create events for multiple drivers', () => {
const raceFacts: RaceFactsDto = {
raceId: 'race-123',
results: [
{
userId: 'user-123',
startPos: 5,
finishPos: 2,
incidents: 0,
status: 'finished',
sof: 2500,
},
{
userId: 'user-456',
startPos: 3,
finishPos: 8,
incidents: 2,
status: 'finished',
sof: 2500,
},
{
userId: 'user-789',
startPos: 5,
finishPos: 5,
incidents: 0,
status: 'dns',
sof: 2500,
},
],
};
const eventsByUser = RatingEventFactory.createDrivingEventsFromRace(raceFacts);
expect(eventsByUser.has('user-123')).toBe(true);
expect(eventsByUser.has('user-456')).toBe(true);
expect(eventsByUser.has('user-789')).toBe(true);
// user-123 should have performance events
const user123Events = eventsByUser.get('user-123')!;
expect(user123Events.some(e => e.reason.code === 'DRIVING_FINISH_STRENGTH_GAIN')).toBe(true);
// user-456 should have incident penalty
const user456Events = eventsByUser.get('user-456')!;
expect(user456Events.some(e => e.reason.code === 'DRIVING_INCIDENTS_PENALTY')).toBe(true);
// user-789 should have DNS penalty
const user789Events = eventsByUser.get('user-789')!;
expect(user789Events.some(e => e.reason.code === 'DRIVING_DNS_PENALTY')).toBe(true);
});
it('should create positions gained bonus', () => {
const raceFacts: RaceFactsDto = {
raceId: 'race-123',
results: [
{
userId: 'user-123',
startPos: 10,
finishPos: 3,
incidents: 0,
status: 'finished',
sof: 2500,
},
],
};
const eventsByUser = RatingEventFactory.createDrivingEventsFromRace(raceFacts);
const events = eventsByUser.get('user-123')!;
const gainEvent = events.find(e => e.reason.code === 'DRIVING_POSITIONS_GAINED_BONUS');
expect(gainEvent).toBeDefined();
expect(gainEvent?.delta.value).toBeGreaterThan(0);
});
it('should handle DNF status', () => {
const raceFacts: RaceFactsDto = {
raceId: 'race-123',
results: [
{
userId: 'user-123',
startPos: 5,
finishPos: 10,
incidents: 0,
status: 'dnf',
sof: 2500,
},
],
};
const eventsByUser = RatingEventFactory.createDrivingEventsFromRace(raceFacts);
const events = eventsByUser.get('user-123')!;
const dnfEvent = events.find(e => e.reason.code === 'DRIVING_DNF_PENALTY');
expect(dnfEvent).toBeDefined();
expect(dnfEvent?.delta.value).toBe(-10);
});
it('should handle DSQ status', () => {
const raceFacts: RaceFactsDto = {
raceId: 'race-123',
results: [
{
userId: 'user-123',
startPos: 5,
finishPos: 10,
incidents: 0,
status: 'dsq',
sof: 2500,
},
],
};
const eventsByUser = RatingEventFactory.createDrivingEventsFromRace(raceFacts);
const events = eventsByUser.get('user-123')!;
const dsqEvent = events.find(e => e.reason.code === 'DRIVING_DSQ_PENALTY');
expect(dsqEvent).toBeDefined();
expect(dsqEvent?.delta.value).toBe(-25);
});
it('should handle AFK status', () => {
const raceFacts: RaceFactsDto = {
raceId: 'race-123',
results: [
{
userId: 'user-123',
startPos: 5,
finishPos: 10,
incidents: 0,
status: 'afk',
sof: 2500,
},
],
};
const eventsByUser = RatingEventFactory.createDrivingEventsFromRace(raceFacts);
const events = eventsByUser.get('user-123')!;
const afkEvent = events.find(e => e.reason.code === 'DRIVING_AFK_PENALTY');
expect(afkEvent).toBeDefined();
expect(afkEvent?.delta.value).toBe(-20);
});
it('should handle incident penalties', () => {
const raceFacts: RaceFactsDto = {
raceId: 'race-123',
results: [
{
userId: 'user-123',
startPos: 5,
finishPos: 5,
incidents: 3,
status: 'finished',
sof: 2500,
},
],
};
const eventsByUser = RatingEventFactory.createDrivingEventsFromRace(raceFacts);
const events = eventsByUser.get('user-123')!;
const incidentEvent = events.find(e => e.reason.code === 'DRIVING_INCIDENTS_PENALTY');
expect(incidentEvent).toBeDefined();
expect(incidentEvent?.delta.value).toBeLessThan(0);
});
it('should calculate SoF if not provided', () => {
const raceFacts: RaceFactsDto = {
raceId: 'race-123',
results: [
{
userId: 'user-123',
startPos: 5,
finishPos: 2,
incidents: 0,
status: 'finished',
// No sof
},
{
userId: 'user-456',
startPos: 3,
finishPos: 8,
incidents: 0,
status: 'finished',
// No sof
},
],
};
const eventsByUser = RatingEventFactory.createDrivingEventsFromRace(raceFacts);
// Should still work without errors
expect(eventsByUser.size).toBe(2);
expect(eventsByUser.get('user-123')!.length).toBeGreaterThan(0);
});
it('should handle empty results', () => {
const raceFacts: RaceFactsDto = {
raceId: 'race-123',
results: [],
};
const eventsByUser = RatingEventFactory.createDrivingEventsFromRace(raceFacts);
expect(eventsByUser.size).toBe(0);
});
it('should handle mixed statuses', () => {
const raceFacts: RaceFactsDto = {
raceId: 'race-123',
results: [
{
userId: 'user-123',
startPos: 5,
finishPos: 2,
incidents: 1,
status: 'finished',
sof: 2500,
},
{
userId: 'user-456',
startPos: 3,
finishPos: 10,
incidents: 0,
status: 'dnf',
sof: 2500,
},
{
userId: 'user-789',
startPos: 5,
finishPos: 5,
incidents: 0,
status: 'dns',
sof: 2500,
},
],
};
const eventsByUser = RatingEventFactory.createDrivingEventsFromRace(raceFacts);
expect(eventsByUser.size).toBe(3);
// user-123: performance + incidents
const user123Events = eventsByUser.get('user-123')!;
expect(user123Events.length).toBeGreaterThanOrEqual(2);
// user-456: DNF
const user456Events = eventsByUser.get('user-456')!;
expect(user456Events.some(e => e.reason.code === 'DRIVING_DNF_PENALTY')).toBe(true);
// user-789: DNS
const user789Events = eventsByUser.get('user-789')!;
expect(user789Events.some(e => e.reason.code === 'DRIVING_DNS_PENALTY')).toBe(true);
});
});
describe('createFromPenalty', () => {
it('should create driving penalty event', () => {
const events = RatingEventFactory.createFromPenalty({
userId: 'user-123',
penaltyId: 'penalty-789',
penaltyType: 'incident',
severity: 'major',
reason: 'Caused collision',
});
expect(events.length).toBeGreaterThan(0);
const event = events[0];
expect(event).toBeDefined();
if (event) {
expect(event.dimension.value).toBe('driving');
expect(event.source.type).toBe('penalty');
expect(event.source.id).toBe('penalty-789');
}
});
it('should create admin trust penalty event', () => {
const events = RatingEventFactory.createFromPenalty({
userId: 'user-123',
penaltyId: 'penalty-789',
penaltyType: 'admin_violation',
severity: 'major',
reason: 'Abuse of power',
});
expect(events.length).toBeGreaterThan(0);
const event = events[0];
expect(event).toBeDefined();
if (event) {
expect(event.dimension.value).toBe('adminTrust');
}
});
});
describe('createFromVote', () => {
it('should create positive vote event', () => {
const events = RatingEventFactory.createFromVote({
userId: 'user-123',
voteSessionId: 'vote-101',
outcome: 'positive',
voteCount: 8,
eligibleVoterCount: 10,
percentPositive: 80,
});
expect(events.length).toBeGreaterThan(0);
const event = events[0];
expect(event).toBeDefined();
if (event) {
expect(event.dimension.value).toBe('adminTrust');
expect(event.delta.value).toBeGreaterThan(0);
}
});
it('should create negative vote event', () => {
const events = RatingEventFactory.createFromVote({
userId: 'user-123',
voteSessionId: 'vote-101',
outcome: 'negative',
voteCount: 2,
eligibleVoterCount: 10,
percentPositive: 20,
});
expect(events.length).toBeGreaterThan(0);
const event = events[0];
expect(event).toBeDefined();
if (event) {
expect(event.delta.value).toBeLessThan(0);
}
});
});
describe('createFromAdminAction', () => {
it('should create admin action bonus event', () => {
const events = RatingEventFactory.createFromAdminAction({
userId: 'user-123',
adminActionId: 'admin-202',
actionType: 'sla_response',
details: { responseTime: 30 },
});
expect(events.length).toBeGreaterThan(0);
const event = events[0];
expect(event).toBeDefined();
if (event) {
expect(event.dimension.value).toBe('adminTrust');
expect(event.delta.value).toBeGreaterThan(0);
}
});
it('should create admin action penalty event', () => {
const events = RatingEventFactory.createFromAdminAction({
userId: 'user-123',
adminActionId: 'admin-202',
actionType: 'abuse_report',
details: { validated: true },
});
expect(events.length).toBeGreaterThan(0);
const event = events[0];
expect(event).toBeDefined();
if (event) {
expect(event.dimension.value).toBe('adminTrust');
expect(event.delta.value).toBeLessThan(0);
}
});
});
});