website refactor

This commit is contained in:
2026-01-16 12:55:48 +01:00
parent 0208334c59
commit 20a42c52fd
83 changed files with 1610 additions and 1238 deletions

View File

@@ -15,7 +15,7 @@ import { FeatureAvailabilityGuard } from '../policy/FeatureAvailabilityGuard';
describe('Race domain (HTTP, module-wiring)', () => {
const originalEnv = { ...process.env };
let app: any;
let app: import("@nestjs/common").INestApplication;
beforeAll(async () => {
vi.resetModules();
@@ -62,9 +62,9 @@ describe('Race domain (HTTP, module-wiring)', () => {
};
app.useGlobalGuards(
new AuthenticationGuard(sessionPort as any),
new AuthorizationGuard(reflector, authorizationService as any),
new FeatureAvailabilityGuard(reflector, policyService as any),
new AuthenticationGuard(sessionPort as never),
new AuthorizationGuard(reflector, authorizationService as never),
new FeatureAvailabilityGuard(reflector, policyService as never),
);
await app.init();

View File

@@ -58,8 +58,8 @@ describe('RaceController', () => {
describe('getAllRaces', () => {
it('should return all races view model', async () => {
const mockPresenter = { viewModel: { races: [], filters: { statuses: [], leagues: [] } } } as any;
service.getAllRaces.mockResolvedValue(mockPresenter);
const mockPresenter = { viewModel: { races: [], filters: { statuses: [], leagues: [] } } } as unknown as { viewModel: unknown };
service.getAllRaces.mockResolvedValue(mockPresenter as never);
const result = await controller.getAllRaces();
@@ -70,8 +70,8 @@ describe('RaceController', () => {
describe('getTotalRaces', () => {
it('should return total races count view model', async () => {
const mockPresenter = { viewModel: { totalRaces: 5 } } as any;
service.getTotalRaces.mockResolvedValue(mockPresenter);
const mockPresenter = { viewModel: { totalRaces: 5 } } as unknown as { viewModel: unknown };
service.getTotalRaces.mockResolvedValue(mockPresenter as never);
const result = await controller.getTotalRaces();
@@ -81,7 +81,7 @@ describe('RaceController', () => {
});
describe('auth guards (HTTP)', () => {
let app: any;
let app: import("@nestjs/common").INestApplication;
const sessionPort: { getCurrentSession: () => Promise<null | { token: string; user: { id: string } }> } = {
getCurrentSession: vi.fn(async () => null),
@@ -120,9 +120,9 @@ describe('RaceController', () => {
const reflector = new Reflector();
app.useGlobalGuards(
new AuthenticationGuard(sessionPort as any),
new AuthorizationGuard(reflector, authorizationService as any),
new FeatureAvailabilityGuard(reflector, policyService as any),
new AuthenticationGuard(sessionPort as never),
new AuthorizationGuard(reflector, authorizationService as never),
new FeatureAvailabilityGuard(reflector, policyService as never),
);
await app.init();

View File

@@ -1,11 +1,11 @@
import { describe, expect, it, vi } from 'vitest';
import { describe, expect, it, vi, type Mock } from 'vitest';
import { RaceService } from './RaceService';
import { Result } from '@core/shared/application/Result';
describe('RaceService', () => {
it('invokes each use case and returns the corresponding presenter', async () => {
// Mock use cases to return Result.ok()
const mkUseCase = (resultValue: any = { success: true }) => ({
const mkUseCase = (resultValue: unknown = { success: true }) => ({
execute: vi.fn(async () => Result.ok(resultValue))
});
@@ -32,51 +32,51 @@ describe('RaceService', () => {
const logger = { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() };
const getAllRacesPresenter = { present: vi.fn() } as any;
const getTotalRacesPresenter = { present: vi.fn() } as any;
const importRaceResultsApiPresenter = { present: vi.fn() } as any;
const raceDetailPresenter = { present: vi.fn() } as any;
const racesPageDataPresenter = { present: vi.fn() } as any;
const allRacesPageDataPresenter = { present: vi.fn() } as any;
const raceResultsDetailPresenter = { present: vi.fn() } as any;
const raceWithSOFPresenter = { present: vi.fn() } as any;
const raceProtestsPresenter = { present: vi.fn() } as any;
const racePenaltiesPresenter = { present: vi.fn() } as any;
const commandResultPresenter = { present: vi.fn() } as any;
const getAllRacesPresenter = { present: vi.fn() } as unknown as { present: Mock };
const getTotalRacesPresenter = { present: vi.fn() } as unknown as { present: Mock };
const importRaceResultsApiPresenter = { present: vi.fn() } as unknown as { present: Mock };
const raceDetailPresenter = { present: vi.fn() } as unknown as { present: Mock };
const racesPageDataPresenter = { present: vi.fn() } as unknown as { present: Mock };
const allRacesPageDataPresenter = { present: vi.fn() } as unknown as { present: Mock };
const raceResultsDetailPresenter = { present: vi.fn() } as unknown as { present: Mock };
const raceWithSOFPresenter = { present: vi.fn() } as unknown as { present: Mock };
const raceProtestsPresenter = { present: vi.fn() } as unknown as { present: Mock };
const racePenaltiesPresenter = { present: vi.fn() } as unknown as { present: Mock };
const commandResultPresenter = { present: vi.fn() } as unknown as { present: Mock };
const service = new RaceService(
getAllRacesUseCase as any,
getTotalRacesUseCase as any,
importRaceResultsApiUseCase as any,
getRaceDetailUseCase as any,
getRacesPageDataUseCase as any,
getAllRacesPageDataUseCase as any,
getRaceResultsDetailUseCase as any,
getRaceWithSOFUseCase as any,
getRaceProtestsUseCase as any,
getRacePenaltiesUseCase as any,
registerForRaceUseCase as any,
withdrawFromRaceUseCase as any,
cancelRaceUseCase as any,
completeRaceUseCase as any,
fileProtestUseCase as any,
quickPenaltyUseCase as any,
applyPenaltyUseCase as any,
requestProtestDefenseUseCase as any,
reviewProtestUseCase as any,
reopenRaceUseCase as any,
logger as any,
getAllRacesPresenter,
getTotalRacesPresenter,
importRaceResultsApiPresenter,
raceDetailPresenter,
racesPageDataPresenter,
allRacesPageDataPresenter,
raceResultsDetailPresenter,
raceWithSOFPresenter,
raceProtestsPresenter,
racePenaltiesPresenter,
commandResultPresenter,
getAllRacesUseCase as never,
getTotalRacesUseCase as never,
importRaceResultsApiUseCase as never,
getRaceDetailUseCase as never,
getRacesPageDataUseCase as never,
getAllRacesPageDataUseCase as never,
getRaceResultsDetailUseCase as never,
getRaceWithSOFUseCase as never,
getRaceProtestsUseCase as never,
getRacePenaltiesUseCase as never,
registerForRaceUseCase as never,
withdrawFromRaceUseCase as never,
cancelRaceUseCase as never,
completeRaceUseCase as never,
fileProtestUseCase as never,
quickPenaltyUseCase as never,
applyPenaltyUseCase as never,
requestProtestDefenseUseCase as never,
reviewProtestUseCase as never,
reopenRaceUseCase as never,
logger as never,
getAllRacesPresenter as never,
getTotalRacesPresenter as never,
importRaceResultsApiPresenter as never,
raceDetailPresenter as never,
racesPageDataPresenter as never,
allRacesPageDataPresenter as never,
raceResultsDetailPresenter as never,
raceWithSOFPresenter as never,
raceProtestsPresenter as never,
racePenaltiesPresenter as never,
commandResultPresenter as never,
);
expect(await service.getAllRaces()).toBe(getAllRacesPresenter);
@@ -87,11 +87,11 @@ describe('RaceService', () => {
expect(getTotalRacesUseCase.execute).toHaveBeenCalledWith({});
expect(getTotalRacesPresenter.present).toHaveBeenCalledWith({ totalRaces: 0 });
expect(await service.importRaceResults({ raceId: 'r1', resultsFileContent: 'x' } as any)).toBe(importRaceResultsApiPresenter);
expect(await service.importRaceResults({ raceId: 'r1', resultsFileContent: 'x' } as never)).toBe(importRaceResultsApiPresenter);
expect(importRaceResultsApiUseCase.execute).toHaveBeenCalledWith({ raceId: 'r1', resultsFileContent: 'x' });
expect(importRaceResultsApiPresenter.present).toHaveBeenCalledWith({ success: true, raceId: 'r1', driversProcessed: 0, resultsRecorded: 0, errors: [] });
expect(await service.getRaceDetail({ raceId: 'r1' } as any)).toBe(raceDetailPresenter);
expect(await service.getRaceDetail({ raceId: 'r1' } as never)).toBe(raceDetailPresenter);
expect(getRaceDetailUseCase.execute).toHaveBeenCalled();
expect(await service.getRacesPageData('l1')).toBe(racesPageDataPresenter);
@@ -118,43 +118,43 @@ describe('RaceService', () => {
expect(getRacePenaltiesUseCase.execute).toHaveBeenCalledWith({ raceId: 'r1' });
expect(racePenaltiesPresenter.present).toHaveBeenCalledWith({ penalties: [], drivers: [] });
expect(await service.registerForRace({ raceId: 'r1', driverId: 'd1' } as any)).toBe(commandResultPresenter);
expect(await service.registerForRace({ raceId: 'r1', driverId: 'd1' } as never)).toBe(commandResultPresenter);
expect(registerForRaceUseCase.execute).toHaveBeenCalled();
expect(commandResultPresenter.present).toHaveBeenCalled();
expect(await service.withdrawFromRace({ raceId: 'r1', driverId: 'd1' } as any)).toBe(commandResultPresenter);
expect(await service.withdrawFromRace({ raceId: 'r1', driverId: 'd1' } as never)).toBe(commandResultPresenter);
expect(withdrawFromRaceUseCase.execute).toHaveBeenCalled();
expect(commandResultPresenter.present).toHaveBeenCalled();
expect(await service.cancelRace({ raceId: 'r1' } as any, 'admin')).toBe(commandResultPresenter);
expect(await service.cancelRace({ raceId: 'r1' } as never, 'admin')).toBe(commandResultPresenter);
expect(cancelRaceUseCase.execute).toHaveBeenCalledWith({ raceId: 'r1', cancelledById: 'admin' });
expect(commandResultPresenter.present).toHaveBeenCalled();
expect(await service.completeRace({ raceId: 'r1' } as any)).toBe(commandResultPresenter);
expect(await service.completeRace({ raceId: 'r1' } as never)).toBe(commandResultPresenter);
expect(completeRaceUseCase.execute).toHaveBeenCalledWith({ raceId: 'r1' });
expect(commandResultPresenter.present).toHaveBeenCalled();
expect(await service.reopenRace({ raceId: 'r1' } as any, 'admin')).toBe(commandResultPresenter);
expect(await service.reopenRace({ raceId: 'r1' } as never, 'admin')).toBe(commandResultPresenter);
expect(reopenRaceUseCase.execute).toHaveBeenCalledWith({ raceId: 'r1', reopenedById: 'admin' });
expect(commandResultPresenter.present).toHaveBeenCalled();
expect(await service.fileProtest({} as any)).toBe(commandResultPresenter);
expect(await service.fileProtest({} as never)).toBe(commandResultPresenter);
expect(fileProtestUseCase.execute).toHaveBeenCalled();
expect(commandResultPresenter.present).toHaveBeenCalled();
expect(await service.applyQuickPenalty({} as any)).toBe(commandResultPresenter);
expect(await service.applyQuickPenalty({} as never)).toBe(commandResultPresenter);
expect(quickPenaltyUseCase.execute).toHaveBeenCalled();
expect(commandResultPresenter.present).toHaveBeenCalled();
expect(await service.applyPenalty({} as any)).toBe(commandResultPresenter);
expect(await service.applyPenalty({} as never)).toBe(commandResultPresenter);
expect(applyPenaltyUseCase.execute).toHaveBeenCalled();
expect(commandResultPresenter.present).toHaveBeenCalled();
expect(await service.requestProtestDefense({} as any)).toBe(commandResultPresenter);
expect(await service.requestProtestDefense({} as never)).toBe(commandResultPresenter);
expect(requestProtestDefenseUseCase.execute).toHaveBeenCalled();
expect(commandResultPresenter.present).toHaveBeenCalled();
expect(await service.reviewProtest({} as any)).toBe(commandResultPresenter);
expect(await service.reviewProtest({} as never)).toBe(commandResultPresenter);
expect(reviewProtestUseCase.execute).toHaveBeenCalled();
expect(commandResultPresenter.present).toHaveBeenCalled();
});

View File

@@ -35,13 +35,13 @@ describe('GetAllRacesPresenter', () => {
strengthOfField: 1800,
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
] as any,
] as never,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
leagues: [
{ id: 'league-1', name: 'League One' },
{ id: 'league-2', name: 'League Two' },
// eslint-disable-next-line @typescript-eslint/no-explicit-any
] as any,
] as never,
totalCount: 3,
};
@@ -66,9 +66,9 @@ describe('GetAllRacesPresenter', () => {
const output: GetAllRacesResult = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
races: [] as any,
races: [] as never,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
leagues: [] as any,
leagues: [] as never,
totalCount: 0,
};

View File

@@ -23,12 +23,12 @@ describe('RacePenaltiesPresenter', () => {
const mockDriver = {
id: 'driver-456',
name: { toString: () => 'John Doe' } as any,
name: { toString: () => 'John Doe' } as never,
};
const result: GetRacePenaltiesResult = {
penalties: [mockPenalty as any],
drivers: [mockDriver as any],
penalties: [mockPenalty as never],
drivers: [mockDriver as never],
};
presenter.present(result);
@@ -63,7 +63,7 @@ describe('RacePenaltiesPresenter', () => {
reason: 'Reason 1',
issuedBy: 'steward-1',
issuedAt: new Date('2024-01-01T10:00:00Z'),
} as any,
} as never,
{
id: 'penalty-2',
driverId: 'driver-2',
@@ -72,11 +72,11 @@ describe('RacePenaltiesPresenter', () => {
reason: 'Reason 2',
issuedBy: 'steward-1',
issuedAt: new Date('2024-01-01T10:05:00Z'),
} as any,
} as never,
],
drivers: [
{ id: 'driver-1', name: { toString: () => 'Driver One' } } as any,
{ id: 'driver-2', name: { toString: () => 'Driver Two' } } as any,
{ id: 'driver-1', name: { toString: () => 'Driver One' } } as never,
{ id: 'driver-2', name: { toString: () => 'Driver Two' } } as never,
],
};
@@ -114,9 +114,9 @@ describe('RacePenaltiesPresenter', () => {
reason: 'Reason',
issuedBy: 'steward-1',
issuedAt: new Date('2024-01-01T10:00:00Z'),
} as any,
} as never,
],
drivers: [{ id: 'driver-1', name: { toString: () => 'Driver One' } } as any],
drivers: [{ id: 'driver-1', name: { toString: () => 'Driver One' } } as never],
};
presenter.present(result);
@@ -128,8 +128,8 @@ describe('RacePenaltiesPresenter', () => {
describe('reset', () => {
it('should clear the model', () => {
presenter.present({
penalties: [{ id: 'p1', driverId: 'd1', type: 't', value: 1, reason: 'r', issuedBy: 's1', issuedAt: new Date() } as any],
drivers: [{ id: 'd1', name: { toString: () => 'D1' } } as any],
penalties: [{ id: 'p1', driverId: 'd1', type: 't', value: 1, reason: 'r', issuedBy: 's1', issuedAt: new Date() } as never],
drivers: [{ id: 'd1', name: { toString: () => 'D1' } } as never],
});
expect(presenter.responseModel).toBeDefined();
@@ -147,8 +147,8 @@ describe('RacePenaltiesPresenter', () => {
describe('viewModel', () => {
it('should return same as responseModel', () => {
const result: GetRacePenaltiesResult = {
penalties: [{ id: 'p1', driverId: 'd1', type: 't', value: 1, reason: 'r', issuedBy: 's1', issuedAt: new Date() } as any],
drivers: [{ id: 'd1', name: { toString: () => 'D1' } } as any],
penalties: [{ id: 'p1', driverId: 'd1', type: 't', value: 1, reason: 'r', issuedBy: 's1', issuedAt: new Date() } as never],
drivers: [{ id: 'd1', name: { toString: () => 'D1' } } as never],
};
presenter.present(result);

View File

@@ -15,26 +15,26 @@ describe('RaceProtestsPresenter', () => {
protestingDriverId: 'driver-456',
accusedDriverId: 'driver-789',
incident: {
lap: { toNumber: () => 5 } as any,
description: { toString: () => 'Contact at turn 3' } as any,
lap: { toNumber: () => 5 } as never,
description: { toString: () => 'Contact at turn 3' } as never,
},
status: { toString: () => 'pending' } as any,
status: { toString: () => 'pending' } as never,
filedAt: new Date('2024-01-01T10:30:00Z'),
};
const mockDriver1 = {
id: 'driver-456',
name: { toString: () => 'John Doe' } as any,
name: { toString: () => 'John Doe' } as never,
};
const mockDriver2 = {
id: 'driver-789',
name: { toString: () => 'Jane Smith' } as any,
name: { toString: () => 'Jane Smith' } as never,
};
const result: GetRaceProtestsResult = {
protests: [mockProtest as any],
drivers: [mockDriver1 as any, mockDriver2 as any],
protests: [mockProtest as never],
drivers: [mockDriver1 as never, mockDriver2 as never],
};
presenter.present(result);
@@ -68,28 +68,28 @@ describe('RaceProtestsPresenter', () => {
protestingDriverId: 'driver-1',
accusedDriverId: 'driver-2',
incident: {
lap: { toNumber: () => 3 } as any,
description: { toString: () => 'Incident 1' } as any
lap: { toNumber: () => 3 } as never,
description: { toString: () => 'Incident 1' } as never
},
status: { toString: () => 'pending' } as any,
status: { toString: () => 'pending' } as never,
filedAt: new Date('2024-01-01T10:00:00Z'),
} as any,
} as never,
{
id: 'protest-2',
protestingDriverId: 'driver-3',
accusedDriverId: 'driver-1',
incident: {
lap: { toNumber: () => 7 } as any,
description: { toString: () => 'Incident 2' } as any
lap: { toNumber: () => 7 } as never,
description: { toString: () => 'Incident 2' } as never
},
status: { toString: () => 'reviewed' } as any,
status: { toString: () => 'reviewed' } as never,
filedAt: new Date('2024-01-01T10:10:00Z'),
} as any,
} as never,
],
drivers: [
{ id: 'driver-1', name: { toString: () => 'Driver One' } } as any,
{ id: 'driver-2', name: { toString: () => 'Driver Two' } } as any,
{ id: 'driver-3', name: { toString: () => 'Driver Three' } } as any,
{ id: 'driver-1', name: { toString: () => 'Driver One' } } as never,
{ id: 'driver-2', name: { toString: () => 'Driver Two' } } as never,
{ id: 'driver-3', name: { toString: () => 'Driver Three' } } as never,
],
};
@@ -125,16 +125,16 @@ describe('RaceProtestsPresenter', () => {
protestingDriverId: 'driver-1',
accusedDriverId: 'driver-2',
incident: {
lap: { toNumber: () => 5 } as any,
description: { toString: () => 'Test' } as any
lap: { toNumber: () => 5 } as never,
description: { toString: () => 'Test' } as never
},
status: { toString: () => 'approved' } as any,
status: { toString: () => 'approved' } as never,
filedAt: new Date('2024-01-01T10:00:00Z'),
} as any,
} as never,
],
drivers: [
{ id: 'driver-1', name: { toString: () => 'Driver One' } } as any,
{ id: 'driver-2', name: { toString: () => 'Driver Two' } } as any,
{ id: 'driver-1', name: { toString: () => 'Driver One' } } as never,
{ id: 'driver-2', name: { toString: () => 'Driver Two' } } as never,
],
};
@@ -152,13 +152,13 @@ describe('RaceProtestsPresenter', () => {
protestingDriverId: 'd1',
accusedDriverId: 'd2',
incident: {
lap: { toNumber: () => 1 } as any,
description: { toString: () => 'test' } as any
lap: { toNumber: () => 1 } as never,
description: { toString: () => 'test' } as never
},
status: { toString: () => 'pending' } as any,
status: { toString: () => 'pending' } as never,
filedAt: new Date()
} as any],
drivers: [{ id: 'd1', name: { toString: () => 'D1' } } as any, { id: 'd2', name: { toString: () => 'D2' } } as any],
} as never],
drivers: [{ id: 'd1', name: { toString: () => 'D1' } } as never, { id: 'd2', name: { toString: () => 'D2' } } as never],
});
expect(presenter.responseModel).toBeDefined();
@@ -181,13 +181,13 @@ describe('RaceProtestsPresenter', () => {
protestingDriverId: 'd1',
accusedDriverId: 'd2',
incident: {
lap: { toNumber: () => 1 } as any,
description: { toString: () => 'test' } as any
lap: { toNumber: () => 1 } as never,
description: { toString: () => 'test' } as never
},
status: { toString: () => 'pending' } as any,
status: { toString: () => 'pending' } as never,
filedAt: new Date()
} as any],
drivers: [{ id: 'd1', name: { toString: () => 'D1' } } as any, { id: 'd2', name: { toString: () => 'D2' } } as any],
} as never],
drivers: [{ id: 'd1', name: { toString: () => 'D1' } } as never, { id: 'd2', name: { toString: () => 'D2' } } as never],
};
presenter.present(result);