Files
gridpilot.gg/core/racing/application/use-cases/TeamRatingIntegrationAdapter.test.ts
2026-01-16 13:48:18 +01:00

322 lines
9.3 KiB
TypeScript

import { TeamRatingIntegrationAdapter } from './TeamRatingIntegrationAdapter';
import { TeamRaceResultsProvider } from '../ports/TeamRaceResultsProvider';
import { TeamRatingEventRepository } from '@core/racing/domain/repositories/TeamRatingEventRepository';
import { TeamRatingRepository } from '@core/racing/domain/repositories/TeamRatingRepository';
import { TeamDrivingRaceFactsDto } from '@core/racing/domain/services/TeamDrivingRatingEventFactory';
import { TeamRatingEvent } from '@core/racing/domain/entities/TeamRatingEvent';
import { TeamRatingEventId } from '@core/racing/domain/value-objects/TeamRatingEventId';
import { TeamRatingDimensionKey } from '@core/racing/domain/value-objects/TeamRatingDimensionKey';
import { TeamRatingDelta } from '@core/racing/domain/value-objects/TeamRatingDelta';
// Mock repositories
class MockTeamRaceResultsProvider implements TeamRaceResultsProvider {
private results: TeamDrivingRaceFactsDto | null = null;
async getTeamRaceResults(raceId: string): Promise<TeamDrivingRaceFactsDto | null> {
return this.results;
}
setResults(results: TeamDrivingRaceFactsDto | null) {
this.results = results;
}
}
class MockTeamRatingEventRepository implements TeamRatingEventRepository {
private events: TeamRatingEvent[] = [];
async save(event: TeamRatingEvent): Promise<TeamRatingEvent> {
this.events.push(event);
return event;
}
async findByTeamId(teamId: string): Promise<TeamRatingEvent[]> {
return this.events.filter(e => e.teamId === teamId);
}
async findByIds(ids: TeamRatingEventId[]): Promise<TeamRatingEvent[]> {
return this.events.filter(e => ids.some(id => id.equals(e.id)));
}
async getAllByTeamId(teamId: string): Promise<TeamRatingEvent[]> {
return this.events.filter(e => e.teamId === teamId);
}
async findEventsPaginated(teamId: string): Promise<any> {
const events = await this.getAllByTeamId(teamId);
return {
items: events,
total: events.length,
limit: 10,
offset: 0,
hasMore: false,
};
}
clear() {
this.events = [];
}
}
class MockTeamRatingRepository implements TeamRatingRepository {
private snapshots: Map<string, any> = new Map();
async findByTeamId(teamId: string): Promise<any | null> {
return this.snapshots.get(teamId) || null;
}
async save(snapshot: any): Promise<any> {
this.snapshots.set(snapshot.teamId, snapshot);
return snapshot;
}
clear() {
this.snapshots.clear();
}
}
describe('TeamRatingIntegrationAdapter', () => {
let adapter: TeamRatingIntegrationAdapter;
let mockResultsProvider: MockTeamRaceResultsProvider;
let mockEventRepo: MockTeamRatingEventRepository;
let mockRatingRepo: MockTeamRatingRepository;
beforeEach(() => {
mockResultsProvider = new MockTeamRaceResultsProvider();
mockEventRepo = new MockTeamRatingEventRepository();
mockRatingRepo = new MockTeamRatingRepository();
adapter = new TeamRatingIntegrationAdapter(
mockResultsProvider,
mockEventRepo,
mockRatingRepo
);
});
afterEach(() => {
mockEventRepo.clear();
mockRatingRepo.clear();
});
describe('recordTeamRatings', () => {
it('should return true when no results found', async () => {
mockResultsProvider.setResults(null);
const result = await adapter.recordTeamRatings('race-123');
expect(result).toBe(true);
});
it('should return true when results are empty', async () => {
mockResultsProvider.setResults({
raceId: 'race-123',
teamId: 'team-123',
results: [],
});
const result = await adapter.recordTeamRatings('race-123');
expect(result).toBe(true);
});
it('should return true when no events generated', async () => {
mockResultsProvider.setResults({
raceId: 'race-123',
teamId: 'team-123',
results: [
{
teamId: 'team-123',
position: 1,
incidents: 0,
status: 'dns',
fieldSize: 1,
strengthOfField: 50,
},
],
});
const result = await adapter.recordTeamRatings('race-123');
expect(result).toBe(true);
});
it('should record team ratings successfully', async () => {
const raceResults: TeamDrivingRaceFactsDto = {
raceId: 'race-123',
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,
},
],
};
mockResultsProvider.setResults(raceResults);
const result = await adapter.recordTeamRatings('race-123');
expect(result).toBe(true);
// Verify events were saved
const events1 = await mockEventRepo.getAllByTeamId('team-123');
const events2 = await mockEventRepo.getAllByTeamId('team-456');
expect(events1.length).toBeGreaterThan(0);
expect(events2.length).toBeGreaterThan(0);
// Verify snapshots were updated
const snapshot1 = await mockRatingRepo.findByTeamId('team-123');
const snapshot2 = await mockRatingRepo.findByTeamId('team-456');
expect(snapshot1).toBeDefined();
expect(snapshot2).toBeDefined();
});
it('should return false on error', async () => {
const raceResults: TeamDrivingRaceFactsDto = {
raceId: 'race-123',
teamId: 'team-123',
results: [
{
teamId: 'team-123',
position: 1,
incidents: 0,
status: 'finished',
fieldSize: 1,
strengthOfField: 55,
},
],
};
mockResultsProvider.setResults(raceResults);
// Mock repository to throw error
const originalSave = mockEventRepo.save.bind(mockEventRepo);
mockEventRepo.save = async () => {
throw new Error('Repository error');
};
const result = await adapter.recordTeamRatings('race-123');
expect(result).toBe(false);
});
});
describe('recordTeamRatingsWithDetails', () => {
it('should return details for successful recording', async () => {
const raceResults: TeamDrivingRaceFactsDto = {
raceId: 'race-123',
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,
},
],
};
mockResultsProvider.setResults(raceResults);
const result = await adapter.recordTeamRatingsWithDetails('race-123');
expect(result.success).toBe(true);
expect(result.eventsCreated).toBeGreaterThan(0);
expect(result.teamsUpdated).toContain('team-123');
expect(result.teamsUpdated).toContain('team-456');
expect(result.errors).toEqual([]);
});
it('should handle partial failures', async () => {
const raceResults: TeamDrivingRaceFactsDto = {
raceId: 'race-123',
teamId: 'team-123',
results: [
{
teamId: 'team-123',
position: 1,
incidents: 0,
status: 'finished',
fieldSize: 2,
strengthOfField: 55,
},
{
teamId: 'team-456',
position: 2,
incidents: 0,
status: 'finished',
fieldSize: 2,
strengthOfField: 55,
},
],
};
mockResultsProvider.setResults(raceResults);
// Mock repository to fail for team-456
const originalSave = mockEventRepo.save.bind(mockEventRepo);
mockEventRepo.save = async (event) => {
if (event.teamId === 'team-456') {
throw new Error('Simulated failure');
}
return originalSave(event);
};
const result = await adapter.recordTeamRatingsWithDetails('race-123');
expect(result.success).toBe(false);
expect(result.teamsUpdated).toContain('team-123');
expect(result.teamsUpdated).not.toContain('team-456');
expect(result.errors.length).toBeGreaterThan(0);
expect(result.errors[0]).toContain('team-456');
});
it('should handle empty results', async () => {
mockResultsProvider.setResults({
raceId: 'race-123',
teamId: 'team-123',
results: [],
});
const result = await adapter.recordTeamRatingsWithDetails('race-123');
expect(result.success).toBe(true);
expect(result.eventsCreated).toBe(0);
expect(result.teamsUpdated).toEqual([]);
expect(result.errors).toEqual([]);
});
it('should handle null results', async () => {
mockResultsProvider.setResults(null);
const result = await adapter.recordTeamRatingsWithDetails('race-123');
expect(result.success).toBe(true);
expect(result.eventsCreated).toBe(0);
expect(result.teamsUpdated).toEqual([]);
expect(result.errors).toEqual([]);
});
});
});