155 lines
6.2 KiB
TypeScript
155 lines
6.2 KiB
TypeScript
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
|
|
import { beforeEach, describe, expect, it, vi, type Mock } from 'vitest';
|
|
import { Race } from '../../domain/entities/Race';
|
|
import type { DriverRepository } from '../../domain/repositories/DriverRepository';
|
|
import type { LeagueMembershipRepository } from '../../domain/repositories/LeagueMembershipRepository';
|
|
import type { LeagueRepository } from '../../domain/repositories/LeagueRepository';
|
|
import type { RaceRegistrationRepository } from '../../domain/repositories/RaceRegistrationRepository';
|
|
import type { RaceRepository } from '../../domain/repositories/RaceRepository';
|
|
import type { ResultRepository } from '../../domain/repositories/ResultRepository';
|
|
import {
|
|
GetRaceDetailUseCase,
|
|
type GetRaceDetailErrorCode,
|
|
type GetRaceDetailInput,
|
|
} from './GetRaceDetailUseCase';
|
|
|
|
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 RaceRepository,
|
|
leagueRepository as unknown as LeagueRepository,
|
|
driverRepository as unknown as DriverRepository,
|
|
raceRegistrationRepository as unknown as RaceRegistrationRepository,
|
|
resultRepository as unknown as ResultRepository,
|
|
leagueMembershipRepository as unknown as LeagueMembershipRepository,
|
|
);
|
|
});
|
|
|
|
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');
|
|
});
|
|
});
|