Files
gridpilot.gg/core/racing/application/use-cases/ImportRaceResultsUseCase.test.ts
2026-01-08 15:34:51 +01:00

227 lines
6.9 KiB
TypeScript

import { describe, it, expect, beforeEach, vi, Mock } from 'vitest';
import {
ImportRaceResultsUseCase,
type ImportRaceResultsInput,
type ImportRaceResultsResult,
type ImportRaceResultsErrorCode,
} from './ImportRaceResultsUseCase';
import { IRaceRepository } from '../../domain/repositories/IRaceRepository';
import { ILeagueRepository } from '../../domain/repositories/ILeagueRepository';
import { IResultRepository } from '../../domain/repositories/IResultRepository';
import { IDriverRepository } from '../../domain/repositories/IDriverRepository';
import { IStandingRepository } from '../../domain/repositories/IStandingRepository';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import type { Logger } from '@core/shared/application';
describe('ImportRaceResultsUseCase', () => {
let useCase: ImportRaceResultsUseCase;
let raceRepository: {
findById: Mock;
};
let leagueRepository: {
findById: Mock;
};
let resultRepository: {
existsByRaceId: Mock;
createMany: Mock;
};
let driverRepository: {
findByIRacingId: Mock;
};
let standingRepository: {
recalculate: Mock;
};
let logger: {
debug: Mock;
info: Mock;
warn: Mock;
error: Mock;
};
beforeEach(() => {
raceRepository = {
findById: vi.fn(),
};
leagueRepository = {
findById: vi.fn(),
};
resultRepository = {
existsByRaceId: vi.fn(),
createMany: vi.fn(),
};
driverRepository = {
findByIRacingId: vi.fn(),
};
standingRepository = {
recalculate: vi.fn(),
};
logger = {
debug: vi.fn(),
info: vi.fn(),
warn: vi.fn(),
error: vi.fn(),
};
useCase = new ImportRaceResultsUseCase(raceRepository as unknown as IRaceRepository,
leagueRepository as unknown as ILeagueRepository,
resultRepository as unknown as IResultRepository,
driverRepository as unknown as IDriverRepository,
standingRepository as unknown as IStandingRepository,
logger as unknown as Logger);
});
it('should return race not found error', async () => {
const input: ImportRaceResultsInput = { raceId: 'race-1', rows: [] };
raceRepository.findById.mockResolvedValue(null);
const result = await useCase.execute(input);
expect(result.isErr()).toBe(true);
const error = result.unwrapErr() as ApplicationErrorCode<
ImportRaceResultsErrorCode,
{ message: string }
>;
expect(error).toEqual({
code: 'RACE_NOT_FOUND',
details: { message: 'Race race-1 not found' },
});
});
it('should return league not found error', async () => {
const input: ImportRaceResultsInput = { raceId: 'race-1', rows: [] };
raceRepository.findById.mockResolvedValue({ id: 'race-1', leagueId: 'league-1' });
leagueRepository.findById.mockResolvedValue(null);
const result = await useCase.execute(input);
expect(result.isErr()).toBe(true);
const error = result.unwrapErr() as ApplicationErrorCode<
ImportRaceResultsErrorCode,
{ message: string }
>;
expect(error).toEqual({
code: 'LEAGUE_NOT_FOUND',
details: { message: 'League league-1 not found' },
});
});
it('should return results exist error', async () => {
const input: ImportRaceResultsInput = { raceId: 'race-1', rows: [] };
raceRepository.findById.mockResolvedValue({ id: 'race-1', leagueId: 'league-1' });
leagueRepository.findById.mockResolvedValue({ id: 'league-1' });
resultRepository.existsByRaceId.mockResolvedValue(true);
const result = await useCase.execute(input);
expect(result.isErr()).toBe(true);
const error = result.unwrapErr() as ApplicationErrorCode<
ImportRaceResultsErrorCode,
{ message: string }
>;
expect(error).toEqual({
code: 'RESULTS_EXIST',
details: { message: 'Results already exist for this race' },
});
});
it('should return driver not found error', async () => {
const input: ImportRaceResultsInput = {
raceId: 'race-1',
rows: [
{
id: 'result-1',
driverExternalId: '123',
position: 1,
fastestLap: 100,
incidents: 0,
startPosition: 1,
},
],
};
raceRepository.findById.mockResolvedValue({ id: 'race-1', leagueId: 'league-1' });
leagueRepository.findById.mockResolvedValue({ id: 'league-1' });
resultRepository.existsByRaceId.mockResolvedValue(false);
driverRepository.findByIRacingId.mockResolvedValue(null);
const result = await useCase.execute(input);
expect(result.isErr()).toBe(true);
const error = result.unwrapErr() as ApplicationErrorCode<
ImportRaceResultsErrorCode,
{ message: string }
>;
expect(error).toEqual({
code: 'DRIVER_NOT_FOUND',
details: { message: 'Driver with iRacing ID 123 not found' },
});
});
it('should import results successfully', async () => {
const input: ImportRaceResultsInput = {
raceId: 'race-1',
rows: [
{
id: 'result-1',
driverExternalId: '123',
position: 1,
fastestLap: 100,
incidents: 0,
startPosition: 1,
},
],
};
raceRepository.findById.mockResolvedValue({ id: 'race-1', leagueId: 'league-1' });
leagueRepository.findById.mockResolvedValue({ id: 'league-1' });
resultRepository.existsByRaceId.mockResolvedValue(false);
driverRepository.findByIRacingId.mockResolvedValue({ id: 'driver-1' });
resultRepository.createMany.mockResolvedValue(undefined);
standingRepository.recalculate.mockResolvedValue(undefined);
const result = await useCase.execute(input);
expect(result.isOk()).toBe(true);
const value = result.unwrap();
expect(value).toEqual({
raceId: 'race-1',
leagueId: 'league-1',
driversProcessed: 1,
resultsRecorded: 1,
errors: [],
});
});
it('should return repository error when persistence fails', async () => {
const input: ImportRaceResultsInput = {
raceId: 'race-1',
rows: [
{
id: 'result-1',
driverExternalId: '123',
position: 1,
fastestLap: 100,
incidents: 0,
startPosition: 1,
},
],
};
raceRepository.findById.mockResolvedValue({ id: 'race-1', leagueId: 'league-1' });
leagueRepository.findById.mockResolvedValue({ id: 'league-1' });
resultRepository.existsByRaceId.mockResolvedValue(false);
driverRepository.findByIRacingId.mockResolvedValue({ id: 'driver-1' });
resultRepository.createMany.mockRejectedValue(new Error('DB failure'));
const result = await useCase.execute(input);
expect(result.isErr()).toBe(true);
const error = result.unwrapErr() as ApplicationErrorCode<
ImportRaceResultsErrorCode,
{ message: string }
>;
expect(error.code).toBe('REPOSITORY_ERROR');
expect(error.details.message).toBe('DB failure');
});
});