193 lines
5.6 KiB
TypeScript
193 lines
5.6 KiB
TypeScript
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
import { GetDriversLeaderboardUseCase } from './GetDriversLeaderboardUseCase';
|
|
import type { IDriverRepository } from '../../domain/repositories/IDriverRepository';
|
|
import type { IRankingService } from '../../domain/services/IRankingService';
|
|
import type { IDriverStatsService } from '../../domain/services/IDriverStatsService';
|
|
import type { Logger } from '@core/shared/application';
|
|
|
|
describe('GetDriversLeaderboardUseCase', () => {
|
|
const mockDriverFindAll = vi.fn();
|
|
const mockDriverRepo: IDriverRepository = {
|
|
findById: vi.fn(),
|
|
findAll: mockDriverFindAll,
|
|
create: vi.fn(),
|
|
update: vi.fn(),
|
|
delete: vi.fn(),
|
|
exists: vi.fn(),
|
|
};
|
|
|
|
const mockRankingGetAllDriverRankings = vi.fn();
|
|
const mockRankingService: IRankingService = {
|
|
getAllDriverRankings: mockRankingGetAllDriverRankings,
|
|
};
|
|
|
|
const mockDriverStatsGetDriverStats = vi.fn();
|
|
const mockDriverStatsService: IDriverStatsService = {
|
|
getDriverStats: mockDriverStatsGetDriverStats,
|
|
};
|
|
|
|
const mockGetDriverAvatar = vi.fn();
|
|
const mockLogger: Logger = {
|
|
debug: vi.fn(),
|
|
info: vi.fn(),
|
|
warn: vi.fn(),
|
|
error: vi.fn(),
|
|
};
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it('should return drivers leaderboard data', async () => {
|
|
const useCase = new GetDriversLeaderboardUseCase(
|
|
mockDriverRepo,
|
|
mockRankingService,
|
|
mockDriverStatsService,
|
|
mockGetDriverAvatar,
|
|
mockLogger,
|
|
);
|
|
|
|
const driver1 = { id: 'driver1', name: { value: 'Driver One' }, country: { value: 'US' } };
|
|
const driver2 = { id: 'driver2', name: { value: 'Driver Two' }, country: { value: 'US' } };
|
|
const rankings = [
|
|
{ driverId: 'driver1', rating: 2500, overallRank: 1 },
|
|
{ driverId: 'driver2', rating: 2400, overallRank: 2 },
|
|
];
|
|
const stats1 = { totalRaces: 10, wins: 5, podiums: 7 };
|
|
const stats2 = { totalRaces: 8, wins: 3, podiums: 4 };
|
|
|
|
mockDriverFindAll.mockResolvedValue([driver1, driver2]);
|
|
mockRankingGetAllDriverRankings.mockReturnValue(rankings);
|
|
mockDriverStatsGetDriverStats.mockImplementation((id) => {
|
|
if (id === 'driver1') return stats1;
|
|
if (id === 'driver2') return stats2;
|
|
return null;
|
|
});
|
|
mockGetDriverAvatar.mockImplementation((input) => {
|
|
if (input.driverId === 'driver1') return Promise.resolve({ avatarUrl: 'avatar-driver1' });
|
|
if (input.driverId === 'driver2') return Promise.resolve({ avatarUrl: 'avatar-driver2' });
|
|
return Promise.resolve({ avatarUrl: 'avatar-default' });
|
|
});
|
|
|
|
const result = await useCase.execute();
|
|
|
|
expect(result.isOk()).toBe(true);
|
|
expect(result.value).toEqual({
|
|
drivers: [
|
|
{
|
|
id: 'driver1',
|
|
name: 'Driver One',
|
|
rating: 2500,
|
|
skillLevel: 'Pro',
|
|
nationality: 'US',
|
|
racesCompleted: 10,
|
|
wins: 5,
|
|
podiums: 7,
|
|
isActive: true,
|
|
rank: 1,
|
|
avatarUrl: 'avatar-driver1',
|
|
},
|
|
{
|
|
id: 'driver2',
|
|
name: 'Driver Two',
|
|
rating: 2400,
|
|
skillLevel: 'Pro',
|
|
nationality: 'US',
|
|
racesCompleted: 8,
|
|
wins: 3,
|
|
podiums: 4,
|
|
isActive: true,
|
|
rank: 2,
|
|
avatarUrl: 'avatar-driver2',
|
|
},
|
|
],
|
|
totalRaces: 18,
|
|
totalWins: 8,
|
|
activeCount: 2,
|
|
});
|
|
});
|
|
|
|
it('should return empty result when no drivers', async () => {
|
|
const useCase = new GetDriversLeaderboardUseCase(
|
|
mockDriverRepo,
|
|
mockRankingService,
|
|
mockDriverStatsService,
|
|
mockGetDriverAvatar,
|
|
mockLogger,
|
|
);
|
|
|
|
mockDriverFindAll.mockResolvedValue([]);
|
|
mockRankingGetAllDriverRankings.mockReturnValue([]);
|
|
|
|
const result = await useCase.execute();
|
|
|
|
expect(result.isOk()).toBe(true);
|
|
expect(result.value).toEqual({
|
|
drivers: [],
|
|
totalRaces: 0,
|
|
totalWins: 0,
|
|
activeCount: 0,
|
|
});
|
|
});
|
|
|
|
it('should handle drivers without stats', async () => {
|
|
const useCase = new GetDriversLeaderboardUseCase(
|
|
mockDriverRepo,
|
|
mockRankingService,
|
|
mockDriverStatsService,
|
|
mockGetDriverAvatar,
|
|
mockLogger,
|
|
);
|
|
|
|
const driver1 = { id: 'driver1', name: { value: 'Driver One' }, country: { value: 'US' } };
|
|
const rankings = [{ driverId: 'driver1', rating: 2500, overallRank: 1 }];
|
|
|
|
mockDriverFindAll.mockResolvedValue([driver1]);
|
|
mockRankingGetAllDriverRankings.mockReturnValue(rankings);
|
|
mockDriverStatsGetDriverStats.mockReturnValue(null);
|
|
mockGetDriverAvatar.mockResolvedValue({ avatarUrl: 'avatar-driver1' });
|
|
|
|
const result = await useCase.execute();
|
|
|
|
expect(result.isOk()).toBe(true);
|
|
expect(result.value).toEqual({
|
|
drivers: [
|
|
{
|
|
id: 'driver1',
|
|
name: 'Driver One',
|
|
rating: 2500,
|
|
skillLevel: 'Pro',
|
|
nationality: 'US',
|
|
racesCompleted: 0,
|
|
wins: 0,
|
|
podiums: 0,
|
|
isActive: true,
|
|
rank: 1,
|
|
avatarUrl: 'avatar-driver1',
|
|
},
|
|
],
|
|
totalRaces: 0,
|
|
totalWins: 0,
|
|
activeCount: 1,
|
|
});
|
|
});
|
|
|
|
it('should return error when repository throws', async () => {
|
|
const useCase = new GetDriversLeaderboardUseCase(
|
|
mockDriverRepo,
|
|
mockRankingService,
|
|
mockDriverStatsService,
|
|
mockGetDriverAvatar,
|
|
mockLogger,
|
|
);
|
|
|
|
const error = new Error('Repository error');
|
|
mockDriverFindAll.mockRejectedValue(error);
|
|
|
|
const result = await useCase.execute();
|
|
|
|
expect(result.isErr()).toBe(true);
|
|
expect(result.unwrapErr().code).toBe('REPOSITORY_ERROR');
|
|
expect(result.unwrapErr().details.message).toBe('Repository error');
|
|
});
|
|
}); |