Files
gridpilot.gg/tests/integration/drivers/drivers-list-use-cases.integration.test.ts
Marc Mintel 597bb48248
Some checks failed
Contract Testing / contract-tests (pull_request) Failing after 4m51s
Contract Testing / contract-snapshot (pull_request) Has been skipped
integration tests
2026-01-22 17:29:06 +01:00

237 lines
8.4 KiB
TypeScript

/**
* Integration Test: GetDriversLeaderboardUseCase Orchestration
*
* Tests the orchestration logic of GetDriversLeaderboardUseCase:
* - GetDriversLeaderboardUseCase: Retrieves list of drivers with rankings and statistics
* - Validates that Use Cases correctly interact with their Ports (Repositories, other Use Cases)
* - Uses In-Memory adapters for fast, deterministic testing
*
* Focus: Business logic orchestration, NOT UI rendering
*/
import { describe, it, expect, beforeAll, beforeEach } from 'vitest';
import { InMemoryDriverRepository } from '../../../adapters/racing/persistence/inmemory/InMemoryDriverRepository';
import { InMemoryDriverStatsRepository } from '../../../adapters/racing/persistence/inmemory/InMemoryDriverStatsRepository';
import { GetDriversLeaderboardUseCase } from '../../../core/racing/application/use-cases/GetDriversLeaderboardUseCase';
import { RankingUseCase } from '../../../core/racing/application/use-cases/RankingUseCase';
import { DriverStatsUseCase } from '../../../core/racing/application/use-cases/DriverStatsUseCase';
import { Driver } from '../../../core/racing/domain/entities/Driver';
import { Logger } from '../../../core/shared/domain/Logger';
describe('GetDriversLeaderboardUseCase Orchestration', () => {
let driverRepository: InMemoryDriverRepository;
let driverStatsRepository: InMemoryDriverStatsRepository;
let rankingUseCase: RankingUseCase;
let driverStatsUseCase: DriverStatsUseCase;
let getDriversLeaderboardUseCase: GetDriversLeaderboardUseCase;
let mockLogger: Logger;
beforeAll(() => {
mockLogger = {
info: () => {},
debug: () => {},
warn: () => {},
error: () => {},
} as unknown as Logger;
driverRepository = new InMemoryDriverRepository(mockLogger);
driverStatsRepository = new InMemoryDriverStatsRepository(mockLogger);
// RankingUseCase and DriverStatsUseCase are dependencies of GetDriversLeaderboardUseCase
rankingUseCase = new RankingUseCase(
{} as any, // standingRepository not used in getAllDriverRankings
{} as any, // driverRepository not used in getAllDriverRankings
driverStatsRepository,
mockLogger
);
driverStatsUseCase = new DriverStatsUseCase(
{} as any, // resultRepository not used in getDriverStats
{} as any, // standingRepository not used in getDriverStats
driverStatsRepository,
mockLogger
);
getDriversLeaderboardUseCase = new GetDriversLeaderboardUseCase(
driverRepository,
rankingUseCase,
driverStatsUseCase,
mockLogger
);
});
beforeEach(() => {
driverRepository.clear();
driverStatsRepository.clear();
});
describe('GetDriversLeaderboardUseCase - Success Path', () => {
it('should retrieve complete list of drivers with all data', async () => {
// Scenario: System has multiple drivers
// Given: 3 drivers exist with various data
const drivers = [
Driver.create({ id: 'd1', iracingId: '1', name: 'Driver 1', country: 'US' }),
Driver.create({ id: 'd2', iracingId: '2', name: 'Driver 2', country: 'UK' }),
Driver.create({ id: 'd3', iracingId: '3', name: 'Driver 3', country: 'DE' }),
];
for (const d of drivers) {
await driverRepository.create(d);
}
// And: Each driver has statistics
await driverStatsRepository.saveDriverStats('d1', {
rating: 2000,
totalRaces: 10,
wins: 2,
podiums: 5,
overallRank: 1,
safetyRating: 4.5,
sportsmanshipRating: 95,
dnfs: 0,
avgFinish: 3.5,
bestFinish: 1,
worstFinish: 10,
consistency: 85,
experienceLevel: 'pro'
});
await driverStatsRepository.saveDriverStats('d2', {
rating: 1800,
totalRaces: 8,
wins: 1,
podiums: 3,
overallRank: 2,
safetyRating: 4.0,
sportsmanshipRating: 90,
dnfs: 1,
avgFinish: 5.2,
bestFinish: 1,
worstFinish: 15,
consistency: 75,
experienceLevel: 'intermediate'
});
await driverStatsRepository.saveDriverStats('d3', {
rating: 1500,
totalRaces: 5,
wins: 0,
podiums: 1,
overallRank: 3,
safetyRating: 3.5,
sportsmanshipRating: 80,
dnfs: 0,
avgFinish: 8.0,
bestFinish: 3,
worstFinish: 12,
consistency: 65,
experienceLevel: 'rookie'
});
// When: GetDriversLeaderboardUseCase.execute() is called
const result = await getDriversLeaderboardUseCase.execute({});
// Then: The result should contain all drivers
expect(result.isOk()).toBe(true);
const leaderboard = result.unwrap();
expect(leaderboard.items).toHaveLength(3);
expect(leaderboard.totalRaces).toBe(23);
expect(leaderboard.totalWins).toBe(3);
expect(leaderboard.activeCount).toBe(3);
// And: Drivers should be sorted by rating (high to low)
expect(leaderboard.items[0].driver.id).toBe('d1');
expect(leaderboard.items[1].driver.id).toBe('d2');
expect(leaderboard.items[2].driver.id).toBe('d3');
expect(leaderboard.items[0].rating).toBe(2000);
expect(leaderboard.items[1].rating).toBe(1800);
expect(leaderboard.items[2].rating).toBe(1500);
});
it('should handle empty drivers list', async () => {
// Scenario: System has no registered drivers
// Given: No drivers exist in the system
// When: GetDriversLeaderboardUseCase.execute() is called
const result = await getDriversLeaderboardUseCase.execute({});
// Then: The result should contain an empty array
expect(result.isOk()).toBe(true);
const leaderboard = result.unwrap();
expect(leaderboard.items).toHaveLength(0);
expect(leaderboard.totalRaces).toBe(0);
expect(leaderboard.totalWins).toBe(0);
expect(leaderboard.activeCount).toBe(0);
});
it('should correctly identify active drivers', async () => {
// Scenario: Some drivers have no races
// Given: 2 drivers exist, one with races, one without
await driverRepository.create(Driver.create({ id: 'active', iracingId: '1', name: 'Active', country: 'US' }));
await driverRepository.create(Driver.create({ id: 'inactive', iracingId: '2', name: 'Inactive', country: 'UK' }));
await driverStatsRepository.saveDriverStats('active', {
rating: 1500,
totalRaces: 1,
wins: 0,
podiums: 0,
overallRank: 1,
safetyRating: 3.0,
sportsmanshipRating: 70,
dnfs: 0,
avgFinish: 10,
bestFinish: 10,
worstFinish: 10,
consistency: 50,
experienceLevel: 'rookie'
});
// No stats for inactive driver or totalRaces = 0
await driverStatsRepository.saveDriverStats('inactive', {
rating: 1000,
totalRaces: 0,
wins: 0,
podiums: 0,
overallRank: null,
safetyRating: 2.5,
sportsmanshipRating: 50,
dnfs: 0,
avgFinish: 0,
bestFinish: 0,
worstFinish: 0,
consistency: 0,
experienceLevel: 'rookie'
});
// When: GetDriversLeaderboardUseCase.execute() is called
const result = await getDriversLeaderboardUseCase.execute({});
// Then: Only one driver should be active
const leaderboard = result.unwrap();
expect(leaderboard.activeCount).toBe(1);
expect(leaderboard.items.find(i => i.driver.id === 'active')?.isActive).toBe(true);
expect(leaderboard.items.find(i => i.driver.id === 'inactive')?.isActive).toBe(false);
});
});
describe('GetDriversLeaderboardUseCase - Error Handling', () => {
it('should handle repository errors gracefully', async () => {
// Scenario: Repository throws error
// Given: DriverRepository throws an error during query
const originalFindAll = driverRepository.findAll.bind(driverRepository);
driverRepository.findAll = async () => {
throw new Error('Repository error');
};
// When: GetDriversLeaderboardUseCase.execute() is called
const result = await getDriversLeaderboardUseCase.execute({});
// Then: Should return a repository error
expect(result.isErr()).toBe(true);
const error = result.unwrapErr();
expect(error.code).toBe('REPOSITORY_ERROR');
// Restore original method
driverRepository.findAll = originalFindAll;
});
});
});