This commit is contained in:
2025-12-12 21:39:48 +01:00
parent ddbd99b747
commit cae81b1088
49 changed files with 777 additions and 269 deletions

View File

@@ -6,7 +6,6 @@ import type { IDriverRepository } from '@gridpilot/racing/domain/repositories/ID
import type { IRaceRegistrationRepository } from '@gridpilot/racing/domain/repositories/IRaceRegistrationRepository';
import type { IResultRepository } from '@gridpilot/racing/domain/repositories/IResultRepository';
import type { ILeagueMembershipRepository } from '@gridpilot/racing/domain/repositories/ILeagueMembershipRepository';
import type { LeagueMembership } from '@gridpilot/racing/domain/entities/LeagueMembership';
import type { DriverRatingProvider } from '@gridpilot/racing/application/ports/DriverRatingProvider';
import type { IImageServicePort } from '@gridpilot/racing/application/ports/IImageServicePort';
import type {
@@ -17,6 +16,8 @@ import type {
import { Race } from '@gridpilot/racing/domain/entities/Race';
import { League } from '@gridpilot/racing/domain/entities/League';
import { Result } from '@gridpilot/racing/domain/entities/Result';
import { Driver } from '@gridpilot/racing/domain/entities/Driver';
import { LeagueMembership } from '@gridpilot/racing/domain/entities/LeagueMembership';
import { GetRaceDetailUseCase } from '@gridpilot/racing/application/use-cases/GetRaceDetailUseCase';
import { CancelRaceUseCase } from '@gridpilot/racing/application/use-cases/CancelRaceUseCase';
@@ -118,31 +119,39 @@ class InMemoryLeagueRepository implements ILeagueRepository {
async exists(id: string): Promise<boolean> {
return this.leagues.has(id);
}
async searchByName(): Promise<League[]> {
return [];
}
}
class InMemoryDriverRepository implements IDriverRepository {
private drivers = new Map<string, { id: string; name: string; country: string }>();
private drivers = new Map<string, Driver>();
constructor(drivers: Array<{ id: string; name: string; country: string }>) {
for (const driver of drivers) {
this.drivers.set(driver.id, {
...driver,
});
this.drivers.set(driver.id, Driver.create({
id: driver.id,
iracingId: `iracing-${driver.id}`,
name: driver.name,
country: driver.country,
joinedAt: new Date('2024-01-01'),
}));
}
}
async findById(id: string): Promise<{ id: string; name: string; country: string } | null> {
async findById(id: string): Promise<Driver | null> {
return this.drivers.get(id) ?? null;
}
async findAll(): Promise<Array<{ id: string; name: string; country: string }>> {
async findAll(): Promise<Driver[]> {
return [...this.drivers.values()];
}
async findByIds(ids: string[]): Promise<Array<{ id: string; name: string; country: string }>> {
async findByIds(ids: string[]): Promise<Driver[]> {
return ids
.map(id => this.drivers.get(id))
.filter((d): d is { id: string; name: string; country: string } => !!d);
.filter((d): d is Driver => !!d);
}
async create(): Promise<any> {
@@ -160,6 +169,14 @@ class InMemoryDriverRepository implements IDriverRepository {
async exists(): Promise<boolean> {
return false;
}
async findByIRacingId(): Promise<Driver | null> {
return null;
}
async existsByIRacingId(): Promise<boolean> {
return false;
}
}
class InMemoryRaceRegistrationRepository implements IRaceRegistrationRepository {
@@ -365,6 +382,10 @@ class FakeRaceDetailPresenter implements IRaceDetailPresenter {
getViewModel(): RaceDetailViewModel | null {
return this.viewModel;
}
reset(): void {
this.viewModel = null;
}
}
describe('GetRaceDetailUseCase', () => {
@@ -405,13 +426,13 @@ describe('GetRaceDetailUseCase', () => {
const resultRepo = new InMemoryResultRepository([]);
const membershipRepo = new InMemoryLeagueMembershipRepository();
membershipRepo.seedMembership({
membershipRepo.seedMembership(LeagueMembership.create({
leagueId: league.id,
driverId,
role: 'member',
status: 'active',
joinedAt: new Date('2024-01-01'),
});
}));
const ratingProvider = new TestDriverRatingProvider();
ratingProvider.seed(driverId, 1500);
@@ -429,11 +450,10 @@ describe('GetRaceDetailUseCase', () => {
membershipRepo,
ratingProvider,
imageService,
presenter,
);
// When (execute the query for the current driver)
await useCase.execute({ raceId: race.id, driverId });
await useCase.execute({ raceId: race.id, driverId }, presenter);
const viewModel = presenter.getViewModel();
expect(viewModel).not.toBeNull();
@@ -502,13 +522,13 @@ describe('GetRaceDetailUseCase', () => {
const resultRepo = new InMemoryResultRepository([resultEntity]);
const membershipRepo = new InMemoryLeagueMembershipRepository();
membershipRepo.seedMembership({
membershipRepo.seedMembership(LeagueMembership.create({
leagueId: league.id,
driverId,
role: 'member',
status: 'active',
joinedAt: new Date('2024-01-01'),
});
}));
const ratingProvider = new TestDriverRatingProvider();
ratingProvider.seed(driverId, 2000);
@@ -525,11 +545,10 @@ describe('GetRaceDetailUseCase', () => {
membershipRepo,
ratingProvider,
imageService,
presenter,
);
// When (executing the query for the completed race)
await useCase.execute({ raceId: race.id, driverId });
await useCase.execute({ raceId: race.id, driverId }, presenter);
const viewModel = presenter.getViewModel();
expect(viewModel).not.toBeNull();
@@ -566,11 +585,10 @@ describe('GetRaceDetailUseCase', () => {
membershipRepo,
ratingProvider,
imageService,
presenter,
);
// When
await useCase.execute({ raceId: 'missing-race', driverId: 'driver-x' });
await useCase.execute({ raceId: 'missing-race', driverId: 'driver-x' }, presenter);
const viewModel = presenter.getViewModel();
// Then