module cleanup
This commit is contained in:
45
apps/api/src/domain/dashboard/DashboardController.test.ts
Normal file
45
apps/api/src/domain/dashboard/DashboardController.test.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { vi } from 'vitest';
|
||||
import { DashboardController } from './DashboardController';
|
||||
import { DashboardService } from './DashboardService';
|
||||
import { DashboardOverviewDTO } from './dtos/DashboardOverviewDTO';
|
||||
|
||||
describe('DashboardController', () => {
|
||||
let controller: DashboardController;
|
||||
let mockService: { getDashboardOverview: ReturnType<typeof vi.fn> };
|
||||
|
||||
beforeEach(() => {
|
||||
mockService = {
|
||||
getDashboardOverview: vi.fn(),
|
||||
};
|
||||
|
||||
controller = new DashboardController(mockService as any);
|
||||
});
|
||||
|
||||
describe('getDashboardOverview', () => {
|
||||
it('should call service.getDashboardOverview and return overview', async () => {
|
||||
const driverId = 'driver-123';
|
||||
const overview: DashboardOverviewDTO = {
|
||||
currentDriver: null,
|
||||
myUpcomingRaces: [],
|
||||
otherUpcomingRaces: [],
|
||||
upcomingRaces: [],
|
||||
activeLeaguesCount: 5,
|
||||
nextRace: null,
|
||||
recentResults: [],
|
||||
leagueStandingsSummaries: [],
|
||||
feedSummary: {
|
||||
notificationCount: 0,
|
||||
items: [],
|
||||
},
|
||||
friends: [],
|
||||
};
|
||||
mockService.getDashboardOverview.mockResolvedValue(overview);
|
||||
|
||||
const result = await controller.getDashboardOverview(driverId);
|
||||
|
||||
expect(mockService.getDashboardOverview).toHaveBeenCalledWith(driverId);
|
||||
expect(result).toEqual(overview);
|
||||
});
|
||||
});
|
||||
});
|
||||
30
apps/api/src/domain/dashboard/DashboardModule.test.ts
Normal file
30
apps/api/src/domain/dashboard/DashboardModule.test.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { DashboardModule } from './DashboardModule';
|
||||
import { DashboardController } from './DashboardController';
|
||||
import { DashboardService } from './DashboardService';
|
||||
|
||||
describe('DashboardModule', () => {
|
||||
let module: TestingModule;
|
||||
|
||||
beforeEach(async () => {
|
||||
module = await Test.createTestingModule({
|
||||
imports: [DashboardModule],
|
||||
}).compile();
|
||||
});
|
||||
|
||||
it('should compile the module', () => {
|
||||
expect(module).toBeDefined();
|
||||
});
|
||||
|
||||
it('should provide DashboardController', () => {
|
||||
const controller = module.get<DashboardController>(DashboardController);
|
||||
expect(controller).toBeDefined();
|
||||
expect(controller).toBeInstanceOf(DashboardController);
|
||||
});
|
||||
|
||||
it('should provide DashboardService', () => {
|
||||
const service = module.get<DashboardService>(DashboardService);
|
||||
expect(service).toBeDefined();
|
||||
expect(service).toBeInstanceOf(DashboardService);
|
||||
});
|
||||
});
|
||||
@@ -5,7 +5,7 @@ import { DashboardProviders } from './DashboardProviders';
|
||||
|
||||
@Module({
|
||||
controllers: [DashboardController],
|
||||
providers: DashboardProviders,
|
||||
providers: [DashboardService, ...DashboardProviders],
|
||||
exports: [DashboardService],
|
||||
})
|
||||
export class DashboardModule {}
|
||||
@@ -3,21 +3,114 @@ import { DashboardService } from './DashboardService';
|
||||
|
||||
// Import core interfaces
|
||||
import type { Logger } from '@core/shared/application/Logger';
|
||||
import { IDriverRepository } from '@core/racing/domain/repositories/IDriverRepository';
|
||||
import { IRaceRepository } from '@core/racing/domain/repositories/IRaceRepository';
|
||||
import { IResultRepository } from '@core/racing/domain/repositories/IResultRepository';
|
||||
import { ILeagueRepository } from '@core/racing/domain/repositories/ILeagueRepository';
|
||||
import { IStandingRepository } from '@core/racing/domain/repositories/IStandingRepository';
|
||||
import { ILeagueMembershipRepository } from '@core/racing/domain/repositories/ILeagueMembershipRepository';
|
||||
import { IRaceRegistrationRepository } from '@core/racing/domain/repositories/IRaceRegistrationRepository';
|
||||
import { IFeedRepository } from '@core/social/domain/repositories/IFeedRepository';
|
||||
import { ISocialGraphRepository } from '@core/social/domain/repositories/ISocialGraphRepository';
|
||||
import { IImageServicePort } from '@core/racing/application/ports/IImageServicePort';
|
||||
|
||||
// Import concrete implementations
|
||||
import { ConsoleLogger } from '@adapters/logging/ConsoleLogger';
|
||||
import { InMemoryDriverRepository } from '@adapters/racing/persistence/inmemory/InMemoryDriverRepository';
|
||||
import { InMemoryRaceRepository } from '@adapters/racing/persistence/inmemory/InMemoryRaceRepository';
|
||||
import { InMemoryResultRepository } from '@adapters/racing/persistence/inmemory/InMemoryResultRepository';
|
||||
import { InMemoryLeagueRepository } from '@adapters/racing/persistence/inmemory/InMemoryLeagueRepository';
|
||||
import { InMemoryStandingRepository } from '@adapters/racing/persistence/inmemory/InMemoryStandingRepository';
|
||||
import { InMemoryLeagueMembershipRepository } from '@adapters/racing/persistence/inmemory/InMemoryLeagueMembershipRepository';
|
||||
import { InMemoryRaceRegistrationRepository } from '@adapters/racing/persistence/inmemory/InMemoryRaceRegistrationRepository';
|
||||
import { InMemoryImageServiceAdapter } from '@adapters/media/ports/InMemoryImageServiceAdapter';
|
||||
|
||||
// Import use cases
|
||||
import { DashboardOverviewUseCase } from '@core/racing/application/use-cases/DashboardOverviewUseCase';
|
||||
// Simple mock implementations for missing adapters
|
||||
class MockFeedRepository implements IFeedRepository {
|
||||
async getFeedForDriver(driverId: string, limit?: number) {
|
||||
return [];
|
||||
}
|
||||
async getGlobalFeed(limit?: number) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
class MockSocialGraphRepository implements ISocialGraphRepository {
|
||||
async getFriends(driverId: string) {
|
||||
return [];
|
||||
}
|
||||
async getFriendIds(driverId: string) {
|
||||
return [];
|
||||
}
|
||||
async getSuggestedFriends(driverId: string, limit?: number) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// Define injection tokens
|
||||
export const LOGGER_TOKEN = 'Logger';
|
||||
export const DRIVER_REPOSITORY_TOKEN = 'IDriverRepository';
|
||||
export const RACE_REPOSITORY_TOKEN = 'IRaceRepository';
|
||||
export const RESULT_REPOSITORY_TOKEN = 'IResultRepository';
|
||||
export const LEAGUE_REPOSITORY_TOKEN = 'ILeagueRepository';
|
||||
export const STANDING_REPOSITORY_TOKEN = 'IStandingRepository';
|
||||
export const LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN = 'ILeagueMembershipRepository';
|
||||
export const RACE_REGISTRATION_REPOSITORY_TOKEN = 'IRaceRegistrationRepository';
|
||||
export const FEED_REPOSITORY_TOKEN = 'IFeedRepository';
|
||||
export const SOCIAL_GRAPH_REPOSITORY_TOKEN = 'ISocialGraphRepository';
|
||||
export const IMAGE_SERVICE_TOKEN = 'IImageServicePort';
|
||||
|
||||
export const DashboardProviders: Provider[] = [
|
||||
DashboardService,
|
||||
{
|
||||
provide: LOGGER_TOKEN,
|
||||
useClass: ConsoleLogger,
|
||||
},
|
||||
DashboardOverviewUseCase,
|
||||
{
|
||||
provide: DRIVER_REPOSITORY_TOKEN,
|
||||
useFactory: (logger: Logger) => new InMemoryDriverRepository(logger),
|
||||
inject: [LOGGER_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: RACE_REPOSITORY_TOKEN,
|
||||
useFactory: (logger: Logger) => new InMemoryRaceRepository(logger),
|
||||
inject: [LOGGER_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: RESULT_REPOSITORY_TOKEN,
|
||||
useFactory: (logger: Logger) => new InMemoryResultRepository(logger),
|
||||
inject: [LOGGER_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: LEAGUE_REPOSITORY_TOKEN,
|
||||
useFactory: (logger: Logger) => new InMemoryLeagueRepository(logger),
|
||||
inject: [LOGGER_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: STANDING_REPOSITORY_TOKEN,
|
||||
useFactory: (logger: Logger) => new InMemoryStandingRepository(logger, {}),
|
||||
inject: [LOGGER_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN,
|
||||
useFactory: (logger: Logger) => new InMemoryLeagueMembershipRepository(logger),
|
||||
inject: [LOGGER_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: RACE_REGISTRATION_REPOSITORY_TOKEN,
|
||||
useFactory: (logger: Logger) => new InMemoryRaceRegistrationRepository(logger),
|
||||
inject: [LOGGER_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: FEED_REPOSITORY_TOKEN,
|
||||
useFactory: () => new MockFeedRepository(),
|
||||
},
|
||||
{
|
||||
provide: SOCIAL_GRAPH_REPOSITORY_TOKEN,
|
||||
useFactory: () => new MockSocialGraphRepository(),
|
||||
},
|
||||
{
|
||||
provide: IMAGE_SERVICE_TOKEN,
|
||||
useFactory: (logger: Logger) => new InMemoryImageServiceAdapter(logger),
|
||||
inject: [LOGGER_TOKEN],
|
||||
},
|
||||
];
|
||||
@@ -1,28 +1,76 @@
|
||||
import { Injectable, Inject } from '@nestjs/common';
|
||||
import { DashboardOverviewUseCase } from '@core/racing/application/use-cases/DashboardOverviewUseCase';
|
||||
import type { DashboardOverviewViewModel } from '@core/racing/application/presenters/IDashboardOverviewPresenter';
|
||||
|
||||
// Core imports
|
||||
import type { Logger } from '@core/shared/application/Logger';
|
||||
import type { IDriverRepository } from '@core/racing/domain/repositories/IDriverRepository';
|
||||
import type { IRaceRepository } from '@core/racing/domain/repositories/IRaceRepository';
|
||||
import type { IResultRepository } from '@core/racing/domain/repositories/IResultRepository';
|
||||
import type { ILeagueRepository } from '@core/racing/domain/repositories/ILeagueRepository';
|
||||
import type { IStandingRepository } from '@core/racing/domain/repositories/IStandingRepository';
|
||||
import type { ILeagueMembershipRepository } from '@core/racing/domain/repositories/ILeagueMembershipRepository';
|
||||
import type { IRaceRegistrationRepository } from '@core/racing/domain/repositories/IRaceRegistrationRepository';
|
||||
import type { IFeedRepository } from '@core/social/domain/repositories/IFeedRepository';
|
||||
import type { ISocialGraphRepository } from '@core/social/domain/repositories/ISocialGraphRepository';
|
||||
import type { IImageServicePort } from '@core/racing/application/ports/IImageServicePort';
|
||||
|
||||
// Tokens
|
||||
import { LOGGER_TOKEN } from './DashboardProviders';
|
||||
import {
|
||||
LOGGER_TOKEN,
|
||||
DRIVER_REPOSITORY_TOKEN,
|
||||
RACE_REPOSITORY_TOKEN,
|
||||
RESULT_REPOSITORY_TOKEN,
|
||||
LEAGUE_REPOSITORY_TOKEN,
|
||||
STANDING_REPOSITORY_TOKEN,
|
||||
LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN,
|
||||
RACE_REGISTRATION_REPOSITORY_TOKEN,
|
||||
FEED_REPOSITORY_TOKEN,
|
||||
SOCIAL_GRAPH_REPOSITORY_TOKEN,
|
||||
IMAGE_SERVICE_TOKEN,
|
||||
} from './DashboardProviders';
|
||||
|
||||
@Injectable()
|
||||
export class DashboardService {
|
||||
constructor(
|
||||
private readonly dashboardOverviewUseCase: DashboardOverviewUseCase,
|
||||
@Inject(LOGGER_TOKEN) private readonly logger: Logger,
|
||||
) {}
|
||||
private readonly dashboardOverviewUseCase: DashboardOverviewUseCase;
|
||||
|
||||
async getDashboardOverview(driverId: string): Promise<any> {
|
||||
constructor(
|
||||
@Inject(LOGGER_TOKEN) private readonly logger: Logger,
|
||||
@Inject(DRIVER_REPOSITORY_TOKEN) private readonly driverRepository?: IDriverRepository,
|
||||
@Inject(RACE_REPOSITORY_TOKEN) private readonly raceRepository?: IRaceRepository,
|
||||
@Inject(RESULT_REPOSITORY_TOKEN) private readonly resultRepository?: IResultRepository,
|
||||
@Inject(LEAGUE_REPOSITORY_TOKEN) private readonly leagueRepository?: ILeagueRepository,
|
||||
@Inject(STANDING_REPOSITORY_TOKEN) private readonly standingRepository?: IStandingRepository,
|
||||
@Inject(LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN) private readonly leagueMembershipRepository?: ILeagueMembershipRepository,
|
||||
@Inject(RACE_REGISTRATION_REPOSITORY_TOKEN) private readonly raceRegistrationRepository?: IRaceRegistrationRepository,
|
||||
@Inject(FEED_REPOSITORY_TOKEN) private readonly feedRepository?: IFeedRepository,
|
||||
@Inject(SOCIAL_GRAPH_REPOSITORY_TOKEN) private readonly socialRepository?: ISocialGraphRepository,
|
||||
@Inject(IMAGE_SERVICE_TOKEN) private readonly imageService?: IImageServicePort,
|
||||
) {
|
||||
this.dashboardOverviewUseCase = new DashboardOverviewUseCase(
|
||||
driverRepository,
|
||||
raceRepository,
|
||||
resultRepository,
|
||||
leagueRepository,
|
||||
standingRepository,
|
||||
leagueMembershipRepository,
|
||||
raceRegistrationRepository,
|
||||
feedRepository,
|
||||
socialRepository,
|
||||
imageService,
|
||||
() => null, // getDriverStats
|
||||
);
|
||||
}
|
||||
|
||||
async getDashboardOverview(driverId: string): Promise<DashboardOverviewViewModel> {
|
||||
this.logger.debug('[DashboardService] Getting dashboard overview:', { driverId });
|
||||
|
||||
const result = await this.dashboardOverviewUseCase.execute({ driverId });
|
||||
|
||||
if (result.isErr()) {
|
||||
throw new Error(result.error.details.message || 'Failed to get dashboard overview');
|
||||
throw new Error(result.error?.message || 'Failed to get dashboard overview');
|
||||
}
|
||||
|
||||
return result.value;
|
||||
return result.value!;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsNumber, IsOptional } from 'class-validator';
|
||||
import { DashboardDriverSummaryDTO } from '../../../race/dtos/DashboardDriverSummaryDTO';
|
||||
import { DashboardRaceSummaryDTO } from '../../../race/dtos/DashboardRaceSummaryDTO';
|
||||
import { DashboardRecentResultDTO } from '../../../race/dtos/DashboardRecentResultDTO';
|
||||
import { DashboardLeagueStandingSummaryDTO } from '../../../race/dtos/DashboardLeagueStandingSummaryDTO';
|
||||
import { DashboardFeedSummaryDTO } from '../../../race/dtos/DashboardFeedSummaryDTO';
|
||||
import { DashboardFriendSummaryDTO } from '../../../race/dtos/DashboardFriendSummaryDTO';
|
||||
import { IsNumber } from 'class-validator';
|
||||
import { DashboardDriverSummaryDTO } from './DashboardDriverSummaryDTO';
|
||||
import { DashboardRaceSummaryDTO } from './DashboardRaceSummaryDTO';
|
||||
import { DashboardRecentResultDTO } from './DashboardRecentResultDTO';
|
||||
import { DashboardLeagueStandingSummaryDTO } from './DashboardLeagueStandingSummaryDTO';
|
||||
import { DashboardFeedSummaryDTO } from './DashboardFeedSummaryDTO';
|
||||
import { DashboardFriendSummaryDTO } from './DashboardFriendSummaryDTO';
|
||||
|
||||
export class DashboardOverviewDTO {
|
||||
@ApiProperty({ nullable: true })
|
||||
|
||||
Reference in New Issue
Block a user