module cleanup

This commit is contained in:
2025-12-19 01:22:45 +01:00
parent d617654928
commit d0fac9e6c1
135 changed files with 5104 additions and 1315 deletions

View File

@@ -0,0 +1,163 @@
import { Test, TestingModule } from '@nestjs/testing';
import { vi } from 'vitest';
import { DriverController } from './DriverController';
import { DriverService } from './DriverService';
import type { Request } from 'express';
interface AuthenticatedRequest extends Request {
user?: { userId: string };
}
import { CompleteOnboardingInputDTO } from './dtos/CompleteOnboardingInputDTO';
import { CompleteOnboardingOutputDTO } from './dtos/CompleteOnboardingOutputDTO';
import { DriversLeaderboardDTO } from './dtos/DriversLeaderboardDTO';
import { DriverStatsDTO } from './dtos/DriverStatsDTO';
import { GetDriverOutputDTO } from './dtos/GetDriverOutputDTO';
import { GetDriverProfileOutputDTO } from './dtos/GetDriverProfileOutputDTO';
import { DriverRegistrationStatusDTO } from './dtos/DriverRegistrationStatusDTO';
describe('DriverController', () => {
let controller: DriverController;
let service: ReturnType<typeof vi.mocked<DriverService>>;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [DriverController],
providers: [
{
provide: DriverService,
useValue: {
getDriversLeaderboard: vi.fn(),
getTotalDrivers: vi.fn(),
getCurrentDriver: vi.fn(),
completeOnboarding: vi.fn(),
getDriverRegistrationStatus: vi.fn(),
getDriver: vi.fn(),
getDriverProfile: vi.fn(),
updateDriverProfile: vi.fn(),
},
},
],
}).compile();
controller = module.get<DriverController>(DriverController);
service = vi.mocked(module.get(DriverService));
});
describe('getDriversLeaderboard', () => {
it('should return drivers leaderboard', async () => {
const leaderboard: DriversLeaderboardDTO = { items: [] };
service.getDriversLeaderboard.mockResolvedValue(leaderboard);
const result = await controller.getDriversLeaderboard();
expect(service.getDriversLeaderboard).toHaveBeenCalled();
expect(result).toEqual(leaderboard);
});
});
describe('getTotalDrivers', () => {
it('should return total drivers stats', async () => {
const stats: DriverStatsDTO = { totalDrivers: 100 };
service.getTotalDrivers.mockResolvedValue(stats);
const result = await controller.getTotalDrivers();
expect(service.getTotalDrivers).toHaveBeenCalled();
expect(result).toEqual(stats);
});
});
describe('getCurrentDriver', () => {
it('should return current driver if userId exists', async () => {
const userId = 'user-123';
const driver: GetDriverOutputDTO = { id: 'driver-123', name: 'Driver' };
service.getCurrentDriver.mockResolvedValue(driver);
const mockReq: Partial<AuthenticatedRequest> = { user: { userId } };
const result = await controller.getCurrentDriver(mockReq as AuthenticatedRequest);
expect(service.getCurrentDriver).toHaveBeenCalledWith(userId);
expect(result).toEqual(driver);
});
it('should return null if no userId', async () => {
const mockReq: Partial<AuthenticatedRequest> = {};
const result = await controller.getCurrentDriver(mockReq as AuthenticatedRequest);
expect(service.getCurrentDriver).not.toHaveBeenCalled();
expect(result).toBeNull();
});
});
describe('completeOnboarding', () => {
it('should complete onboarding', async () => {
const userId = 'user-123';
const input: CompleteOnboardingInputDTO = { someField: 'value' };
const output: CompleteOnboardingOutputDTO = { success: true };
service.completeOnboarding.mockResolvedValue(output);
const mockReq: Partial<AuthenticatedRequest> = { user: { userId } };
const result = await controller.completeOnboarding(input, mockReq as AuthenticatedRequest);
expect(service.completeOnboarding).toHaveBeenCalledWith(userId, input);
expect(result).toEqual(output);
});
});
describe('getDriverRegistrationStatus', () => {
it('should return registration status', async () => {
const driverId = 'driver-123';
const raceId = 'race-456';
const status: DriverRegistrationStatusDTO = { registered: true };
service.getDriverRegistrationStatus.mockResolvedValue(status);
const result = await controller.getDriverRegistrationStatus(driverId, raceId);
expect(service.getDriverRegistrationStatus).toHaveBeenCalledWith({ driverId, raceId });
expect(result).toEqual(status);
});
});
describe('getDriver', () => {
it('should return driver by id', async () => {
const driverId = 'driver-123';
const driver: GetDriverOutputDTO = { id: driverId, name: 'Driver' };
service.getDriver.mockResolvedValue(driver);
const result = await controller.getDriver(driverId);
expect(service.getDriver).toHaveBeenCalledWith(driverId);
expect(result).toEqual(driver);
});
});
describe('getDriverProfile', () => {
it('should return driver profile', async () => {
const driverId = 'driver-123';
const profile: GetDriverProfileOutputDTO = { id: driverId, bio: 'Bio' };
service.getDriverProfile.mockResolvedValue(profile);
const result = await controller.getDriverProfile(driverId);
expect(service.getDriverProfile).toHaveBeenCalledWith(driverId);
expect(result).toEqual(profile);
});
});
describe('updateDriverProfile', () => {
it('should update driver profile', async () => {
const driverId = 'driver-123';
const body = { bio: 'New bio', country: 'US' };
const updated: GetDriverOutputDTO = { id: driverId, name: 'Driver' };
service.updateDriverProfile.mockResolvedValue(updated);
const result = await controller.updateDriverProfile(driverId, body);
expect(service.updateDriverProfile).toHaveBeenCalledWith(driverId, body.bio, body.country);
expect(result).toEqual(updated);
});
});
});

