wip
This commit is contained in:
@@ -1,6 +1,13 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
|
||||
import { GetDashboardOverviewUseCase } from '@gridpilot/racing/application/use-cases/GetDashboardOverviewUseCase';
|
||||
import { Driver } from '@gridpilot/racing/domain/entities/Driver';
|
||||
import { Race } from '@gridpilot/racing/domain/entities/Race';
|
||||
import { Result } from '@gridpilot/racing/domain/entities/Result';
|
||||
import { League } from '@gridpilot/racing/domain/entities/League';
|
||||
import { Standing } from '@gridpilot/racing/domain/entities/Standing';
|
||||
import { LeagueMembership } from '@gridpilot/racing/domain/entities/LeagueMembership';
|
||||
import type { FeedItem } from '@gridpilot/social/domain/types/FeedItem';
|
||||
import type {
|
||||
IDashboardOverviewPresenter,
|
||||
DashboardOverviewViewModel,
|
||||
@@ -25,11 +32,17 @@ class FakeDashboardOverviewPresenter implements IDashboardOverviewPresenter {
|
||||
|
||||
interface TestImageService {
|
||||
getDriverAvatar(driverId: string): string;
|
||||
getTeamLogo(teamId: string): string;
|
||||
getLeagueCover(leagueId: string): string;
|
||||
getLeagueLogo(leagueId: string): string;
|
||||
}
|
||||
|
||||
function createTestImageService(): TestImageService {
|
||||
return {
|
||||
getDriverAvatar: (driverId: string) => `avatar-${driverId}`,
|
||||
getTeamLogo: (teamId: string) => `team-logo-${teamId}`,
|
||||
getLeagueCover: (leagueId: string) => `league-cover-${leagueId}`,
|
||||
getLeagueLogo: (leagueId: string) => `league-logo-${leagueId}`,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -38,143 +51,173 @@ describe('GetDashboardOverviewUseCase', () => {
|
||||
// Given a driver with memberships in two leagues and future races with mixed registration
|
||||
const driverId = 'driver-1';
|
||||
|
||||
const driver = { id: driverId, name: 'Alice Racer', country: 'US' };
|
||||
const driver = Driver.create({ id: driverId, iracingId: '12345', name: 'Alice Racer', country: 'US' });
|
||||
|
||||
const leagues = [
|
||||
{ id: 'league-1', name: 'Alpha League' },
|
||||
{ id: 'league-2', name: 'Beta League' },
|
||||
League.create({ id: 'league-1', name: 'Alpha League', description: 'First league', ownerId: 'owner-1' }),
|
||||
League.create({ id: 'league-2', name: 'Beta League', description: 'Second league', ownerId: 'owner-2' }),
|
||||
];
|
||||
|
||||
const now = Date.now();
|
||||
|
||||
const races = [
|
||||
{
|
||||
Race.create({
|
||||
id: 'race-1',
|
||||
leagueId: 'league-1',
|
||||
track: 'Monza',
|
||||
car: 'GT3',
|
||||
scheduledAt: new Date(now + 60 * 60 * 1000),
|
||||
status: 'scheduled' as const,
|
||||
},
|
||||
{
|
||||
status: 'scheduled',
|
||||
}),
|
||||
Race.create({
|
||||
id: 'race-2',
|
||||
leagueId: 'league-1',
|
||||
track: 'Spa',
|
||||
car: 'GT3',
|
||||
scheduledAt: new Date(now + 2 * 60 * 60 * 1000),
|
||||
status: 'scheduled' as const,
|
||||
},
|
||||
{
|
||||
status: 'scheduled',
|
||||
}),
|
||||
Race.create({
|
||||
id: 'race-3',
|
||||
leagueId: 'league-2',
|
||||
track: 'Silverstone',
|
||||
car: 'GT4',
|
||||
scheduledAt: new Date(now + 3 * 60 * 60 * 1000),
|
||||
status: 'scheduled' as const,
|
||||
},
|
||||
{
|
||||
status: 'scheduled',
|
||||
}),
|
||||
Race.create({
|
||||
id: 'race-4',
|
||||
leagueId: 'league-2',
|
||||
track: 'Imola',
|
||||
car: 'GT4',
|
||||
scheduledAt: new Date(now + 4 * 60 * 60 * 1000),
|
||||
status: 'scheduled' as const,
|
||||
},
|
||||
status: 'scheduled',
|
||||
}),
|
||||
];
|
||||
|
||||
const results: unknown[] = [];
|
||||
const results: Result[] = [];
|
||||
|
||||
const memberships = [
|
||||
{
|
||||
LeagueMembership.create({
|
||||
leagueId: 'league-1',
|
||||
driverId,
|
||||
role: 'member',
|
||||
status: 'active',
|
||||
},
|
||||
{
|
||||
}),
|
||||
LeagueMembership.create({
|
||||
leagueId: 'league-2',
|
||||
driverId,
|
||||
role: 'member',
|
||||
status: 'active',
|
||||
},
|
||||
}),
|
||||
];
|
||||
|
||||
const registeredRaceIds = new Set<string>(['race-1', 'race-3']);
|
||||
|
||||
const feedItems: DashboardFeedItemSummaryViewModel[] = [];
|
||||
const friends: Array<{ id: string }> = [];
|
||||
const feedItems: FeedItem[] = [];
|
||||
const friends: Driver[] = [];
|
||||
|
||||
const driverRepository: {
|
||||
findById: (id: string) => Promise<{ id: string; name: string; country: string } | null>;
|
||||
} = {
|
||||
findById: async (id: string) => (id === driver.id ? driver : null),
|
||||
const driverRepository = {
|
||||
findById: async (id: string): Promise<Driver | null> => (id === driver.id ? driver : null),
|
||||
findByIRacingId: async (): Promise<Driver | null> => null,
|
||||
findAll: async (): Promise<Driver[]> => [],
|
||||
create: async (): Promise<Driver> => { throw new Error('Not implemented'); },
|
||||
update: async (): Promise<Driver> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
existsByIRacingId: async (): Promise<boolean> => false,
|
||||
};
|
||||
|
||||
const raceRepository: {
|
||||
findAll: () => Promise<
|
||||
Array<{
|
||||
id: string;
|
||||
leagueId: string;
|
||||
track: string;
|
||||
car: string;
|
||||
scheduledAt: Date;
|
||||
status: 'scheduled';
|
||||
}>
|
||||
>;
|
||||
} = {
|
||||
findAll: async () => races,
|
||||
const raceRepository = {
|
||||
findById: async (): Promise<Race | null> => null,
|
||||
findAll: async (): Promise<Race[]> => races,
|
||||
findByLeagueId: async (): Promise<Race[]> => [],
|
||||
findUpcomingByLeagueId: async (): Promise<Race[]> => [],
|
||||
findCompletedByLeagueId: async (): Promise<Race[]> => [],
|
||||
findByStatus: async (): Promise<Race[]> => [],
|
||||
findByDateRange: async (): Promise<Race[]> => [],
|
||||
create: async (): Promise<Race> => { throw new Error('Not implemented'); },
|
||||
update: async (): Promise<Race> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
};
|
||||
|
||||
const resultRepository: {
|
||||
findAll: () => Promise<unknown[]>;
|
||||
} = {
|
||||
findAll: async () => results,
|
||||
const resultRepository = {
|
||||
findById: async (): Promise<Result | null> => null,
|
||||
findAll: async (): Promise<Result[]> => results,
|
||||
findByRaceId: async (): Promise<Result[]> => [],
|
||||
findByDriverId: async (): Promise<Result[]> => [],
|
||||
findByDriverIdAndLeagueId: async (): Promise<Result[]> => [],
|
||||
create: async (): Promise<Result> => { throw new Error('Not implemented'); },
|
||||
createMany: async (): Promise<Result[]> => { throw new Error('Not implemented'); },
|
||||
update: async (): Promise<Result> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
deleteByRaceId: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
existsByRaceId: async (): Promise<boolean> => false,
|
||||
};
|
||||
|
||||
const leagueRepository: {
|
||||
findAll: () => Promise<Array<{ id: string; name: string }>>;
|
||||
} = {
|
||||
findAll: async () => leagues,
|
||||
const leagueRepository = {
|
||||
findById: async (): Promise<League | null> => null,
|
||||
findAll: async (): Promise<League[]> => leagues,
|
||||
findByOwnerId: async (): Promise<League[]> => [],
|
||||
create: async (): Promise<League> => { throw new Error('Not implemented'); },
|
||||
update: async (): Promise<League> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
searchByName: async (): Promise<League[]> => [],
|
||||
};
|
||||
|
||||
const standingRepository: {
|
||||
findByLeagueId: (leagueId: string) => Promise<unknown[]>;
|
||||
} = {
|
||||
findByLeagueId: async () => [],
|
||||
const standingRepository = {
|
||||
findByLeagueId: async (): Promise<Standing[]> => [],
|
||||
findByDriverIdAndLeagueId: async (): Promise<Standing | null> => null,
|
||||
findAll: async (): Promise<Standing[]> => [],
|
||||
save: async (): Promise<Standing> => { throw new Error('Not implemented'); },
|
||||
saveMany: async (): Promise<Standing[]> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
deleteByLeagueId: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
recalculate: async (): Promise<Standing[]> => [],
|
||||
};
|
||||
|
||||
const leagueMembershipRepository: {
|
||||
getMembership: (
|
||||
leagueId: string,
|
||||
driverIdParam: string,
|
||||
) => Promise<{ leagueId: string; driverId: string; status: string } | null>;
|
||||
} = {
|
||||
getMembership: async (leagueId: string, driverIdParam: string) => {
|
||||
const leagueMembershipRepository = {
|
||||
getMembership: async (leagueId: string, driverIdParam: string): Promise<LeagueMembership | null> => {
|
||||
return (
|
||||
memberships.find(
|
||||
(m) => m.leagueId === leagueId && m.driverId === driverIdParam,
|
||||
) ?? null
|
||||
);
|
||||
},
|
||||
getLeagueMembers: async (): Promise<LeagueMembership[]> => [],
|
||||
getJoinRequests: async (): Promise<any[]> => [],
|
||||
saveMembership: async (): Promise<LeagueMembership> => { throw new Error('Not implemented'); },
|
||||
removeMembership: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
saveJoinRequest: async (): Promise<any> => { throw new Error('Not implemented'); },
|
||||
removeJoinRequest: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
};
|
||||
|
||||
const raceRegistrationRepository: {
|
||||
isRegistered: (raceId: string, driverIdParam: string) => Promise<boolean>;
|
||||
} = {
|
||||
isRegistered: async (raceId: string, driverIdParam: string) => {
|
||||
const raceRegistrationRepository = {
|
||||
isRegistered: async (raceId: string, driverIdParam: string): Promise<boolean> => {
|
||||
if (driverIdParam !== driverId) return false;
|
||||
return registeredRaceIds.has(raceId);
|
||||
},
|
||||
getRegisteredDrivers: async (): Promise<string[]> => [],
|
||||
getRegistrationCount: async (): Promise<number> => 0,
|
||||
register: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
withdraw: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
getDriverRegistrations: async (): Promise<string[]> => [],
|
||||
clearRaceRegistrations: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
};
|
||||
|
||||
const feedRepository: {
|
||||
getFeedForDriver: (driverIdParam: string) => Promise<DashboardFeedItemSummaryViewModel[]>;
|
||||
} = {
|
||||
getFeedForDriver: async () => feedItems,
|
||||
const feedRepository = {
|
||||
getFeedForDriver: async (): Promise<FeedItem[]> => feedItems,
|
||||
getGlobalFeed: async (): Promise<FeedItem[]> => [],
|
||||
};
|
||||
|
||||
const socialRepository: {
|
||||
getFriends: (driverIdParam: string) => Promise<Array<{ id: string }>>;
|
||||
} = {
|
||||
getFriends: async () => friends,
|
||||
const socialRepository = {
|
||||
getFriends: async (): Promise<Driver[]> => friends,
|
||||
getFriendIds: async (): Promise<string[]> => [],
|
||||
getSuggestedFriends: async (): Promise<Driver[]> => [],
|
||||
};
|
||||
|
||||
const imageService = createTestImageService();
|
||||
@@ -230,138 +273,181 @@ describe('GetDashboardOverviewUseCase', () => {
|
||||
// Given completed races with results and standings
|
||||
const driverId = 'driver-2';
|
||||
|
||||
const driver = { id: driverId, name: 'Result Driver', country: 'DE' };
|
||||
const driver = Driver.create({ id: driverId, iracingId: '67890', name: 'Result Driver', country: 'DE' });
|
||||
|
||||
const leagues = [
|
||||
{ id: 'league-A', name: 'Results League A' },
|
||||
{ id: 'league-B', name: 'Results League B' },
|
||||
League.create({ id: 'league-A', name: 'Results League A', description: 'League A', ownerId: 'owner-A' }),
|
||||
League.create({ id: 'league-B', name: 'Results League B', description: 'League B', ownerId: 'owner-B' }),
|
||||
];
|
||||
|
||||
const raceOld = {
|
||||
const raceOld = Race.create({
|
||||
id: 'race-old',
|
||||
leagueId: 'league-A',
|
||||
track: 'Old Circuit',
|
||||
car: 'GT3',
|
||||
scheduledAt: new Date('2024-01-01T10:00:00Z'),
|
||||
status: 'completed' as const,
|
||||
};
|
||||
status: 'completed',
|
||||
});
|
||||
|
||||
const raceNew = {
|
||||
const raceNew = Race.create({
|
||||
id: 'race-new',
|
||||
leagueId: 'league-B',
|
||||
track: 'New Circuit',
|
||||
car: 'GT4',
|
||||
scheduledAt: new Date('2024-02-01T10:00:00Z'),
|
||||
status: 'completed' as const,
|
||||
};
|
||||
status: 'completed',
|
||||
});
|
||||
|
||||
const races = [raceOld, raceNew];
|
||||
|
||||
const results = [
|
||||
{
|
||||
Result.create({
|
||||
id: 'result-old',
|
||||
raceId: raceOld.id,
|
||||
driverId,
|
||||
position: 5,
|
||||
fastestLap: 120,
|
||||
incidents: 3,
|
||||
},
|
||||
{
|
||||
startPosition: 5,
|
||||
}),
|
||||
Result.create({
|
||||
id: 'result-new',
|
||||
raceId: raceNew.id,
|
||||
driverId,
|
||||
position: 2,
|
||||
fastestLap: 115,
|
||||
incidents: 1,
|
||||
},
|
||||
startPosition: 2,
|
||||
}),
|
||||
];
|
||||
|
||||
const memberships = [
|
||||
{
|
||||
LeagueMembership.create({
|
||||
leagueId: 'league-A',
|
||||
driverId,
|
||||
role: 'member',
|
||||
status: 'active',
|
||||
},
|
||||
{
|
||||
}),
|
||||
LeagueMembership.create({
|
||||
leagueId: 'league-B',
|
||||
driverId,
|
||||
role: 'member',
|
||||
status: 'active',
|
||||
},
|
||||
}),
|
||||
];
|
||||
|
||||
const standingsByLeague = new Map<
|
||||
string,
|
||||
Array<{ leagueId: string; driverId: string; position: number; points: number }>
|
||||
Standing[]
|
||||
>();
|
||||
standingsByLeague.set('league-A', [
|
||||
{ leagueId: 'league-A', driverId, position: 3, points: 50 },
|
||||
{ leagueId: 'league-A', driverId: 'other-1', position: 1, points: 80 },
|
||||
Standing.create({ leagueId: 'league-A', driverId, position: 3, points: 50 }),
|
||||
Standing.create({ leagueId: 'league-A', driverId: 'other-1', position: 1, points: 80 }),
|
||||
]);
|
||||
standingsByLeague.set('league-B', [
|
||||
{ leagueId: 'league-B', driverId, position: 1, points: 100 },
|
||||
{ leagueId: 'league-B', driverId: 'other-2', position: 2, points: 90 },
|
||||
Standing.create({ leagueId: 'league-B', driverId, position: 1, points: 100 }),
|
||||
Standing.create({ leagueId: 'league-B', driverId: 'other-2', position: 2, points: 90 }),
|
||||
]);
|
||||
|
||||
const driverRepository: {
|
||||
findById: (id: string) => Promise<{ id: string; name: string; country: string } | null>;
|
||||
} = {
|
||||
findById: async (id: string) => (id === driver.id ? driver : null),
|
||||
const driverRepository = {
|
||||
findById: async (id: string): Promise<Driver | null> => (id === driver.id ? driver : null),
|
||||
findByIRacingId: async (): Promise<Driver | null> => null,
|
||||
findAll: async (): Promise<Driver[]> => [],
|
||||
create: async (): Promise<Driver> => { throw new Error('Not implemented'); },
|
||||
update: async (): Promise<Driver> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
existsByIRacingId: async (): Promise<boolean> => false,
|
||||
};
|
||||
|
||||
const raceRepository: {
|
||||
findAll: () => Promise<typeof races>;
|
||||
} = {
|
||||
findAll: async () => races,
|
||||
const raceRepository = {
|
||||
findById: async (): Promise<Race | null> => null,
|
||||
findAll: async (): Promise<Race[]> => races,
|
||||
findByLeagueId: async (): Promise<Race[]> => [],
|
||||
findUpcomingByLeagueId: async (): Promise<Race[]> => [],
|
||||
findCompletedByLeagueId: async (): Promise<Race[]> => [],
|
||||
findByStatus: async (): Promise<Race[]> => [],
|
||||
findByDateRange: async (): Promise<Race[]> => [],
|
||||
create: async (): Promise<Race> => { throw new Error('Not implemented'); },
|
||||
update: async (): Promise<Race> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
};
|
||||
|
||||
const resultRepository: {
|
||||
findAll: () => Promise<typeof results>;
|
||||
} = {
|
||||
findAll: async () => results,
|
||||
const resultRepository = {
|
||||
findById: async (): Promise<Result | null> => null,
|
||||
findAll: async (): Promise<Result[]> => results,
|
||||
findByRaceId: async (): Promise<Result[]> => [],
|
||||
findByDriverId: async (): Promise<Result[]> => [],
|
||||
findByDriverIdAndLeagueId: async (): Promise<Result[]> => [],
|
||||
create: async (): Promise<Result> => { throw new Error('Not implemented'); },
|
||||
createMany: async (): Promise<Result[]> => { throw new Error('Not implemented'); },
|
||||
update: async (): Promise<Result> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
deleteByRaceId: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
existsByRaceId: async (): Promise<boolean> => false,
|
||||
};
|
||||
|
||||
const leagueRepository: {
|
||||
findAll: () => Promise<typeof leagues>;
|
||||
} = {
|
||||
findAll: async () => leagues,
|
||||
const leagueRepository = {
|
||||
findById: async (): Promise<League | null> => null,
|
||||
findAll: async (): Promise<League[]> => leagues,
|
||||
findByOwnerId: async (): Promise<League[]> => [],
|
||||
create: async (): Promise<League> => { throw new Error('Not implemented'); },
|
||||
update: async (): Promise<League> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
searchByName: async (): Promise<League[]> => [],
|
||||
};
|
||||
|
||||
const standingRepository: {
|
||||
findByLeagueId: (leagueId: string) => Promise<Array<{ leagueId: string; driverId: string; position: number; points: number }>>;
|
||||
} = {
|
||||
findByLeagueId: async (leagueId: string) =>
|
||||
const standingRepository = {
|
||||
findByLeagueId: async (leagueId: string): Promise<Standing[]> =>
|
||||
standingsByLeague.get(leagueId) ?? [],
|
||||
findByDriverIdAndLeagueId: async (): Promise<Standing | null> => null,
|
||||
findAll: async (): Promise<Standing[]> => [],
|
||||
save: async (): Promise<Standing> => { throw new Error('Not implemented'); },
|
||||
saveMany: async (): Promise<Standing[]> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
deleteByLeagueId: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
recalculate: async (): Promise<Standing[]> => [],
|
||||
};
|
||||
|
||||
const leagueMembershipRepository: {
|
||||
getMembership: (
|
||||
leagueId: string,
|
||||
driverIdParam: string,
|
||||
) => Promise<{ leagueId: string; driverId: string; status: string } | null>;
|
||||
} = {
|
||||
getMembership: async (leagueId: string, driverIdParam: string) => {
|
||||
const leagueMembershipRepository = {
|
||||
getMembership: async (leagueId: string, driverIdParam: string): Promise<LeagueMembership | null> => {
|
||||
return (
|
||||
memberships.find(
|
||||
(m) => m.leagueId === leagueId && m.driverId === driverIdParam,
|
||||
) ?? null
|
||||
);
|
||||
},
|
||||
getLeagueMembers: async (): Promise<LeagueMembership[]> => [],
|
||||
getJoinRequests: async (): Promise<any[]> => [],
|
||||
saveMembership: async (): Promise<LeagueMembership> => { throw new Error('Not implemented'); },
|
||||
removeMembership: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
saveJoinRequest: async (): Promise<any> => { throw new Error('Not implemented'); },
|
||||
removeJoinRequest: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
};
|
||||
|
||||
const raceRegistrationRepository: {
|
||||
isRegistered: (raceId: string, driverIdParam: string) => Promise<boolean>;
|
||||
} = {
|
||||
isRegistered: async () => false,
|
||||
const raceRegistrationRepository = {
|
||||
isRegistered: async (): Promise<boolean> => false,
|
||||
getRegisteredDrivers: async (): Promise<string[]> => [],
|
||||
getRegistrationCount: async (): Promise<number> => 0,
|
||||
register: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
withdraw: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
getDriverRegistrations: async (): Promise<string[]> => [],
|
||||
clearRaceRegistrations: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
};
|
||||
|
||||
const feedRepository: {
|
||||
getFeedForDriver: (driverIdParam: string) => Promise<DashboardFeedItemSummaryViewModel[]>;
|
||||
} = {
|
||||
getFeedForDriver: async () => [],
|
||||
const feedRepository = {
|
||||
getFeedForDriver: async (): Promise<FeedItem[]> => [],
|
||||
getGlobalFeed: async (): Promise<FeedItem[]> => [],
|
||||
};
|
||||
|
||||
const socialRepository: {
|
||||
getFriends: (driverIdParam: string) => Promise<Array<{ id: string }>>;
|
||||
} = {
|
||||
getFriends: async () => [],
|
||||
const socialRepository = {
|
||||
getFriends: async (): Promise<Driver[]> => [],
|
||||
getFriendIds: async (): Promise<string[]> => [],
|
||||
getSuggestedFriends: async (): Promise<Driver[]> => [],
|
||||
};
|
||||
|
||||
const imageService = createTestImageService();
|
||||
@@ -430,54 +516,100 @@ describe('GetDashboardOverviewUseCase', () => {
|
||||
// Given a driver with no related data
|
||||
const driverId = 'driver-empty';
|
||||
|
||||
const driver = { id: driverId, name: 'New Racer', country: 'FR' };
|
||||
const driver = Driver.create({ id: driverId, iracingId: '11111', name: 'New Racer', country: 'FR' });
|
||||
|
||||
const driverRepository: {
|
||||
findById: (id: string) => Promise<{ id: string; name: string; country: string } | null>;
|
||||
} = {
|
||||
findById: async (id: string) => (id === driver.id ? driver : null),
|
||||
const driverRepository = {
|
||||
findById: async (id: string): Promise<Driver | null> => (id === driver.id ? driver : null),
|
||||
findByIRacingId: async (): Promise<Driver | null> => null,
|
||||
findAll: async (): Promise<Driver[]> => [],
|
||||
create: async (): Promise<Driver> => { throw new Error('Not implemented'); },
|
||||
update: async (): Promise<Driver> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
existsByIRacingId: async (): Promise<boolean> => false,
|
||||
};
|
||||
|
||||
const raceRepository: { findAll: () => Promise<never[]> } = {
|
||||
findAll: async () => [],
|
||||
const raceRepository = {
|
||||
findById: async (): Promise<Race | null> => null,
|
||||
findAll: async (): Promise<Race[]> => [],
|
||||
findByLeagueId: async (): Promise<Race[]> => [],
|
||||
findUpcomingByLeagueId: async (): Promise<Race[]> => [],
|
||||
findCompletedByLeagueId: async (): Promise<Race[]> => [],
|
||||
findByStatus: async (): Promise<Race[]> => [],
|
||||
findByDateRange: async (): Promise<Race[]> => [],
|
||||
create: async (): Promise<Race> => { throw new Error('Not implemented'); },
|
||||
update: async (): Promise<Race> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
};
|
||||
|
||||
const resultRepository: { findAll: () => Promise<never[]> } = {
|
||||
findAll: async () => [],
|
||||
const resultRepository = {
|
||||
findById: async (): Promise<Result | null> => null,
|
||||
findAll: async (): Promise<Result[]> => [],
|
||||
findByRaceId: async (): Promise<Result[]> => [],
|
||||
findByDriverId: async (): Promise<Result[]> => [],
|
||||
findByDriverIdAndLeagueId: async (): Promise<Result[]> => [],
|
||||
create: async (): Promise<Result> => { throw new Error('Not implemented'); },
|
||||
createMany: async (): Promise<Result[]> => { throw new Error('Not implemented'); },
|
||||
update: async (): Promise<Result> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
deleteByRaceId: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
existsByRaceId: async (): Promise<boolean> => false,
|
||||
};
|
||||
|
||||
const leagueRepository: { findAll: () => Promise<never[]> } = {
|
||||
findAll: async () => [],
|
||||
const leagueRepository = {
|
||||
findById: async (): Promise<League | null> => null,
|
||||
findAll: async (): Promise<League[]> => [],
|
||||
findByOwnerId: async (): Promise<League[]> => [],
|
||||
create: async (): Promise<League> => { throw new Error('Not implemented'); },
|
||||
update: async (): Promise<League> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
searchByName: async (): Promise<League[]> => [],
|
||||
};
|
||||
|
||||
const standingRepository: {
|
||||
findByLeagueId: (leagueId: string) => Promise<never[]>;
|
||||
} = {
|
||||
findByLeagueId: async () => [],
|
||||
const standingRepository = {
|
||||
findByLeagueId: async (): Promise<Standing[]> => [],
|
||||
findByDriverIdAndLeagueId: async (): Promise<Standing | null> => null,
|
||||
findAll: async (): Promise<Standing[]> => [],
|
||||
save: async (): Promise<Standing> => { throw new Error('Not implemented'); },
|
||||
saveMany: async (): Promise<Standing[]> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
deleteByLeagueId: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
recalculate: async (): Promise<Standing[]> => [],
|
||||
};
|
||||
|
||||
const leagueMembershipRepository: {
|
||||
getMembership: (leagueId: string, driverIdParam: string) => Promise<null>;
|
||||
} = {
|
||||
getMembership: async () => null,
|
||||
const leagueMembershipRepository = {
|
||||
getMembership: async (): Promise<LeagueMembership | null> => null,
|
||||
getLeagueMembers: async (): Promise<LeagueMembership[]> => [],
|
||||
getJoinRequests: async (): Promise<any[]> => [],
|
||||
saveMembership: async (): Promise<LeagueMembership> => { throw new Error('Not implemented'); },
|
||||
removeMembership: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
saveJoinRequest: async (): Promise<any> => { throw new Error('Not implemented'); },
|
||||
removeJoinRequest: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
};
|
||||
|
||||
const raceRegistrationRepository: {
|
||||
isRegistered: (raceId: string, driverIdParam: string) => Promise<boolean>;
|
||||
} = {
|
||||
isRegistered: async () => false,
|
||||
const raceRegistrationRepository = {
|
||||
isRegistered: async (): Promise<boolean> => false,
|
||||
getRegisteredDrivers: async (): Promise<string[]> => [],
|
||||
getRegistrationCount: async (): Promise<number> => 0,
|
||||
register: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
withdraw: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
getDriverRegistrations: async (): Promise<string[]> => [],
|
||||
clearRaceRegistrations: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
};
|
||||
|
||||
const feedRepository: {
|
||||
getFeedForDriver: (driverIdParam: string) => Promise<DashboardFeedItemSummaryViewModel[]>;
|
||||
} = {
|
||||
getFeedForDriver: async () => [],
|
||||
const feedRepository = {
|
||||
getFeedForDriver: async (): Promise<FeedItem[]> => [],
|
||||
getGlobalFeed: async (): Promise<FeedItem[]> => [],
|
||||
};
|
||||
|
||||
const socialRepository: {
|
||||
getFriends: (driverIdParam: string) => Promise<Array<{ id: string }>>;
|
||||
} = {
|
||||
getFriends: async () => [],
|
||||
const socialRepository = {
|
||||
getFriends: async (): Promise<Driver[]> => [],
|
||||
getFriendIds: async (): Promise<string[]> => [],
|
||||
getSuggestedFriends: async (): Promise<Driver[]> => [],
|
||||
};
|
||||
|
||||
const imageService = createTestImageService();
|
||||
|
||||
@@ -2,10 +2,10 @@ import { describe, it, expect, beforeEach } from 'vitest';
|
||||
|
||||
import { JoinLeagueUseCase } from '@gridpilot/racing/application/use-cases/JoinLeagueUseCase';
|
||||
import type { ILeagueMembershipRepository } from '@gridpilot/racing/domain/repositories/ILeagueMembershipRepository';
|
||||
import type {
|
||||
import {
|
||||
LeagueMembership,
|
||||
MembershipRole,
|
||||
MembershipStatus,
|
||||
type MembershipRole,
|
||||
type MembershipStatus,
|
||||
} from '@gridpilot/racing/domain/entities/LeagueMembership';
|
||||
|
||||
class InMemoryLeagueMembershipRepository implements ILeagueMembershipRepository {
|
||||
@@ -109,13 +109,13 @@ describe('Membership use-cases', () => {
|
||||
const leagueId = 'league-1';
|
||||
const driverId = 'driver-1';
|
||||
|
||||
repository.seedMembership({
|
||||
repository.seedMembership(LeagueMembership.create({
|
||||
leagueId,
|
||||
driverId,
|
||||
role: 'member',
|
||||
status: 'active',
|
||||
joinedAt: new Date('2024-01-01'),
|
||||
});
|
||||
}));
|
||||
|
||||
await expect(
|
||||
useCase.execute({ leagueId, driverId }),
|
||||
|
||||
@@ -4,6 +4,8 @@ import { Race } from '@gridpilot/racing/domain/entities/Race';
|
||||
import { League } from '@gridpilot/racing/domain/entities/League';
|
||||
import { Result } from '@gridpilot/racing/domain/entities/Result';
|
||||
import { Penalty } from '@gridpilot/racing/domain/entities/Penalty';
|
||||
import { Standing } from '@gridpilot/racing/domain/entities/Standing';
|
||||
import { Driver } from '@gridpilot/racing/domain/entities/Driver';
|
||||
|
||||
import { GetRaceResultsDetailUseCase } from '@gridpilot/racing/application/use-cases/GetRaceResultsDetailUseCase';
|
||||
import { ImportRaceResultsUseCase } from '@gridpilot/racing/application/use-cases/ImportRaceResultsUseCase';
|
||||
@@ -77,37 +79,64 @@ describe('ImportRaceResultsUseCase', () => {
|
||||
let existsByRaceIdCalled = false;
|
||||
const recalcCalls: string[] = [];
|
||||
|
||||
const raceRepository: {
|
||||
findById: (id: string) => Promise<Race | null>;
|
||||
} = {
|
||||
findById: async (id: string) => races.get(id) ?? null,
|
||||
const raceRepository = {
|
||||
findById: async (id: string): Promise<Race | null> => races.get(id) ?? null,
|
||||
findAll: async (): Promise<Race[]> => [],
|
||||
findByLeagueId: async (): Promise<Race[]> => [],
|
||||
findUpcomingByLeagueId: async (): Promise<Race[]> => [],
|
||||
findCompletedByLeagueId: async (): Promise<Race[]> => [],
|
||||
findByStatus: async (): Promise<Race[]> => [],
|
||||
findByDateRange: async (): Promise<Race[]> => [],
|
||||
create: async (): Promise<Race> => { throw new Error('Not implemented'); },
|
||||
update: async (): Promise<Race> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
};
|
||||
|
||||
const leagueRepository: {
|
||||
findById: (id: string) => Promise<League | null>;
|
||||
} = {
|
||||
findById: async (id: string) => leagues.get(id) ?? null,
|
||||
const leagueRepository = {
|
||||
findById: async (id: string): Promise<League | null> => leagues.get(id) ?? null,
|
||||
findAll: async (): Promise<League[]> => [],
|
||||
findByOwnerId: async (): Promise<League[]> => [],
|
||||
create: async (): Promise<League> => { throw new Error('Not implemented'); },
|
||||
update: async (): Promise<League> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
searchByName: async (): Promise<League[]> => [],
|
||||
};
|
||||
|
||||
const resultRepository: {
|
||||
existsByRaceId: (raceId: string) => Promise<boolean>;
|
||||
createMany: (results: Result[]) => Promise<Result[]>;
|
||||
} = {
|
||||
existsByRaceId: async (raceId: string) => {
|
||||
existsByRaceIdCalled = true;
|
||||
return storedResults.some((r) => r.raceId === raceId);
|
||||
},
|
||||
createMany: async (results: Result[]) => {
|
||||
const resultRepository = {
|
||||
findById: async (): Promise<Result | null> => null,
|
||||
findAll: async (): Promise<Result[]> => [],
|
||||
findByRaceId: async (): Promise<Result[]> => [],
|
||||
findByDriverId: async (): Promise<Result[]> => [],
|
||||
findByDriverIdAndLeagueId: async (): Promise<Result[]> => [],
|
||||
create: async (): Promise<Result> => { throw new Error('Not implemented'); },
|
||||
createMany: async (results: Result[]): Promise<Result[]> => {
|
||||
storedResults.push(...results);
|
||||
return results;
|
||||
},
|
||||
update: async (): Promise<Result> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
deleteByRaceId: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
existsByRaceId: async (raceId: string): Promise<boolean> => {
|
||||
existsByRaceIdCalled = true;
|
||||
return storedResults.some((r) => r.raceId === raceId);
|
||||
},
|
||||
};
|
||||
|
||||
const standingRepository: {
|
||||
recalculate: (leagueId: string) => Promise<void>;
|
||||
} = {
|
||||
recalculate: async (leagueId: string) => {
|
||||
const standingRepository = {
|
||||
findByLeagueId: async (): Promise<Standing[]> => [],
|
||||
findByDriverIdAndLeagueId: async (): Promise<Standing | null> => null,
|
||||
findAll: async (): Promise<Standing[]> => [],
|
||||
save: async (): Promise<Standing> => { throw new Error('Not implemented'); },
|
||||
saveMany: async (): Promise<Standing[]> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
deleteByLeagueId: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
recalculate: async (leagueId: string): Promise<Standing[]> => {
|
||||
recalcCalls.push(leagueId);
|
||||
return [];
|
||||
},
|
||||
};
|
||||
|
||||
@@ -196,34 +225,60 @@ describe('ImportRaceResultsUseCase', () => {
|
||||
}),
|
||||
];
|
||||
|
||||
const raceRepository: {
|
||||
findById: (id: string) => Promise<Race | null>;
|
||||
} = {
|
||||
findById: async (id: string) => races.get(id) ?? null,
|
||||
const raceRepository = {
|
||||
findById: async (id: string): Promise<Race | null> => races.get(id) ?? null,
|
||||
findAll: async (): Promise<Race[]> => [],
|
||||
findByLeagueId: async (): Promise<Race[]> => [],
|
||||
findUpcomingByLeagueId: async (): Promise<Race[]> => [],
|
||||
findCompletedByLeagueId: async (): Promise<Race[]> => [],
|
||||
findByStatus: async (): Promise<Race[]> => [],
|
||||
findByDateRange: async (): Promise<Race[]> => [],
|
||||
create: async (): Promise<Race> => { throw new Error('Not implemented'); },
|
||||
update: async (): Promise<Race> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
};
|
||||
|
||||
const leagueRepository: {
|
||||
findById: (id: string) => Promise<League | null>;
|
||||
} = {
|
||||
findById: async (id: string) => leagues.get(id) ?? null,
|
||||
const leagueRepository = {
|
||||
findById: async (id: string): Promise<League | null> => leagues.get(id) ?? null,
|
||||
findAll: async (): Promise<League[]> => [],
|
||||
findByOwnerId: async (): Promise<League[]> => [],
|
||||
create: async (): Promise<League> => { throw new Error('Not implemented'); },
|
||||
update: async (): Promise<League> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
searchByName: async (): Promise<League[]> => [],
|
||||
};
|
||||
|
||||
const resultRepository: {
|
||||
existsByRaceId: (raceId: string) => Promise<boolean>;
|
||||
createMany: (results: Result[]) => Promise<Result[]>;
|
||||
} = {
|
||||
existsByRaceId: async (raceId: string) => {
|
||||
return storedResults.some((r) => r.raceId === raceId);
|
||||
},
|
||||
createMany: async (_results: Result[]) => {
|
||||
const resultRepository = {
|
||||
findById: async (): Promise<Result | null> => null,
|
||||
findAll: async (): Promise<Result[]> => [],
|
||||
findByRaceId: async (): Promise<Result[]> => [],
|
||||
findByDriverId: async (): Promise<Result[]> => [],
|
||||
findByDriverIdAndLeagueId: async (): Promise<Result[]> => [],
|
||||
create: async (): Promise<Result> => { throw new Error('Not implemented'); },
|
||||
createMany: async (_results: Result[]): Promise<Result[]> => {
|
||||
throw new Error('Should not be called when results already exist');
|
||||
},
|
||||
update: async (): Promise<Result> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
deleteByRaceId: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
existsByRaceId: async (raceId: string): Promise<boolean> => {
|
||||
return storedResults.some((r) => r.raceId === raceId);
|
||||
},
|
||||
};
|
||||
|
||||
const standingRepository: {
|
||||
recalculate: (leagueId: string) => Promise<void>;
|
||||
} = {
|
||||
recalculate: async (_leagueId: string) => {
|
||||
const standingRepository = {
|
||||
findByLeagueId: async (): Promise<Standing[]> => [],
|
||||
findByDriverIdAndLeagueId: async (): Promise<Standing | null> => null,
|
||||
findAll: async (): Promise<Standing[]> => [],
|
||||
save: async (): Promise<Standing> => { throw new Error('Not implemented'); },
|
||||
saveMany: async (): Promise<Standing[]> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
deleteByLeagueId: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
recalculate: async (_leagueId: string): Promise<Standing[]> => {
|
||||
throw new Error('Should not be called when results already exist');
|
||||
},
|
||||
};
|
||||
@@ -315,35 +370,68 @@ describe('GetRaceResultsDetailUseCase', () => {
|
||||
const results = [result1, result2];
|
||||
const drivers = [driver1, driver2];
|
||||
|
||||
const raceRepository: {
|
||||
findById: (id: string) => Promise<Race | null>;
|
||||
} = {
|
||||
findById: async (id: string) => races.get(id) ?? null,
|
||||
const raceRepository = {
|
||||
findById: async (id: string): Promise<Race | null> => races.get(id) ?? null,
|
||||
findAll: async (): Promise<Race[]> => [],
|
||||
findByLeagueId: async (): Promise<Race[]> => [],
|
||||
findUpcomingByLeagueId: async (): Promise<Race[]> => [],
|
||||
findCompletedByLeagueId: async (): Promise<Race[]> => [],
|
||||
findByStatus: async (): Promise<Race[]> => [],
|
||||
findByDateRange: async (): Promise<Race[]> => [],
|
||||
create: async (): Promise<Race> => { throw new Error('Not implemented'); },
|
||||
update: async (): Promise<Race> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
};
|
||||
|
||||
const leagueRepository: {
|
||||
findById: (id: string) => Promise<League | null>;
|
||||
} = {
|
||||
findById: async (id: string) => leagues.get(id) ?? null,
|
||||
const leagueRepository = {
|
||||
findById: async (id: string): Promise<League | null> => leagues.get(id) ?? null,
|
||||
findAll: async (): Promise<League[]> => [],
|
||||
findByOwnerId: async (): Promise<League[]> => [],
|
||||
create: async (): Promise<League> => { throw new Error('Not implemented'); },
|
||||
update: async (): Promise<League> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
searchByName: async (): Promise<League[]> => [],
|
||||
};
|
||||
|
||||
const resultRepository: {
|
||||
findByRaceId: (raceId: string) => Promise<Result[]>;
|
||||
} = {
|
||||
findByRaceId: async (raceId: string) =>
|
||||
const resultRepository = {
|
||||
findById: async (): Promise<Result | null> => null,
|
||||
findAll: async (): Promise<Result[]> => [],
|
||||
findByRaceId: async (raceId: string): Promise<Result[]> =>
|
||||
results.filter((r) => r.raceId === raceId),
|
||||
findByDriverId: async (): Promise<Result[]> => [],
|
||||
findByDriverIdAndLeagueId: async (): Promise<Result[]> => [],
|
||||
create: async (): Promise<Result> => { throw new Error('Not implemented'); },
|
||||
createMany: async (): Promise<Result[]> => { throw new Error('Not implemented'); },
|
||||
update: async (): Promise<Result> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
deleteByRaceId: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
existsByRaceId: async (): Promise<boolean> => false,
|
||||
};
|
||||
|
||||
const driverRepository: {
|
||||
findAll: () => Promise<Array<{ id: string; name: string; country: string }>>;
|
||||
} = {
|
||||
findAll: async () => drivers,
|
||||
const driverRepository = {
|
||||
findById: async (): Promise<Driver | null> => null,
|
||||
findByIRacingId: async (): Promise<Driver | null> => null,
|
||||
findAll: async (): Promise<Driver[]> => drivers.map(d => Driver.create({ id: d.id, iracingId: '123', name: d.name, country: d.country })),
|
||||
create: async (): Promise<Driver> => { throw new Error('Not implemented'); },
|
||||
update: async (): Promise<Driver> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
existsByIRacingId: async (): Promise<boolean> => false,
|
||||
};
|
||||
|
||||
const penaltyRepository: {
|
||||
findByRaceId: (raceId: string) => Promise<Penalty[]>;
|
||||
} = {
|
||||
findByRaceId: async () => [] as Penalty[],
|
||||
const penaltyRepository = {
|
||||
findById: async (): Promise<Penalty | null> => null,
|
||||
findByRaceId: async (): Promise<Penalty[]> => [] as Penalty[],
|
||||
findByDriverId: async (): Promise<Penalty[]> => [],
|
||||
findByProtestId: async (): Promise<Penalty[]> => [],
|
||||
findPending: async (): Promise<Penalty[]> => [],
|
||||
findIssuedBy: async (): Promise<Penalty[]> => [],
|
||||
create: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
update: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
};
|
||||
|
||||
const presenter = new FakeRaceResultsDetailPresenter();
|
||||
@@ -354,7 +442,6 @@ describe('GetRaceResultsDetailUseCase', () => {
|
||||
resultRepository,
|
||||
driverRepository,
|
||||
penaltyRepository,
|
||||
presenter,
|
||||
);
|
||||
|
||||
// When executing the query
|
||||
@@ -364,8 +451,8 @@ describe('GetRaceResultsDetailUseCase', () => {
|
||||
expect(viewModel).not.toBeNull();
|
||||
|
||||
// Then points system matches the default F1-style configuration
|
||||
expect(viewModel!.pointsSystem[1]).toBe(25);
|
||||
expect(viewModel!.pointsSystem[2]).toBe(18);
|
||||
expect(viewModel!.pointsSystem?.[1]).toBe(25);
|
||||
expect(viewModel!.pointsSystem?.[2]).toBe(18);
|
||||
|
||||
// And fastest lap is identified correctly
|
||||
expect(viewModel!.fastestLapTime).toBeCloseTo(88.456, 3);
|
||||
@@ -408,6 +495,7 @@ describe('GetRaceResultsDetailUseCase', () => {
|
||||
|
||||
const penalty = Penalty.create({
|
||||
id: 'pen-1',
|
||||
leagueId: league.id,
|
||||
raceId: race.id,
|
||||
driverId: driver.id,
|
||||
type: 'points_deduction',
|
||||
@@ -424,36 +512,69 @@ describe('GetRaceResultsDetailUseCase', () => {
|
||||
const drivers = [driver];
|
||||
const penalties = [penalty];
|
||||
|
||||
const raceRepository: {
|
||||
findById: (id: string) => Promise<Race | null>;
|
||||
} = {
|
||||
findById: async (id: string) => races.get(id) ?? null,
|
||||
const raceRepository = {
|
||||
findById: async (id: string): Promise<Race | null> => races.get(id) ?? null,
|
||||
findAll: async (): Promise<Race[]> => [],
|
||||
findByLeagueId: async (): Promise<Race[]> => [],
|
||||
findUpcomingByLeagueId: async (): Promise<Race[]> => [],
|
||||
findCompletedByLeagueId: async (): Promise<Race[]> => [],
|
||||
findByStatus: async (): Promise<Race[]> => [],
|
||||
findByDateRange: async (): Promise<Race[]> => [],
|
||||
create: async (): Promise<Race> => { throw new Error('Not implemented'); },
|
||||
update: async (): Promise<Race> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
};
|
||||
|
||||
const leagueRepository: {
|
||||
findById: (id: string) => Promise<League | null>;
|
||||
} = {
|
||||
findById: async (id: string) => leagues.get(id) ?? null,
|
||||
const leagueRepository = {
|
||||
findById: async (id: string): Promise<League | null> => leagues.get(id) ?? null,
|
||||
findAll: async (): Promise<League[]> => [],
|
||||
findByOwnerId: async (): Promise<League[]> => [],
|
||||
create: async (): Promise<League> => { throw new Error('Not implemented'); },
|
||||
update: async (): Promise<League> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
searchByName: async (): Promise<League[]> => [],
|
||||
};
|
||||
|
||||
const resultRepository: {
|
||||
findByRaceId: (raceId: string) => Promise<Result[]>;
|
||||
} = {
|
||||
findByRaceId: async (raceId: string) =>
|
||||
const resultRepository = {
|
||||
findById: async (): Promise<Result | null> => null,
|
||||
findAll: async (): Promise<Result[]> => [],
|
||||
findByRaceId: async (raceId: string): Promise<Result[]> =>
|
||||
results.filter((r) => r.raceId === raceId),
|
||||
findByDriverId: async (): Promise<Result[]> => [],
|
||||
findByDriverIdAndLeagueId: async (): Promise<Result[]> => [],
|
||||
create: async (): Promise<Result> => { throw new Error('Not implemented'); },
|
||||
createMany: async (): Promise<Result[]> => { throw new Error('Not implemented'); },
|
||||
update: async (): Promise<Result> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
deleteByRaceId: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
existsByRaceId: async (): Promise<boolean> => false,
|
||||
};
|
||||
|
||||
const driverRepository: {
|
||||
findAll: () => Promise<Array<{ id: string; name: string; country: string }>>;
|
||||
} = {
|
||||
findAll: async () => drivers,
|
||||
const driverRepository = {
|
||||
findById: async (): Promise<Driver | null> => null,
|
||||
findByIRacingId: async (): Promise<Driver | null> => null,
|
||||
findAll: async (): Promise<Driver[]> => drivers.map(d => Driver.create({ id: d.id, iracingId: '123', name: d.name, country: d.country })),
|
||||
create: async (): Promise<Driver> => { throw new Error('Not implemented'); },
|
||||
update: async (): Promise<Driver> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
existsByIRacingId: async (): Promise<boolean> => false,
|
||||
};
|
||||
|
||||
const penaltyRepository: {
|
||||
findByRaceId: (raceId: string) => Promise<Penalty[]>;
|
||||
} = {
|
||||
findByRaceId: async (raceId: string) =>
|
||||
const penaltyRepository = {
|
||||
findById: async (): Promise<Penalty | null> => null,
|
||||
findByRaceId: async (raceId: string): Promise<Penalty[]> =>
|
||||
penalties.filter((p) => p.raceId === raceId),
|
||||
findByDriverId: async (): Promise<Penalty[]> => [],
|
||||
findByProtestId: async (): Promise<Penalty[]> => [],
|
||||
findPending: async (): Promise<Penalty[]> => [],
|
||||
findIssuedBy: async (): Promise<Penalty[]> => [],
|
||||
create: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
update: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
};
|
||||
|
||||
const presenter = new FakeRaceResultsDetailPresenter();
|
||||
@@ -464,7 +585,6 @@ describe('GetRaceResultsDetailUseCase', () => {
|
||||
resultRepository,
|
||||
driverRepository,
|
||||
penaltyRepository,
|
||||
presenter,
|
||||
);
|
||||
|
||||
// When
|
||||
@@ -491,34 +611,67 @@ describe('GetRaceResultsDetailUseCase', () => {
|
||||
|
||||
it('presents an error when race does not exist', async () => {
|
||||
// Given repositories without the requested race
|
||||
const raceRepository: {
|
||||
findById: (id: string) => Promise<Race | null>;
|
||||
} = {
|
||||
findById: async () => null,
|
||||
const raceRepository = {
|
||||
findById: async (): Promise<Race | null> => null,
|
||||
findAll: async (): Promise<Race[]> => [],
|
||||
findByLeagueId: async (): Promise<Race[]> => [],
|
||||
findUpcomingByLeagueId: async (): Promise<Race[]> => [],
|
||||
findCompletedByLeagueId: async (): Promise<Race[]> => [],
|
||||
findByStatus: async (): Promise<Race[]> => [],
|
||||
findByDateRange: async (): Promise<Race[]> => [],
|
||||
create: async (): Promise<Race> => { throw new Error('Not implemented'); },
|
||||
update: async (): Promise<Race> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
};
|
||||
|
||||
const leagueRepository: {
|
||||
findById: (id: string) => Promise<League | null>;
|
||||
} = {
|
||||
findById: async () => null,
|
||||
const leagueRepository = {
|
||||
findById: async (): Promise<League | null> => null,
|
||||
findAll: async (): Promise<League[]> => [],
|
||||
findByOwnerId: async (): Promise<League[]> => [],
|
||||
create: async (): Promise<League> => { throw new Error('Not implemented'); },
|
||||
update: async (): Promise<League> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
searchByName: async (): Promise<League[]> => [],
|
||||
};
|
||||
|
||||
const resultRepository: {
|
||||
findByRaceId: (raceId: string) => Promise<Result[]>;
|
||||
} = {
|
||||
findByRaceId: async () => [] as Result[],
|
||||
const resultRepository = {
|
||||
findById: async (): Promise<Result | null> => null,
|
||||
findAll: async (): Promise<Result[]> => [],
|
||||
findByRaceId: async (): Promise<Result[]> => [] as Result[],
|
||||
findByDriverId: async (): Promise<Result[]> => [],
|
||||
findByDriverIdAndLeagueId: async (): Promise<Result[]> => [],
|
||||
create: async (): Promise<Result> => { throw new Error('Not implemented'); },
|
||||
createMany: async (): Promise<Result[]> => { throw new Error('Not implemented'); },
|
||||
update: async (): Promise<Result> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
deleteByRaceId: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
existsByRaceId: async (): Promise<boolean> => false,
|
||||
};
|
||||
|
||||
const driverRepository: {
|
||||
findAll: () => Promise<Array<{ id: string; name: string; country: string }>>;
|
||||
} = {
|
||||
findAll: async () => [],
|
||||
const driverRepository = {
|
||||
findById: async (): Promise<Driver | null> => null,
|
||||
findByIRacingId: async (): Promise<Driver | null> => null,
|
||||
findAll: async (): Promise<Driver[]> => [],
|
||||
create: async (): Promise<Driver> => { throw new Error('Not implemented'); },
|
||||
update: async (): Promise<Driver> => { throw new Error('Not implemented'); },
|
||||
delete: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
existsByIRacingId: async (): Promise<boolean> => false,
|
||||
};
|
||||
|
||||
const penaltyRepository: {
|
||||
findByRaceId: (raceId: string) => Promise<Penalty[]>;
|
||||
} = {
|
||||
findByRaceId: async () => [] as Penalty[],
|
||||
const penaltyRepository = {
|
||||
findById: async (): Promise<Penalty | null> => null,
|
||||
findByRaceId: async (): Promise<Penalty[]> => [] as Penalty[],
|
||||
findByDriverId: async (): Promise<Penalty[]> => [],
|
||||
findByProtestId: async (): Promise<Penalty[]> => [],
|
||||
findPending: async (): Promise<Penalty[]> => [],
|
||||
findIssuedBy: async (): Promise<Penalty[]> => [],
|
||||
create: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
update: async (): Promise<void> => { throw new Error('Not implemented'); },
|
||||
exists: async (): Promise<boolean> => false,
|
||||
};
|
||||
|
||||
const presenter = new FakeRaceResultsDetailPresenter();
|
||||
@@ -529,7 +682,6 @@ describe('GetRaceResultsDetailUseCase', () => {
|
||||
resultRepository,
|
||||
driverRepository,
|
||||
penaltyRepository,
|
||||
presenter,
|
||||
);
|
||||
|
||||
// When
|
||||
|
||||
@@ -9,13 +9,14 @@ import {
|
||||
LeagueMembership,
|
||||
type MembershipStatus,
|
||||
} from '@gridpilot/racing/domain/entities/LeagueMembership';
|
||||
import { Team } from '@gridpilot/racing/domain/entities/Team';
|
||||
import { Driver } from '@gridpilot/racing/domain/entities/Driver';
|
||||
import type {
|
||||
Team,
|
||||
TeamMembership,
|
||||
TeamMembershipStatus,
|
||||
TeamRole,
|
||||
TeamJoinRequest,
|
||||
} from '@gridpilot/racing/domain/entities/Team';
|
||||
} from '@gridpilot/racing/domain/types/TeamMembership';
|
||||
|
||||
import { RegisterForRaceUseCase } from '@gridpilot/racing/application/use-cases/RegisterForRaceUseCase';
|
||||
import { WithdrawFromRaceUseCase } from '@gridpilot/racing/application/use-cases/WithdrawFromRaceUseCase';
|
||||
@@ -169,10 +170,23 @@ class TestDriverRegistrationStatusPresenter implements IDriverRegistrationStatus
|
||||
raceId: string | null = null;
|
||||
driverId: string | null = null;
|
||||
|
||||
present(isRegistered: boolean, raceId: string, driverId: string): void {
|
||||
present(isRegistered: boolean, raceId: string, driverId: string) {
|
||||
this.isRegistered = isRegistered;
|
||||
this.raceId = raceId;
|
||||
this.driverId = driverId;
|
||||
return {
|
||||
isRegistered,
|
||||
raceId,
|
||||
driverId,
|
||||
};
|
||||
}
|
||||
|
||||
getViewModel() {
|
||||
return {
|
||||
isRegistered: this.isRegistered!,
|
||||
raceId: this.raceId!,
|
||||
driverId: this.driverId!,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,9 +199,20 @@ class TestRaceRegistrationsPresenter implements IRaceRegistrationsPresenter {
|
||||
this.driverIds = [];
|
||||
}
|
||||
|
||||
present(input: RaceRegistrationsResultDTO): void {
|
||||
present(input: RaceRegistrationsResultDTO) {
|
||||
this.driverIds = input.registeredDriverIds;
|
||||
this.raceId = null;
|
||||
return {
|
||||
registeredDriverIds: input.registeredDriverIds,
|
||||
count: input.registeredDriverIds.length,
|
||||
};
|
||||
}
|
||||
|
||||
getViewModel() {
|
||||
return {
|
||||
registeredDriverIds: this.driverIds,
|
||||
count: this.driverIds.length,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -411,8 +436,43 @@ describe('Racing application use-cases - teams', () => {
|
||||
let getDriverTeamUseCase: GetDriverTeamUseCase;
|
||||
|
||||
class FakeDriverRepository {
|
||||
async findById(driverId: string): Promise<{ id: string; name: string } | null> {
|
||||
return { id: driverId, name: `Driver ${driverId}` };
|
||||
async findById(driverId: string): Promise<Driver | null> {
|
||||
return Driver.create({ id: driverId, iracingId: '123', name: `Driver ${driverId}`, country: 'US' });
|
||||
}
|
||||
|
||||
async findByIRacingId(id: string): Promise<Driver | null> {
|
||||
return null;
|
||||
}
|
||||
|
||||
async findAll(): Promise<Driver[]> {
|
||||
return [];
|
||||
}
|
||||
|
||||
async create(driver: Driver): Promise<Driver> {
|
||||
return driver;
|
||||
}
|
||||
|
||||
async update(driver: Driver): Promise<Driver> {
|
||||
return driver;
|
||||
}
|
||||
|
||||
async delete(id: string): Promise<void> {
|
||||
}
|
||||
|
||||
async exists(id: string): Promise<boolean> {
|
||||
return false;
|
||||
}
|
||||
|
||||
async existsByIRacingId(iracingId: string): Promise<boolean> {
|
||||
return false;
|
||||
}
|
||||
|
||||
async findByLeagueId(leagueId: string): Promise<Driver[]> {
|
||||
return [];
|
||||
}
|
||||
|
||||
async findByTeamId(teamId: string): Promise<Driver[]> {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -420,6 +480,18 @@ describe('Racing application use-cases - teams', () => {
|
||||
getDriverAvatar(driverId: string): string {
|
||||
return `https://example.com/avatar/${driverId}.png`;
|
||||
}
|
||||
|
||||
getTeamLogo(teamId: string): string {
|
||||
return `https://example.com/logo/${teamId}.png`;
|
||||
}
|
||||
|
||||
getLeagueCover(leagueId: string): string {
|
||||
return `https://example.com/cover/${leagueId}.png`;
|
||||
}
|
||||
|
||||
getLeagueLogo(leagueId: string): string {
|
||||
return `https://example.com/logo/${leagueId}.png`;
|
||||
}
|
||||
}
|
||||
|
||||
class TestAllTeamsPresenter implements IAllTeamsPresenter {
|
||||
@@ -438,9 +510,9 @@ describe('Racing application use-cases - teams', () => {
|
||||
description: team.description,
|
||||
memberCount: team.memberCount,
|
||||
leagues: team.leagues,
|
||||
specialization: team.specialization,
|
||||
region: team.region,
|
||||
languages: team.languages,
|
||||
specialization: (team as any).specialization,
|
||||
region: (team as any).region,
|
||||
languages: (team as any).languages,
|
||||
})),
|
||||
totalCount: input.teams.length,
|
||||
};
|
||||
@@ -487,7 +559,7 @@ describe('Racing application use-cases - teams', () => {
|
||||
return {
|
||||
driverId,
|
||||
driverName,
|
||||
role: membership.role,
|
||||
role: ((membership.role as any) === 'owner' ? 'owner' : (membership.role as any) === 'member' ? 'member' : (membership.role as any) === 'manager' ? 'manager' : (membership.role as any) === 'driver' ? 'member' : 'member') as "owner" | "member" | "manager",
|
||||
joinedAt: membership.joinedAt.toISOString(),
|
||||
isActive: membership.status === 'active',
|
||||
avatarUrl,
|
||||
@@ -496,7 +568,7 @@ describe('Racing application use-cases - teams', () => {
|
||||
|
||||
const ownerCount = members.filter((m) => m.role === 'owner').length;
|
||||
const managerCount = members.filter((m) => m.role === 'manager').length;
|
||||
const memberCount = members.filter((m) => m.role === 'member').length;
|
||||
const memberCount = members.filter((m) => (m.role as any) === 'member').length;
|
||||
|
||||
this.viewModel = {
|
||||
members,
|
||||
@@ -534,7 +606,7 @@ describe('Racing application use-cases - teams', () => {
|
||||
driverId,
|
||||
driverName,
|
||||
teamId: request.teamId,
|
||||
status: 'pending',
|
||||
status: 'pending' as const,
|
||||
requestedAt: request.requestedAt.toISOString(),
|
||||
avatarUrl,
|
||||
};
|
||||
@@ -559,7 +631,7 @@ describe('Racing application use-cases - teams', () => {
|
||||
}
|
||||
|
||||
class TestDriverTeamPresenter implements IDriverTeamPresenter {
|
||||
private viewModel: DriverTeamViewModel | null = null;
|
||||
viewModel: DriverTeamViewModel | null = null;
|
||||
|
||||
reset(): void {
|
||||
this.viewModel = null;
|
||||
@@ -579,12 +651,9 @@ describe('Racing application use-cases - teams', () => {
|
||||
description: team.description,
|
||||
ownerId: team.ownerId,
|
||||
leagues: team.leagues,
|
||||
specialization: team.specialization,
|
||||
region: team.region,
|
||||
languages: team.languages,
|
||||
},
|
||||
membership: {
|
||||
role: membership.role,
|
||||
role: (membership.role === 'owner' || membership.role === 'manager') ? membership.role : 'member' as "owner" | "member" | "manager",
|
||||
joinedAt: membership.joinedAt.toISOString(),
|
||||
isActive: membership.status === 'active',
|
||||
},
|
||||
@@ -619,19 +688,17 @@ describe('Racing application use-cases - teams', () => {
|
||||
getAllTeamsUseCase = new GetAllTeamsUseCase(
|
||||
teamRepo,
|
||||
membershipRepo,
|
||||
allTeamsPresenter,
|
||||
);
|
||||
|
||||
teamDetailsPresenter = new TestTeamDetailsPresenter();
|
||||
getTeamDetailsUseCase = new GetTeamDetailsUseCase(
|
||||
teamRepo,
|
||||
membershipRepo,
|
||||
teamDetailsPresenter,
|
||||
);
|
||||
|
||||
const driverRepository = new FakeDriverRepository();
|
||||
const imageService = new FakeImageService();
|
||||
|
||||
|
||||
teamMembersPresenter = new TestTeamMembersPresenter();
|
||||
getTeamMembersUseCase = new GetTeamMembersUseCase(
|
||||
membershipRepo,
|
||||
|
||||
Reference in New Issue
Block a user