Files
gridpilot.gg/core/racing/application/use-cases/GetTeamsLeaderboardUseCase.test.ts
2025-12-16 21:05:01 +01:00

135 lines
4.2 KiB
TypeScript

import { describe, it, expect, beforeEach, vi, Mock } from 'vitest';
import { GetTeamsLeaderboardUseCase } from './GetTeamsLeaderboardUseCase';
import { ITeamRepository } from '../../domain/repositories/ITeamRepository';
import { ITeamMembershipRepository } from '../../domain/repositories/ITeamMembershipRepository';
import { IDriverRepository } from '../../domain/repositories/IDriverRepository';
import { Team } from '../../domain/entities/Team';
import type { Logger } from '@core/shared/application';
describe('GetTeamsLeaderboardUseCase', () => {
let useCase: GetTeamsLeaderboardUseCase;
let teamRepository: {
findAll: Mock;
};
let teamMembershipRepository: {
getTeamMembers: Mock;
};
let driverRepository: {
findById: Mock;
};
let getDriverStats: Mock;
let logger: {
debug: Mock;
info: Mock;
warn: Mock;
error: Mock;
};
beforeEach(() => {
teamRepository = {
findAll: vi.fn(),
};
teamMembershipRepository = {
getTeamMembers: vi.fn(),
};
driverRepository = {
findById: vi.fn(),
};
getDriverStats = vi.fn();
logger = {
debug: vi.fn(),
info: vi.fn(),
warn: vi.fn(),
error: vi.fn(),
};
useCase = new GetTeamsLeaderboardUseCase(
teamRepository as unknown as ITeamRepository,
teamMembershipRepository as unknown as ITeamMembershipRepository,
driverRepository as unknown as IDriverRepository,
getDriverStats,
logger as unknown as Logger,
);
});
it('should return teams leaderboard with calculated stats', async () => {
const team1 = Team.create({
id: 'team-1',
name: 'Team Alpha',
tag: 'TA',
description: 'Description 1',
ownerId: 'owner-1',
leagues: [],
});
const team2 = Team.create({
id: 'team-2',
name: 'Team Beta',
tag: 'TB',
description: 'Description 2',
ownerId: 'owner-2',
leagues: [],
});
const memberships1 = [
{ teamId: 'team-1', driverId: 'driver-1', role: 'driver' as const, status: 'active' as const, joinedAt: new Date() },
{ teamId: 'team-1', driverId: 'driver-2', role: 'driver' as const, status: 'active' as const, joinedAt: new Date() },
];
const memberships2 = [
{ teamId: 'team-2', driverId: 'driver-3', role: 'driver' as const, status: 'active' as const, joinedAt: new Date() },
];
teamRepository.findAll.mockResolvedValue([team1, team2]);
teamMembershipRepository.getTeamMembers.mockImplementation((teamId: string) => {
if (teamId === 'team-1') return Promise.resolve(memberships1);
if (teamId === 'team-2') return Promise.resolve(memberships2);
return Promise.resolve([]);
});
getDriverStats.mockImplementation((driverId: string) => {
if (driverId === 'driver-1') return { rating: 1500, wins: 5, totalRaces: 10 };
if (driverId === 'driver-2') return { rating: 1600, wins: 3, totalRaces: 8 };
if (driverId === 'driver-3') return { rating: null, wins: 2, totalRaces: 5 };
return null;
});
const result = await useCase.execute();
expect(result.isOk()).toBe(true);
const data = result.unwrap();
expect(data.recruitingCount).toBe(2); // both teams are recruiting
expect(data.teams).toHaveLength(2);
expect(data.teams[0]).toMatchObject({
id: 'team-1',
name: 'Team Alpha',
memberCount: 2,
rating: 1550, // (1500 + 1600) / 2
totalWins: 8,
totalRaces: 18,
performanceLevel: expect.any(String),
isRecruiting: true,
description: 'Description 1',
});
expect(data.teams[1]).toMatchObject({
id: 'team-2',
name: 'Team Beta',
memberCount: 1,
rating: null,
totalWins: 2,
totalRaces: 5,
performanceLevel: expect.any(String),
isRecruiting: true,
description: 'Description 2',
});
});
it('should return error on repository failure', async () => {
const error = new Error('Repository error');
teamRepository.findAll.mockRejectedValue(error);
const result = await useCase.execute();
expect(result.isErr()).toBe(true);
expect(result.unwrapErr()).toEqual({
code: 'REPOSITORY_ERROR',
details: { message: 'Failed to retrieve teams leaderboard' },
});
});
});