View File

@@ -1,6 +1,10 @@
import { Controller, Get, Post, Body, Req, Param } from '@nestjs/common';
import { Request } from 'express';
import { ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger';
interface AuthenticatedRequest extends Request {
user?: { userId: string };
}
import { DriverService } from './DriverService';
import { DriversLeaderboardDTO } from './dtos/DriversLeaderboardDTO';
import { DriverStatsDTO } from './dtos/DriverStatsDTO';
@@ -35,9 +39,9 @@ export class DriverController {
@ApiOperation({ summary: 'Get current authenticated driver' })
@ApiResponse({ status: 200, description: 'Current driver data', type: GetDriverOutputDTO })
@ApiResponse({ status: 404, description: 'Driver not found' })
async getCurrentDriver(@Req() req: Request): Promise<GetDriverOutputDTO | null> {
async getCurrentDriver(@Req() req: AuthenticatedRequest): Promise<GetDriverOutputDTO | null> {
// Assuming userId is available from the request (e.g., via auth middleware)
const userId = req['user']?.userId;
const userId = req.user?.userId;
if (!userId) {
return null;
}
@@ -49,10 +53,10 @@ export class DriverController {
@ApiResponse({ status: 200, description: 'Onboarding complete', type: CompleteOnboardingOutputDTO })
async completeOnboarding(
@Body() input: CompleteOnboardingInputDTO,
@Req() req: Request,
@Req() req: AuthenticatedRequest,
): Promise<CompleteOnboardingOutputDTO> {
// Assuming userId is available from the request (e.g., via auth middleware)
const userId = req['user'].userId; // Placeholder for actual user extraction
const userId = req.user!.userId; // Placeholder for actual user extraction
return this.driverService.completeOnboarding(userId, input);
}

View File

@@ -0,0 +1,30 @@
import { Test, TestingModule } from '@nestjs/testing';
import { DriverModule } from './DriverModule';
import { DriverController } from './DriverController';
import { DriverService } from './DriverService';
describe('DriverModule', () => {
let module: TestingModule;
beforeEach(async () => {
module = await Test.createTestingModule({
imports: [DriverModule],
}).compile();
});
it('should compile the module', () => {
expect(module).toBeDefined();
});
it('should provide DriverController', () => {
const controller = module.get<DriverController>(DriverController);
expect(controller).toBeDefined();
expect(controller).toBeInstanceOf(DriverController);
});
it('should provide DriverService', () => {
const service = module.get<DriverService>(DriverService);
expect(service).toBeDefined();
expect(service).toBeInstanceOf(DriverService);
});
});

View File

@@ -9,25 +9,24 @@ import { DriverRatingProvider } from '@core/racing/application/ports/DriverRatin
import { IImageServicePort } from '@core/racing/application/ports/IImageServicePort';
import { IRaceRegistrationRepository } from '@core/racing/domain/repositories/IRaceRegistrationRepository';
import { INotificationPreferenceRepository } from '@core/notifications/domain/repositories/INotificationPreferenceRepository';
import type { Logger } from "@gridpilot/core/shared/application";
import type { Logger } from "@core/shared/application";
// Import use cases
import { GetDriversLeaderboardUseCase } from '@core/racing/application/use-cases/GetDriversLeaderboardUseCase';
import { GetTotalDriversUseCase } from '@core/racing/application/use-cases/GetTotalDriversUseCase';
import { CompleteDriverOnboardingUseCase } from '@core/racing/application/use-cases/CompleteDriverOnboardingUseCase';
import { GetProfileOverviewUseCase } from '@core/racing/application/use-cases/GetProfileOverviewUseCase';
import { GetDriverTeamUseCase } from '@core/racing/application/use-cases/GetDriverTeamUseCase';
import { UpdateDriverProfileUseCase } from '@core/racing/application/use-cases/UpdateDriverProfileUseCase';
import { IsDriverRegisteredForRaceUseCase } from '@core/racing/application/use-cases/IsDriverRegisteredForRaceUseCase';
// Import concrete in-memory implementations
import { InMemoryDriverRepository } from '../../..//racing/persistence/inmemory/InMemoryDriverRepository';
import { InMemoryRankingService } from '../../..//racing/services/InMemoryRankingService';
import { InMemoryDriverStatsService } from '../../..//racing/services/InMemoryDriverStatsService';
import { InMemoryDriverRatingProvider } from '../../..//racing/ports/InMemoryDriverRatingProvider';
import { InMemoryImageServiceAdapter } from '../../..//media/ports/InMemoryImageServiceAdapter';
import { InMemoryRaceRegistrationRepository } from '../../..//racing/persistence/inmemory/InMemoryRaceRegistrationRepository';
import { InMemoryNotificationPreferenceRepository } from '../../..//notifications/persistence/inmemory/InMemoryNotificationPreferenceRepository';
import { ConsoleLogger } from '../../..//logging/ConsoleLogger';
import { InMemoryDriverRepository } from '@adapters/racing/persistence/inmemory/InMemoryDriverRepository';
import { InMemoryRankingService } from '@adapters/racing/services/InMemoryRankingService';
import { InMemoryDriverStatsService } from '@adapters/racing/services/InMemoryDriverStatsService';
import { InMemoryDriverRatingProvider } from '@adapters/racing/ports/InMemoryDriverRatingProvider';
import { InMemoryImageServiceAdapter } from '@adapters/media/ports/InMemoryImageServiceAdapter';
import { InMemoryRaceRegistrationRepository } from '@adapters/racing/persistence/inmemory/InMemoryRaceRegistrationRepository';
import { InMemoryNotificationPreferenceRepository } from '@adapters/notifications/persistence/inmemory/InMemoryNotificationPreferenceRepository';
import { ConsoleLogger } from '@adapters/logging/ConsoleLogger';
// Define injection tokens
export const DRIVER_REPOSITORY_TOKEN = 'IDriverRepository';
@@ -44,8 +43,6 @@ export const GET_DRIVERS_LEADERBOARD_USE_CASE_TOKEN = 'GetDriversLeaderboardUseC
export const GET_TOTAL_DRIVERS_USE_CASE_TOKEN = 'GetTotalDriversUseCase';
export const COMPLETE_DRIVER_ONBOARDING_USE_CASE_TOKEN = 'CompleteDriverOnboardingUseCase';
export const IS_DRIVER_REGISTERED_FOR_RACE_USE_CASE_TOKEN = 'IsDriverRegisteredForRaceUseCase';
export const GET_PROFILE_OVERVIEW_USE_CASE_TOKEN = 'GetProfileOverviewUseCase';
export const GET_DRIVER_TEAM_USE_CASE_TOKEN = 'GetDriverTeamUseCase';
export const UPDATE_DRIVER_PROFILE_USE_CASE_TOKEN = 'UpdateDriverProfileUseCase';
export const DriverProviders: Provider[] = [
@@ -92,14 +89,14 @@ export const DriverProviders: Provider[] = [
// Use cases
{
provide: GET_DRIVERS_LEADERBOARD_USE_CASE_TOKEN,
useFactory: (driverRepo: IDriverRepository, rankingService: IRankingService, driverStatsService: IDriverStatsService, imageService: IImageServicePort) =>
new GetDriversLeaderboardUseCase(driverRepo, rankingService, driverStatsService, imageService),
inject: [DRIVER_REPOSITORY_TOKEN, RANKING_SERVICE_TOKEN, DRIVER_STATS_SERVICE_TOKEN, IMAGE_SERVICE_PORT_TOKEN],
useFactory: (driverRepo: IDriverRepository, rankingService: IRankingService, driverStatsService: IDriverStatsService, imageService: IImageServicePort, logger: Logger) =>
new GetDriversLeaderboardUseCase(driverRepo, rankingService, driverStatsService, imageService, logger),
inject: [DRIVER_REPOSITORY_TOKEN, RANKING_SERVICE_TOKEN, DRIVER_STATS_SERVICE_TOKEN, IMAGE_SERVICE_PORT_TOKEN, LOGGER_TOKEN],
},
{
provide: GET_TOTAL_DRIVERS_USE_CASE_TOKEN,
useFactory: (driverRepo: IDriverRepository) => new GetTotalDriversUseCase(driverRepo),
inject: [DRIVER_REPOSITORY_TOKEN],
useFactory: (driverRepo: IDriverRepository, logger: Logger) => new GetTotalDriversUseCase(driverRepo, logger),
inject: [DRIVER_REPOSITORY_TOKEN, LOGGER_TOKEN],
},
{
provide: COMPLETE_DRIVER_ONBOARDING_USE_CASE_TOKEN,
@@ -108,8 +105,8 @@ export const DriverProviders: Provider[] = [
},
{
provide: IS_DRIVER_REGISTERED_FOR_RACE_USE_CASE_TOKEN,
useFactory: (registrationRepo: IRaceRegistrationRepository) => new IsDriverRegisteredForRaceUseCase(registrationRepo),
inject: [RACE_REGISTRATION_REPOSITORY_TOKEN],
useFactory: (registrationRepo: IRaceRegistrationRepository, logger: Logger) => new IsDriverRegisteredForRaceUseCase(registrationRepo, logger),
inject: [RACE_REGISTRATION_REPOSITORY_TOKEN, LOGGER_TOKEN],
},
{
provide: UPDATE_DRIVER_PROFILE_USE_CASE_TOKEN,

View File

@@ -1,18 +1,23 @@
import { Test, TestingModule } from '@nestjs/testing';
import { vi } from 'vitest';
import { DriverService } from './DriverService';
import { GetDriversLeaderboardUseCase } from '@core/racing/application/use-cases/GetDriversLeaderboardUseCase';
import { GetTotalDriversUseCase } from '@core/racing/application/use-cases/GetTotalDriversUseCase';
import { CompleteDriverOnboardingUseCase } from '@core/racing/application/use-cases/CompleteDriverOnboardingUseCase';
import { IsDriverRegisteredForRaceUseCase } from '@core/racing/application/use-cases/IsDriverRegisteredForRaceUseCase';
import { UpdateDriverProfileUseCase } from '@core/racing/application/use-cases/UpdateDriverProfileUseCase';
import type { Logger } from '@core/shared/application';
import type { IDriverRepository } from '@core/racing/domain/repositories/IDriverRepository';
describe('DriverService', () => {
let service: DriverService;
let getDriversLeaderboardUseCase: jest.Mocked<GetDriversLeaderboardUseCase>;
let getTotalDriversUseCase: jest.Mocked<GetTotalDriversUseCase>;
let completeDriverOnboardingUseCase: jest.Mocked<CompleteDriverOnboardingUseCase>;
let isDriverRegisteredForRaceUseCase: jest.Mocked<IsDriverRegisteredForRaceUseCase>;
let logger: jest.Mocked<Logger>;
let getDriversLeaderboardUseCase: ReturnType<typeof vi.mocked<GetDriversLeaderboardUseCase>>;
let getTotalDriversUseCase: ReturnType<typeof vi.mocked<GetTotalDriversUseCase>>;
let completeDriverOnboardingUseCase: ReturnType<typeof vi.mocked<CompleteDriverOnboardingUseCase>>;
let isDriverRegisteredForRaceUseCase: ReturnType<typeof vi.mocked<IsDriverRegisteredForRaceUseCase>>;
let updateDriverProfileUseCase: ReturnType<typeof vi.mocked<UpdateDriverProfileUseCase>>;
let driverRepository: ReturnType<typeof vi.mocked<IDriverRepository>>;
let logger: ReturnType<typeof vi.mocked<Logger>>;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
@@ -21,42 +26,57 @@ describe('DriverService', () => {
{
provide: 'GetDriversLeaderboardUseCase',
useValue: {
execute: jest.fn(),
execute: vi.fn(),
},
},
{
provide: 'GetTotalDriversUseCase',
useValue: {
execute: jest.fn(),
execute: vi.fn(),
},
},
{
provide: 'CompleteDriverOnboardingUseCase',
useValue: {
execute: jest.fn(),
execute: vi.fn(),
},
},
{
provide: 'IsDriverRegisteredForRaceUseCase',
useValue: {
execute: jest.fn(),
execute: vi.fn(),
},
},
{
provide: 'UpdateDriverProfileUseCase',
useValue: {
execute: vi.fn(),
},
},
{
provide: 'IDriverRepository',
useValue: {
findById: vi.fn(),
},
},
{
provide: 'Logger',
useValue: {
debug: jest.fn(),
debug: vi.fn(),
error: vi.fn(),
},
},
],
}).compile();
service = module.get<DriverService>(DriverService);
getDriversLeaderboardUseCase = module.get('GetDriversLeaderboardUseCase');
getTotalDriversUseCase = module.get('GetTotalDriversUseCase');
completeDriverOnboardingUseCase = module.get('CompleteDriverOnboardingUseCase');
isDriverRegisteredForRaceUseCase = module.get('IsDriverRegisteredForRaceUseCase');
logger = module.get('Logger');
getDriversLeaderboardUseCase = vi.mocked(module.get('GetDriversLeaderboardUseCase'));
getTotalDriversUseCase = vi.mocked(module.get('GetTotalDriversUseCase'));
completeDriverOnboardingUseCase = vi.mocked(module.get('CompleteDriverOnboardingUseCase'));
isDriverRegisteredForRaceUseCase = vi.mocked(module.get('IsDriverRegisteredForRaceUseCase'));
updateDriverProfileUseCase = vi.mocked(module.get('UpdateDriverProfileUseCase'));
driverRepository = vi.mocked(module.get('IDriverRepository'));
logger = vi.mocked(module.get('Logger'));
});
describe('getDriversLeaderboard', () => {

View File

@@ -143,7 +143,12 @@ export class DriverProfileSocialSummaryDTO {
export type DriverProfileSocialPlatform = 'twitter' | 'youtube' | 'twitch' | 'discord';
export type DriverProfileAchievementRarity = 'common' | 'rare' | 'epic' | 'legendary';
export enum DriverProfileAchievementRarity {
COMMON = 'common',
RARE = 'rare',
EPIC = 'epic',
LEGENDARY = 'legendary',
}
export class DriverProfileAchievementDTO {
@ApiProperty()