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

156 lines
6.2 KiB
TypeScript

import { describe, it, expect, beforeEach, vi, type Mock } from 'vitest';
import {
GetRaceDetailUseCase,
type GetRaceDetailInput,
type GetRaceDetailResult,
type GetRaceDetailErrorCode,
} from './GetRaceDetailUseCase';
import type { IRaceRepository } from '../../domain/repositories/IRaceRepository';
import type { ILeagueRepository } from '../../domain/repositories/ILeagueRepository';
import type { IDriverRepository } from '../../domain/repositories/IDriverRepository';
import type { IRaceRegistrationRepository } from '../../domain/repositories/IRaceRegistrationRepository';
import type { IResultRepository } from '../../domain/repositories/IResultRepository';
import type { ILeagueMembershipRepository } from '../../domain/repositories/ILeagueMembershipRepository';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import { Race } from '../../domain/entities/Race';
describe('GetRaceDetailUseCase', () => {
let useCase: GetRaceDetailUseCase;
let raceRepository: { findById: Mock };
let leagueRepository: { findById: Mock };
let driverRepository: { findById: Mock };
let raceRegistrationRepository: { findByRaceId: Mock };
let resultRepository: { findByRaceId: Mock };
let leagueMembershipRepository: { getMembership: Mock };
beforeEach(() => {
raceRepository = { findById: vi.fn() };
leagueRepository = { findById: vi.fn() };
driverRepository = { findById: vi.fn() };
raceRegistrationRepository = { findByRaceId: vi.fn() };
resultRepository = { findByRaceId: vi.fn() };
leagueMembershipRepository = { getMembership: vi.fn() };
useCase = new GetRaceDetailUseCase(
raceRepository as unknown as IRaceRepository,
leagueRepository as unknown as ILeagueRepository,
driverRepository as unknown as IDriverRepository,
raceRegistrationRepository as unknown as IRaceRegistrationRepository,
resultRepository as unknown as IResultRepository,
leagueMembershipRepository as unknown as ILeagueMembershipRepository,
);
});
it('should return race detail when race exists', async () => {
const raceId = 'race-1';
const driverId = 'driver-1';
const race = Race.create({
id: raceId,
leagueId: 'league-1',
track: 'Track 1',
car: 'Car 1',
scheduledAt: new Date('2099-01-01T10:00:00Z'),
status: 'scheduled',
strengthOfField: 1500,
registeredCount: 10,
maxParticipants: 20,
});
const league = {
id: 'league-1',
name: 'League 1',
description: 'Description',
settings: { maxDrivers: 20, qualifyingFormat: 'ladder' },
};
const registrations = [
{ driverId: { toString: () => 'driver-1' } },
{ driverId: { toString: () => 'driver-2' } },
];
const membership = { status: { toString: () => 'active' } };
const drivers = [
{ id: 'driver-1', name: 'Driver 1', country: 'US' },
{ id: 'driver-2', name: 'Driver 2', country: 'UK' },
];
raceRepository.findById.mockResolvedValue(race);
leagueRepository.findById.mockResolvedValue(league);
raceRegistrationRepository.findByRaceId.mockResolvedValue(registrations);
leagueMembershipRepository.getMembership.mockResolvedValue(membership);
driverRepository.findById.mockImplementation((id: string) =>
Promise.resolve(drivers.find(d => d.id === id) || null),
);
resultRepository.findByRaceId.mockResolvedValue([]);
const input: GetRaceDetailInput = { raceId, driverId };
const result = await useCase.execute(input);
expect(result.isOk()).toBe(true);
const presented = result.unwrap();
expect(presented.race).toEqual(race);
expect(presented.league).toEqual(league);
expect(presented.registrations).toEqual(registrations);
expect(presented.drivers).toHaveLength(2);
expect(presented.isUserRegistered).toBe(true);
expect(presented.canRegister).toBe(true);
expect(presented.userResult).toBeNull();
});
it('should return error when race not found', async () => {
raceRepository.findById.mockResolvedValue(null);
const input: GetRaceDetailInput = { raceId: 'race-1', driverId: 'driver-1' };
const result = await useCase.execute(input);
expect(result.isErr()).toBe(true);
const err = result.unwrapErr() as ApplicationErrorCode<GetRaceDetailErrorCode, { message: string }>;
expect(err.code).toBe('RACE_NOT_FOUND');
expect(err.details?.message).toBe('Race not found');
});
it('should include user result when race is completed', async () => {
const raceId = 'race-1';
const driverId = 'driver-1';
const race = Race.create({
id: raceId,
leagueId: 'league-1',
track: 'Track 1',
car: 'Car 1',
scheduledAt: new Date('2023-01-01T10:00:00Z'),
status: 'completed',
});
const registrations: Array<{ driverId: { toString: () => string } }> = [];
const userDomainResult = {
driverId: { toString: () => driverId },
} as unknown as { driverId: { toString: () => string } };
raceRepository.findById.mockResolvedValue(race);
leagueRepository.findById.mockResolvedValue(null);
raceRegistrationRepository.findByRaceId.mockResolvedValue(registrations);
leagueMembershipRepository.getMembership.mockResolvedValue(null);
driverRepository.findById.mockResolvedValue(null);
resultRepository.findByRaceId.mockResolvedValue([userDomainResult]);
const input: GetRaceDetailInput = { raceId, driverId };
const result = await useCase.execute(input);
expect(result.isOk()).toBe(true);
const presented = result.unwrap();
expect(presented.userResult).toBe(userDomainResult);
expect(presented.race).toEqual(race);
expect(presented.league).toBeNull();
expect(presented.registrations).toEqual(registrations);
});
it('should wrap repository errors', async () => {
const error = new Error('db down');
raceRepository.findById.mockRejectedValue(error);
const input: GetRaceDetailInput = { raceId: 'race-1', driverId: 'driver-1' };
const result = await useCase.execute(input);
expect(result.isErr()).toBe(true);
const err = result.unwrapErr() as ApplicationErrorCode<GetRaceDetailErrorCode, { message: string }>;
expect(err.code).toBe('REPOSITORY_ERROR');
expect(err.details.message).toBe('db down');
});
});