refactor
This commit is contained in:
@@ -8,15 +8,13 @@ import type { IResultRepository } from '@core/racing/domain/repositories/IResult
|
||||
import type { ILeagueMembershipRepository } from '@core/racing/domain/repositories/ILeagueMembershipRepository';
|
||||
import type { DriverRatingProvider } from '@core/racing/application/ports/DriverRatingProvider';
|
||||
import type { IImageServicePort } from '@core/racing/application/ports/IImageServicePort';
|
||||
import type {
|
||||
IRaceDetailPresenter,
|
||||
RaceDetailViewModel,
|
||||
} from '@core/racing/application/presenters/IRaceDetailPresenter';
|
||||
import type { Logger } from '@core/shared/application';
|
||||
|
||||
import { Race } from '@core/racing/domain/entities/Race';
|
||||
import { League } from '@core/racing/domain/entities/League';
|
||||
import { Result } from '@core/racing/domain/entities/Result';
|
||||
import { Driver } from '@core/racing/domain/entities/Driver';
|
||||
import { LeagueMembership } from '@core/racing/domain/entities/LeagueMembership';
|
||||
|
||||
import { GetRaceDetailUseCase } from '@core/racing/application/use-cases/GetRaceDetailUseCase';
|
||||
import { CancelRaceUseCase } from '@core/racing/application/use-cases/CancelRaceUseCase';
|
||||
@@ -154,11 +152,11 @@ class InMemoryDriverRepository implements IDriverRepository {
|
||||
.filter((d): d is Driver => !!d);
|
||||
}
|
||||
|
||||
async create(): Promise<any> {
|
||||
async create(): Promise<Driver> {
|
||||
throw new Error('Not needed for these tests');
|
||||
}
|
||||
|
||||
async update(): Promise<any> {
|
||||
async update(): Promise<Driver> {
|
||||
throw new Error('Not needed for these tests');
|
||||
}
|
||||
|
||||
@@ -371,21 +369,11 @@ class TestImageService implements IImageServicePort {
|
||||
}
|
||||
}
|
||||
|
||||
class FakeRaceDetailPresenter implements IRaceDetailPresenter {
|
||||
viewModel: RaceDetailViewModel | null = null;
|
||||
|
||||
present(viewModel: RaceDetailViewModel): RaceDetailViewModel {
|
||||
this.viewModel = viewModel;
|
||||
return viewModel;
|
||||
}
|
||||
|
||||
getViewModel(): RaceDetailViewModel | null {
|
||||
return this.viewModel;
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
this.viewModel = null;
|
||||
}
|
||||
class MockLogger implements Logger {
|
||||
debug = vi.fn();
|
||||
info = vi.fn();
|
||||
warn = vi.fn();
|
||||
error = vi.fn();
|
||||
}
|
||||
|
||||
describe('GetRaceDetailUseCase', () => {
|
||||
@@ -404,7 +392,7 @@ describe('GetRaceDetailUseCase', () => {
|
||||
scheduledAt: new Date(Date.now() + 60 * 60 * 1000),
|
||||
track: 'Test Track',
|
||||
car: 'GT3',
|
||||
sessionType: 'race',
|
||||
sessionType: 'main',
|
||||
status: 'scheduled',
|
||||
});
|
||||
|
||||
@@ -439,7 +427,6 @@ describe('GetRaceDetailUseCase', () => {
|
||||
ratingProvider.seed(otherDriverId, 1600);
|
||||
|
||||
const imageService = new TestImageService();
|
||||
const presenter = new FakeRaceDetailPresenter();
|
||||
|
||||
const useCase = new GetRaceDetailUseCase(
|
||||
raceRepo,
|
||||
@@ -453,10 +440,10 @@ describe('GetRaceDetailUseCase', () => {
|
||||
);
|
||||
|
||||
// When (execute the query for the current driver)
|
||||
await useCase.execute({ raceId: race.id, driverId }, presenter);
|
||||
const result = await useCase.execute({ raceId: race.id, driverId });
|
||||
|
||||
const viewModel = presenter.getViewModel();
|
||||
expect(viewModel).not.toBeNull();
|
||||
expect(result.isOk()).toBe(true);
|
||||
const viewModel = result.unwrap();
|
||||
|
||||
// Then (verify race, league and registration flags)
|
||||
expect(viewModel!.race?.id).toBe(race.id);
|
||||
@@ -494,7 +481,7 @@ describe('GetRaceDetailUseCase', () => {
|
||||
scheduledAt: new Date(Date.now() - 2 * 60 * 60 * 1000),
|
||||
track: 'Historic Circuit',
|
||||
car: 'LMP2',
|
||||
sessionType: 'race',
|
||||
sessionType: 'main',
|
||||
status: 'completed',
|
||||
});
|
||||
|
||||
@@ -534,7 +521,6 @@ describe('GetRaceDetailUseCase', () => {
|
||||
ratingProvider.seed(driverId, 2000);
|
||||
|
||||
const imageService = new TestImageService();
|
||||
const presenter = new FakeRaceDetailPresenter();
|
||||
|
||||
const useCase = new GetRaceDetailUseCase(
|
||||
raceRepo,
|
||||
@@ -548,11 +534,11 @@ describe('GetRaceDetailUseCase', () => {
|
||||
);
|
||||
|
||||
// When (executing the query for the completed race)
|
||||
await useCase.execute({ raceId: race.id, driverId }, presenter);
|
||||
const result = await useCase.execute({ raceId: race.id, driverId });
|
||||
|
||||
const viewModel = presenter.getViewModel();
|
||||
expect(viewModel).not.toBeNull();
|
||||
expect(viewModel!.userResult).not.toBeNull();
|
||||
expect(result.isOk()).toBe(true);
|
||||
const viewModel = result.unwrap();
|
||||
expect(viewModel.userResult).not.toBeNull();
|
||||
|
||||
// Then (rating change uses the same formula as the legacy UI)
|
||||
// For P1: baseChange = 25, positionBonus = (20 - 1) * 2 = 38, total = 63
|
||||
@@ -574,7 +560,6 @@ describe('GetRaceDetailUseCase', () => {
|
||||
const membershipRepo = new InMemoryLeagueMembershipRepository();
|
||||
const ratingProvider = new TestDriverRatingProvider();
|
||||
const imageService = new TestImageService();
|
||||
const presenter = new FakeRaceDetailPresenter();
|
||||
|
||||
const useCase = new GetRaceDetailUseCase(
|
||||
raceRepo,
|
||||
@@ -588,13 +573,11 @@ describe('GetRaceDetailUseCase', () => {
|
||||
);
|
||||
|
||||
// When
|
||||
await useCase.execute({ raceId: 'missing-race', driverId: 'driver-x' }, presenter);
|
||||
const result = await useCase.execute({ raceId: 'missing-race', driverId: 'driver-x' });
|
||||
|
||||
const viewModel = presenter.getViewModel();
|
||||
// Then
|
||||
expect(viewModel).not.toBeNull();
|
||||
expect(viewModel!.race).toBeNull();
|
||||
expect(viewModel!.error).toBe('Race not found');
|
||||
expect(result.isErr()).toBe(true);
|
||||
expect(result.unwrapErr()).toEqual({ code: 'RACE_NOT_FOUND' });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -607,30 +590,35 @@ describe('CancelRaceUseCase', () => {
|
||||
scheduledAt: new Date(Date.now() + 60 * 60 * 1000),
|
||||
track: 'Cancel Circuit',
|
||||
car: 'GT4',
|
||||
sessionType: 'race',
|
||||
sessionType: 'main',
|
||||
status: 'scheduled',
|
||||
});
|
||||
|
||||
const raceRepo = new InMemoryRaceRepository([race]);
|
||||
const useCase = new CancelRaceUseCase(raceRepo);
|
||||
const logger = new MockLogger();
|
||||
const useCase = new CancelRaceUseCase(raceRepo, logger);
|
||||
|
||||
// When
|
||||
await useCase.execute({ raceId: race.id });
|
||||
const result = await useCase.execute({ raceId: race.id });
|
||||
|
||||
// Then (the stored race is now cancelled)
|
||||
expect(result.isOk()).toBe(true);
|
||||
const updated = raceRepo.getStored(race.id);
|
||||
expect(updated).not.toBeNull();
|
||||
expect(updated!.status).toBe('cancelled');
|
||||
});
|
||||
|
||||
it('throws when trying to cancel a non-existent race', async () => {
|
||||
it('returns error when trying to cancel a non-existent race', async () => {
|
||||
// Given
|
||||
const raceRepo = new InMemoryRaceRepository([]);
|
||||
const useCase = new CancelRaceUseCase(raceRepo);
|
||||
const logger = new MockLogger();
|
||||
const useCase = new CancelRaceUseCase(raceRepo, logger);
|
||||
|
||||
// When / Then
|
||||
await expect(
|
||||
useCase.execute({ raceId: 'does-not-exist' }),
|
||||
).rejects.toThrow('Race not found');
|
||||
// When
|
||||
const result = await useCase.execute({ raceId: 'does-not-exist' });
|
||||
|
||||
// Then
|
||||
expect(result.isErr()).toBe(true);
|
||||
expect(result.unwrapErr()).toEqual({ code: 'RACE_NOT_FOUND' });
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user