refactor racing use cases

This commit is contained in:
2025-12-21 00:43:42 +01:00
parent e9d6f90bb2
commit c12656d671
308 changed files with 14401 additions and 7419 deletions

View File

@@ -1,9 +1,18 @@
import { describe, it, expect, beforeEach, vi, Mock } from 'vitest';
import { GetTeamMembersUseCase } from './GetTeamMembersUseCase';
import { describe, it, expect, beforeEach, vi, type Mock } from 'vitest';
import {
GetTeamMembersUseCase,
type GetTeamMembersInput,
type GetTeamMembersResult,
type GetTeamMembersErrorCode,
} from './GetTeamMembersUseCase';
import { ITeamMembershipRepository } from '../../domain/repositories/ITeamMembershipRepository';
import { IDriverRepository } from '../../domain/repositories/IDriverRepository';
import { ITeamRepository } from '../../domain/repositories/ITeamRepository';
import { Driver } from '../../domain/entities/Driver';
import { Team } from '../../domain/entities/Team';
import type { Logger } from '@core/shared/application';
import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
describe('GetTeamMembersUseCase', () => {
let useCase: GetTeamMembersUseCase;
@@ -13,13 +22,16 @@ describe('GetTeamMembersUseCase', () => {
let driverRepository: {
findById: Mock;
};
let getDriverAvatar: Mock;
let teamRepository: {
findById: Mock;
};
let logger: {
debug: Mock;
info: Mock;
warn: Mock;
error: Mock;
};
let output: UseCaseOutputPort<GetTeamMembersResult> & { present: Mock };
beforeEach(() => {
membershipRepository = {
@@ -28,33 +40,52 @@ describe('GetTeamMembersUseCase', () => {
driverRepository = {
findById: vi.fn(),
};
getDriverAvatar = vi.fn();
teamRepository = {
findById: vi.fn(),
};
logger = {
debug: vi.fn(),
info: vi.fn(),
warn: vi.fn(),
error: vi.fn(),
};
output = {
present: vi.fn(),
} as unknown as UseCaseOutputPort<GetTeamMembersResult> & { present: Mock };
useCase = new GetTeamMembersUseCase(
membershipRepository as unknown as ITeamMembershipRepository,
driverRepository as unknown as IDriverRepository,
getDriverAvatar,
teamRepository as unknown as ITeamRepository,
logger as unknown as Logger,
output,
);
});
it('should return team members with driver names and avatar urls', async () => {
const teamId = 'team-1';
it('should return team members with driver entities', async () => {
const team = Team.create({
id: 'team-1',
name: 'Team Name',
tag: 'TAG',
description: 'Description',
ownerId: 'driver-1',
leagues: [],
});
const input: GetTeamMembersInput = { teamId: team.id };
const memberships = [
{ teamId, driverId: 'driver-1', role: 'owner' as const, status: 'active' as const, joinedAt: new Date() },
{ teamId, driverId: 'driver-2', role: 'driver' as const, status: 'active' as const, joinedAt: new Date() },
{ teamId: team.id, driverId: 'driver-1', role: 'owner' as const, status: 'active' as const, joinedAt: new Date() },
{ teamId: team.id, driverId: 'driver-2', role: 'driver' as const, status: 'active' as const, joinedAt: new Date() },
];
const driver1 = Driver.create({
id: 'driver-1',
iracingId: '123',
name: 'Driver 1',
country: 'US',
});
const driver2 = Driver.create({
id: 'driver-2',
iracingId: '456',
@@ -62,68 +93,109 @@ describe('GetTeamMembersUseCase', () => {
country: 'UK',
});
teamRepository.findById.mockResolvedValue(team);
membershipRepository.getTeamMembers.mockResolvedValue(memberships);
driverRepository.findById.mockImplementation((id: string) => {
if (id === 'driver-1') return Promise.resolve(driver1);
if (id === 'driver-2') return Promise.resolve(driver2);
return Promise.resolve(null);
});
getDriverAvatar.mockImplementation((input) => {
if (input.driverId === 'driver-1') return Promise.resolve({ avatarUrl: 'avatar-driver-1' });
if (input.driverId === 'driver-2') return Promise.resolve({ avatarUrl: 'avatar-driver-2' });
return Promise.resolve({ avatarUrl: 'avatar-default' });
});
const result = await useCase.execute({ teamId });
const result = await useCase.execute(input);
expect(result.isOk()).toBe(true);
expect(result.unwrap()).toEqual({
memberships,
driverNames: {
'driver-1': 'Driver 1',
'driver-2': 'Driver 2',
},
avatarUrls: {
'driver-1': 'avatar-driver-1',
'driver-2': 'avatar-driver-2',
},
});
expect(result.unwrap()).toBeUndefined();
expect(output.present).toHaveBeenCalledTimes(1);
const presented = output.present.mock.calls[0]?.[0] as GetTeamMembersResult;
expect(presented.team).toBe(team);
expect(presented.members).toHaveLength(2);
expect(presented.members[0]).toEqual({ membership: memberships[0], driver: driver1 });
expect(presented.members[1]).toEqual({ membership: memberships[1], driver: driver2 });
});
it('should handle driver not found', async () => {
const teamId = 'team-1';
const team = Team.create({
id: 'team-1',
name: 'Team Name',
tag: 'TAG',
description: 'Description',
ownerId: 'driver-1',
leagues: [],
});
const input: GetTeamMembersInput = { teamId: team.id };
const memberships = [
{ teamId, driverId: 'driver-1', role: 'owner' as const, status: 'active' as const, joinedAt: new Date() },
{ teamId: team.id, driverId: 'driver-1', role: 'owner' as const, status: 'active' as const, joinedAt: new Date() },
];
teamRepository.findById.mockResolvedValue(team);
membershipRepository.getTeamMembers.mockResolvedValue(memberships);
driverRepository.findById.mockResolvedValue(null);
getDriverAvatar.mockResolvedValue({ avatarUrl: 'avatar-driver-1' });
const result = await useCase.execute({ teamId });
const result = await useCase.execute(input);
expect(result.isOk()).toBe(true);
expect(result.unwrap()).toEqual({
memberships,
driverNames: {},
avatarUrls: {
'driver-1': 'avatar-driver-1',
},
});
expect(result.unwrap()).toBeUndefined();
expect(output.present).toHaveBeenCalledTimes(1);
const presented = output.present.mock.calls[0]?.[0] as GetTeamMembersResult;
expect(presented.team).toBe(team);
expect(presented.members).toEqual([
{ membership: memberships[0], driver: null },
]);
});
it('should return error on repository failure', async () => {
const teamId = 'team-1';
const error = new Error('Repository error');
it('should return TEAM_NOT_FOUND when team does not exist', async () => {
const input: GetTeamMembersInput = { teamId: 'missing-team' };
membershipRepository.getTeamMembers.mockRejectedValue(error);
teamRepository.findById.mockResolvedValue(null);
const result = await useCase.execute({ teamId });
const result = await useCase.execute(input);
expect(result.isErr()).toBe(true);
expect(result.unwrapErr()).toEqual({
code: 'REPOSITORY_ERROR',
details: { message: 'Failed to retrieve team members' },
});
const error = result.unwrapErr() as ApplicationErrorCode<
GetTeamMembersErrorCode,
{ message: string }
>;
expect(error.code).toBe('TEAM_NOT_FOUND');
expect(error.details.message).toBe('Team not found');
expect(output.present).not.toHaveBeenCalled();
});
});
it('should return REPOSITORY_ERROR when repository throws', async () => {
const team = Team.create({
id: 'team-1',
name: 'Team Name',
tag: 'TAG',
description: 'Description',
ownerId: 'driver-1',
leagues: [],
});
const input: GetTeamMembersInput = { teamId: team.id };
const error = new Error('Repository failure');
teamRepository.findById.mockResolvedValue(team);
membershipRepository.getTeamMembers.mockRejectedValue(error);
const result = await useCase.execute(input);
expect(result.isErr()).toBe(true);
const err = result.unwrapErr() as ApplicationErrorCode<
GetTeamMembersErrorCode,
{ message: string }
>;
expect(err.code).toBe('REPOSITORY_ERROR');
expect(err.details.message).toBe('Repository failure');
expect(output.present).not.toHaveBeenCalled();
});
});