refactor
This commit is contained in:
162
core/racing/application/use-cases/GetRaceDetailUseCase.test.ts
Normal file
162
core/racing/application/use-cases/GetRaceDetailUseCase.test.ts
Normal file
@@ -0,0 +1,162 @@
|
||||
import { describe, it, expect, beforeEach, vi, Mock } from 'vitest';
|
||||
import { GetRaceDetailUseCase } 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 { DriverRatingProvider } from '../ports/DriverRatingProvider';
|
||||
import type { IImageServicePort } from '../ports/IImageServicePort';
|
||||
|
||||
describe('GetRaceDetailUseCase', () => {
|
||||
let useCase: GetRaceDetailUseCase;
|
||||
let raceRepository: { findById: Mock };
|
||||
let leagueRepository: { findById: Mock };
|
||||
let driverRepository: { findById: Mock };
|
||||
let raceRegistrationRepository: { getRegisteredDrivers: Mock };
|
||||
let resultRepository: { findByRaceId: Mock };
|
||||
let leagueMembershipRepository: { getMembership: Mock };
|
||||
let driverRatingProvider: { getRating: Mock; getRatings: Mock };
|
||||
let imageService: { getDriverAvatar: Mock; getTeamLogo: Mock; getLeagueCover: Mock; getLeagueLogo: Mock };
|
||||
|
||||
beforeEach(() => {
|
||||
raceRepository = { findById: vi.fn() };
|
||||
leagueRepository = { findById: vi.fn() };
|
||||
driverRepository = { findById: vi.fn() };
|
||||
raceRegistrationRepository = { getRegisteredDrivers: vi.fn() };
|
||||
resultRepository = { findByRaceId: vi.fn() };
|
||||
leagueMembershipRepository = { getMembership: vi.fn() };
|
||||
driverRatingProvider = { getRating: vi.fn(), getRatings: vi.fn() };
|
||||
imageService = { getDriverAvatar: vi.fn(), getTeamLogo: vi.fn(), getLeagueCover: vi.fn(), getLeagueLogo: 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,
|
||||
driverRatingProvider as DriverRatingProvider,
|
||||
imageService as IImageServicePort,
|
||||
);
|
||||
});
|
||||
|
||||
it('should return race detail when race exists', async () => {
|
||||
const raceId = 'race-1';
|
||||
const driverId = 'driver-1';
|
||||
const race = {
|
||||
id: raceId,
|
||||
leagueId: 'league-1',
|
||||
track: 'Track 1',
|
||||
car: 'Car 1',
|
||||
scheduledAt: new Date('2023-01-01T10:00:00Z'),
|
||||
sessionType: 'race' as const,
|
||||
status: 'scheduled' as const,
|
||||
strengthOfField: 1500,
|
||||
registeredCount: 10,
|
||||
maxParticipants: 20,
|
||||
};
|
||||
const league = {
|
||||
id: 'league-1',
|
||||
name: 'League 1',
|
||||
description: 'Description',
|
||||
settings: { maxDrivers: 20, qualifyingFormat: 'ladder' },
|
||||
};
|
||||
const registeredDriverIds = ['driver-1', 'driver-2'];
|
||||
const membership = { status: 'active' as const };
|
||||
const ratings = new Map([['driver-1', 1600], ['driver-2', 1400]]);
|
||||
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.getRegisteredDrivers.mockResolvedValue(registeredDriverIds);
|
||||
leagueMembershipRepository.getMembership.mockResolvedValue(membership);
|
||||
driverRatingProvider.getRatings.mockReturnValue(ratings);
|
||||
driverRepository.findById.mockImplementation((id) => Promise.resolve(drivers.find(d => d.id === id) || null));
|
||||
imageService.getDriverAvatar.mockImplementation((id) => `avatar-${id}`);
|
||||
|
||||
const result = await useCase.execute({ raceId, driverId });
|
||||
|
||||
expect(result.isOk()).toBe(true);
|
||||
const viewModel = result.unwrap();
|
||||
expect(viewModel.race).toEqual({
|
||||
id: raceId,
|
||||
leagueId: 'league-1',
|
||||
track: 'Track 1',
|
||||
car: 'Car 1',
|
||||
scheduledAt: '2023-01-01T10:00:00.000Z',
|
||||
sessionType: 'race',
|
||||
status: 'scheduled',
|
||||
strengthOfField: 1500,
|
||||
registeredCount: 10,
|
||||
maxParticipants: 20,
|
||||
});
|
||||
expect(viewModel.league).toEqual({
|
||||
id: 'league-1',
|
||||
name: 'League 1',
|
||||
description: 'Description',
|
||||
settings: { maxDrivers: 20, qualifyingFormat: 'ladder' },
|
||||
});
|
||||
expect(viewModel.entryList).toHaveLength(2);
|
||||
expect(viewModel.registration).toEqual({ isUserRegistered: true, canRegister: false });
|
||||
expect(viewModel.userResult).toBeNull();
|
||||
});
|
||||
|
||||
it('should return error when race not found', async () => {
|
||||
raceRepository.findById.mockResolvedValue(null);
|
||||
|
||||
const result = await useCase.execute({ raceId: 'race-1', driverId: 'driver-1' });
|
||||
|
||||
expect(result.isErr()).toBe(true);
|
||||
expect(result.error).toEqual({ code: 'RACE_NOT_FOUND' });
|
||||
});
|
||||
|
||||
it('should include user result when race is completed', async () => {
|
||||
const raceId = 'race-1';
|
||||
const driverId = 'driver-1';
|
||||
const race = {
|
||||
id: raceId,
|
||||
leagueId: 'league-1',
|
||||
track: 'Track 1',
|
||||
car: 'Car 1',
|
||||
scheduledAt: new Date('2023-01-01T10:00:00Z'),
|
||||
sessionType: 'race' as const,
|
||||
status: 'completed' as const,
|
||||
};
|
||||
const results = [{
|
||||
driverId: 'driver-1',
|
||||
position: 2,
|
||||
startPosition: 1,
|
||||
incidents: 0,
|
||||
fastestLap: 120,
|
||||
getPositionChange: () => -1,
|
||||
isPodium: () => true,
|
||||
isClean: () => true,
|
||||
}];
|
||||
|
||||
raceRepository.findById.mockResolvedValue(race);
|
||||
leagueRepository.findById.mockResolvedValue(null);
|
||||
raceRegistrationRepository.getRegisteredDrivers.mockResolvedValue([]);
|
||||
leagueMembershipRepository.getMembership.mockResolvedValue(null);
|
||||
driverRatingProvider.getRatings.mockReturnValue(new Map());
|
||||
resultRepository.findByRaceId.mockResolvedValue(results);
|
||||
|
||||
const result = await useCase.execute({ raceId, driverId });
|
||||
|
||||
expect(result.isOk()).toBe(true);
|
||||
const viewModel = result.unwrap();
|
||||
expect(viewModel.userResult).toEqual({
|
||||
position: 2,
|
||||
startPosition: 1,
|
||||
incidents: 0,
|
||||
fastestLap: 120,
|
||||
positionChange: -1,
|
||||
isPodium: true,
|
||||
isClean: true,
|
||||
ratingChange: 61, // based on calculateRatingChange
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user