wip
This commit is contained in:
@@ -19,8 +19,8 @@ import type {
|
||||
|
||||
import { RegisterForRaceUseCase } from '@gridpilot/racing/application/use-cases/RegisterForRaceUseCase';
|
||||
import { WithdrawFromRaceUseCase } from '@gridpilot/racing/application/use-cases/WithdrawFromRaceUseCase';
|
||||
import { IsDriverRegisteredForRaceQuery } from '@gridpilot/racing/application/use-cases/IsDriverRegisteredForRaceQuery';
|
||||
import { GetRaceRegistrationsQuery } from '@gridpilot/racing/application/use-cases/GetRaceRegistrationsQuery';
|
||||
import { IsDriverRegisteredForRaceUseCase } from '@gridpilot/racing/application/use-cases/IsDriverRegisteredForRaceUseCase';
|
||||
import { GetRaceRegistrationsUseCase } from '@gridpilot/racing/application/use-cases/GetRaceRegistrationsUseCase';
|
||||
|
||||
import { CreateTeamUseCase } from '@gridpilot/racing/application/use-cases/CreateTeamUseCase';
|
||||
import { JoinTeamUseCase } from '@gridpilot/racing/application/use-cases/JoinTeamUseCase';
|
||||
@@ -28,11 +28,18 @@ import { LeaveTeamUseCase } from '@gridpilot/racing/application/use-cases/LeaveT
|
||||
import { ApproveTeamJoinRequestUseCase } from '@gridpilot/racing/application/use-cases/ApproveTeamJoinRequestUseCase';
|
||||
import { RejectTeamJoinRequestUseCase } from '@gridpilot/racing/application/use-cases/RejectTeamJoinRequestUseCase';
|
||||
import { UpdateTeamUseCase } from '@gridpilot/racing/application/use-cases/UpdateTeamUseCase';
|
||||
import { GetAllTeamsQuery } from '@gridpilot/racing/application/use-cases/GetAllTeamsQuery';
|
||||
import { GetTeamDetailsQuery } from '@gridpilot/racing/application/use-cases/GetTeamDetailsQuery';
|
||||
import { GetTeamMembersQuery } from '@gridpilot/racing/application/use-cases/GetTeamMembersQuery';
|
||||
import { GetTeamJoinRequestsQuery } from '@gridpilot/racing/application/use-cases/GetTeamJoinRequestsQuery';
|
||||
import { GetDriverTeamQuery } from '@gridpilot/racing/application/use-cases/GetDriverTeamQuery';
|
||||
import { GetAllTeamsUseCase } from '@gridpilot/racing/application/use-cases/GetAllTeamsUseCase';
|
||||
import { GetTeamDetailsUseCase } from '@gridpilot/racing/application/use-cases/GetTeamDetailsUseCase';
|
||||
import { GetTeamMembersUseCase } from '@gridpilot/racing/application/use-cases/GetTeamMembersUseCase';
|
||||
import { GetTeamJoinRequestsUseCase } from '@gridpilot/racing/application/use-cases/GetTeamJoinRequestsUseCase';
|
||||
import { GetDriverTeamUseCase } from '@gridpilot/racing/application/use-cases/GetDriverTeamUseCase';
|
||||
import type { IDriverRegistrationStatusPresenter } from '@gridpilot/racing/application/presenters/IDriverRegistrationStatusPresenter';
|
||||
import type { IRaceRegistrationsPresenter } from '@gridpilot/racing/application/presenters/IRaceRegistrationsPresenter';
|
||||
import type { IAllTeamsPresenter } from '@gridpilot/racing/application/presenters/IAllTeamsPresenter';
|
||||
import type { ITeamDetailsPresenter } from '@gridpilot/racing/application/presenters/ITeamDetailsPresenter';
|
||||
import type { ITeamMembersPresenter } from '@gridpilot/racing/application/presenters/ITeamMembersPresenter';
|
||||
import type { ITeamJoinRequestsPresenter } from '@gridpilot/racing/application/presenters/ITeamJoinRequestsPresenter';
|
||||
import type { IDriverTeamPresenter } from '@gridpilot/racing/application/presenters/IDriverTeamPresenter';
|
||||
|
||||
/**
|
||||
* Simple in-memory fakes mirroring current alpha behavior.
|
||||
@@ -138,6 +145,35 @@ class InMemoryLeagueMembershipRepositoryForRegistrations implements ILeagueMembe
|
||||
}
|
||||
}
|
||||
|
||||
class TestDriverRegistrationStatusPresenter implements IDriverRegistrationStatusPresenter {
|
||||
isRegistered: boolean | null = null;
|
||||
raceId: string | null = null;
|
||||
driverId: string | null = null;
|
||||
|
||||
present(isRegistered: boolean, raceId: string, driverId: string): void {
|
||||
this.isRegistered = isRegistered;
|
||||
this.raceId = raceId;
|
||||
this.driverId = driverId;
|
||||
}
|
||||
}
|
||||
|
||||
class TestRaceRegistrationsPresenter implements IRaceRegistrationsPresenter {
|
||||
raceId: string | null = null;
|
||||
driverIds: string[] = [];
|
||||
|
||||
// Accepts either the legacy (raceId, driverIds) shape or the new (driverIds) shape
|
||||
present(raceIdOrDriverIds: string | string[], driverIds?: string[]): void {
|
||||
if (Array.isArray(raceIdOrDriverIds) && driverIds == null) {
|
||||
this.raceId = null;
|
||||
this.driverIds = raceIdOrDriverIds;
|
||||
return;
|
||||
}
|
||||
|
||||
this.raceId = raceIdOrDriverIds as string;
|
||||
this.driverIds = driverIds ?? [];
|
||||
}
|
||||
}
|
||||
|
||||
class InMemoryTeamRepository implements ITeamRepository {
|
||||
private teams: Team[] = [];
|
||||
|
||||
@@ -207,6 +243,10 @@ class InMemoryTeamMembershipRepository implements ITeamMembershipRepository {
|
||||
);
|
||||
}
|
||||
|
||||
async findByTeamId(teamId: string): Promise<TeamMembership[]> {
|
||||
return this.memberships.filter((m) => m.teamId === teamId);
|
||||
}
|
||||
|
||||
async saveMembership(membership: TeamMembership): Promise<TeamMembership> {
|
||||
const index = this.memberships.findIndex(
|
||||
(m) => m.teamId === membership.teamId && m.driverId === membership.driverId,
|
||||
@@ -267,8 +307,10 @@ describe('Racing application use-cases - registrations', () => {
|
||||
let membershipRepo: InMemoryLeagueMembershipRepositoryForRegistrations;
|
||||
let registerForRace: RegisterForRaceUseCase;
|
||||
let withdrawFromRace: WithdrawFromRaceUseCase;
|
||||
let isDriverRegistered: IsDriverRegisteredForRaceQuery;
|
||||
let getRaceRegistrations: GetRaceRegistrationsQuery;
|
||||
let isDriverRegistered: IsDriverRegisteredForRaceUseCase;
|
||||
let getRaceRegistrations: GetRaceRegistrationsUseCase;
|
||||
let driverRegistrationPresenter: TestDriverRegistrationStatusPresenter;
|
||||
let raceRegistrationsPresenter: TestRaceRegistrationsPresenter;
|
||||
|
||||
beforeEach(() => {
|
||||
registrationRepo = new InMemoryRaceRegistrationRepository();
|
||||
@@ -276,8 +318,16 @@ describe('Racing application use-cases - registrations', () => {
|
||||
|
||||
registerForRace = new RegisterForRaceUseCase(registrationRepo, membershipRepo);
|
||||
withdrawFromRace = new WithdrawFromRaceUseCase(registrationRepo);
|
||||
isDriverRegistered = new IsDriverRegisteredForRaceQuery(registrationRepo);
|
||||
getRaceRegistrations = new GetRaceRegistrationsQuery(registrationRepo);
|
||||
driverRegistrationPresenter = new TestDriverRegistrationStatusPresenter();
|
||||
isDriverRegistered = new IsDriverRegisteredForRaceUseCase(
|
||||
registrationRepo,
|
||||
driverRegistrationPresenter,
|
||||
);
|
||||
raceRegistrationsPresenter = new TestRaceRegistrationsPresenter();
|
||||
getRaceRegistrations = new GetRaceRegistrationsUseCase(
|
||||
registrationRepo,
|
||||
raceRegistrationsPresenter,
|
||||
);
|
||||
});
|
||||
|
||||
it('registers an active league member for a race and tracks registration', async () => {
|
||||
@@ -289,10 +339,13 @@ describe('Racing application use-cases - registrations', () => {
|
||||
|
||||
await registerForRace.execute({ raceId, leagueId, driverId });
|
||||
|
||||
expect(await isDriverRegistered.execute({ raceId, driverId })).toBe(true);
|
||||
await isDriverRegistered.execute({ raceId, driverId });
|
||||
expect(driverRegistrationPresenter.isRegistered).toBe(true);
|
||||
expect(driverRegistrationPresenter.raceId).toBe(raceId);
|
||||
expect(driverRegistrationPresenter.driverId).toBe(driverId);
|
||||
|
||||
const registeredDrivers = await getRaceRegistrations.execute({ raceId });
|
||||
expect(registeredDrivers).toContain(driverId);
|
||||
await getRaceRegistrations.execute({ raceId });
|
||||
expect(raceRegistrationsPresenter.driverIds).toContain(driverId);
|
||||
});
|
||||
|
||||
it('throws when registering a non-member for a race', async () => {
|
||||
@@ -315,8 +368,11 @@ describe('Racing application use-cases - registrations', () => {
|
||||
|
||||
await withdrawFromRace.execute({ raceId, driverId });
|
||||
|
||||
expect(await isDriverRegistered.execute({ raceId, driverId })).toBe(false);
|
||||
expect(await getRaceRegistrations.execute({ raceId })).toEqual([]);
|
||||
await isDriverRegistered.execute({ raceId, driverId });
|
||||
expect(driverRegistrationPresenter.isRegistered).toBe(false);
|
||||
|
||||
await getRaceRegistrations.execute({ raceId });
|
||||
expect(raceRegistrationsPresenter.driverIds).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -330,11 +386,69 @@ describe('Racing application use-cases - teams', () => {
|
||||
let approveJoin: ApproveTeamJoinRequestUseCase;
|
||||
let rejectJoin: RejectTeamJoinRequestUseCase;
|
||||
let updateTeamUseCase: UpdateTeamUseCase;
|
||||
let getAllTeamsQuery: GetAllTeamsQuery;
|
||||
let getTeamDetailsQuery: GetTeamDetailsQuery;
|
||||
let getTeamMembersQuery: GetTeamMembersQuery;
|
||||
let getTeamJoinRequestsQuery: GetTeamJoinRequestsQuery;
|
||||
let getDriverTeamQuery: GetDriverTeamQuery;
|
||||
let getAllTeamsUseCase: GetAllTeamsUseCase;
|
||||
let getTeamDetailsUseCase: GetTeamDetailsUseCase;
|
||||
let getTeamMembersUseCase: GetTeamMembersUseCase;
|
||||
let getTeamJoinRequestsUseCase: GetTeamJoinRequestsUseCase;
|
||||
let getDriverTeamUseCase: GetDriverTeamUseCase;
|
||||
|
||||
class FakeDriverRepository {
|
||||
async findById(driverId: string): Promise<{ id: string; name: string } | null> {
|
||||
return { id: driverId, name: `Driver ${driverId}` };
|
||||
}
|
||||
}
|
||||
|
||||
class FakeImageService {
|
||||
getDriverAvatar(driverId: string): string {
|
||||
return `https://example.com/avatar/${driverId}.png`;
|
||||
}
|
||||
}
|
||||
|
||||
class TestAllTeamsPresenter implements IAllTeamsPresenter {
|
||||
teams: any[] = [];
|
||||
|
||||
present(teams: any[]): void {
|
||||
this.teams = teams;
|
||||
}
|
||||
}
|
||||
|
||||
class TestTeamDetailsPresenter implements ITeamDetailsPresenter {
|
||||
viewModel: any = null;
|
||||
|
||||
present(team: any, membership: any, driverId: string): void {
|
||||
this.viewModel = { team, membership, driverId };
|
||||
}
|
||||
}
|
||||
|
||||
class TestTeamMembersPresenter implements ITeamMembersPresenter {
|
||||
members: any[] = [];
|
||||
|
||||
present(members: any[]): void {
|
||||
this.members = members;
|
||||
}
|
||||
}
|
||||
|
||||
class TestTeamJoinRequestsPresenter implements ITeamJoinRequestsPresenter {
|
||||
requests: any[] = [];
|
||||
|
||||
present(requests: any[]): void {
|
||||
this.requests = requests;
|
||||
}
|
||||
}
|
||||
|
||||
class TestDriverTeamPresenter implements IDriverTeamPresenter {
|
||||
viewModel: any = null;
|
||||
|
||||
present(team: any, membership: any, driverId: string): void {
|
||||
this.viewModel = { team, membership, driverId };
|
||||
}
|
||||
}
|
||||
|
||||
let allTeamsPresenter: TestAllTeamsPresenter;
|
||||
let teamDetailsPresenter: TestTeamDetailsPresenter;
|
||||
let teamMembersPresenter: TestTeamMembersPresenter;
|
||||
let teamJoinRequestsPresenter: TestTeamJoinRequestsPresenter;
|
||||
let driverTeamPresenter: TestDriverTeamPresenter;
|
||||
|
||||
beforeEach(() => {
|
||||
teamRepo = new InMemoryTeamRepository();
|
||||
@@ -346,11 +460,43 @@ describe('Racing application use-cases - teams', () => {
|
||||
approveJoin = new ApproveTeamJoinRequestUseCase(membershipRepo);
|
||||
rejectJoin = new RejectTeamJoinRequestUseCase(membershipRepo);
|
||||
updateTeamUseCase = new UpdateTeamUseCase(teamRepo, membershipRepo);
|
||||
getAllTeamsQuery = new GetAllTeamsQuery(teamRepo);
|
||||
getTeamDetailsQuery = new GetTeamDetailsQuery(teamRepo, membershipRepo);
|
||||
getTeamMembersQuery = new GetTeamMembersQuery(membershipRepo);
|
||||
getTeamJoinRequestsQuery = new GetTeamJoinRequestsQuery(membershipRepo);
|
||||
getDriverTeamQuery = new GetDriverTeamQuery(teamRepo, membershipRepo);
|
||||
|
||||
allTeamsPresenter = new TestAllTeamsPresenter();
|
||||
getAllTeamsUseCase = new GetAllTeamsUseCase(
|
||||
teamRepo,
|
||||
membershipRepo,
|
||||
allTeamsPresenter,
|
||||
);
|
||||
|
||||
teamDetailsPresenter = new TestTeamDetailsPresenter();
|
||||
getTeamDetailsUseCase = new GetTeamDetailsUseCase(
|
||||
teamRepo,
|
||||
membershipRepo,
|
||||
teamDetailsPresenter,
|
||||
);
|
||||
|
||||
teamMembersPresenter = new TestTeamMembersPresenter();
|
||||
getTeamMembersUseCase = new GetTeamMembersUseCase(
|
||||
membershipRepo,
|
||||
new FakeDriverRepository() as any,
|
||||
new FakeImageService() as any,
|
||||
teamMembersPresenter,
|
||||
);
|
||||
|
||||
teamJoinRequestsPresenter = new TestTeamJoinRequestsPresenter();
|
||||
getTeamJoinRequestsUseCase = new GetTeamJoinRequestsUseCase(
|
||||
membershipRepo,
|
||||
new FakeDriverRepository() as any,
|
||||
new FakeImageService() as any,
|
||||
teamJoinRequestsPresenter,
|
||||
);
|
||||
|
||||
driverTeamPresenter = new TestDriverTeamPresenter();
|
||||
getDriverTeamUseCase = new GetDriverTeamUseCase(
|
||||
teamRepo,
|
||||
membershipRepo,
|
||||
driverTeamPresenter,
|
||||
);
|
||||
});
|
||||
|
||||
it('creates a team and assigns creator as active owner', async () => {
|
||||
@@ -449,13 +595,10 @@ describe('Racing application use-cases - teams', () => {
|
||||
updatedBy: ownerId,
|
||||
});
|
||||
|
||||
const teamDetails = await getTeamDetailsQuery.execute({
|
||||
teamId: created.team.id,
|
||||
driverId: ownerId,
|
||||
});
|
||||
await getTeamDetailsUseCase.execute(created.team.id, ownerId);
|
||||
|
||||
expect(teamDetails.team.name).toBe('Updated Name');
|
||||
expect(teamDetails.team.description).toBe('Updated description');
|
||||
expect(teamDetailsPresenter.viewModel.team.name).toBe('Updated Name');
|
||||
expect(teamDetailsPresenter.viewModel.team.description).toBe('Updated description');
|
||||
});
|
||||
|
||||
it('returns driver team via query matching legacy getDriverTeam behavior', async () => {
|
||||
@@ -469,7 +612,8 @@ describe('Racing application use-cases - teams', () => {
|
||||
leagues: [],
|
||||
});
|
||||
|
||||
const result = await getDriverTeamQuery.execute({ driverId: ownerId });
|
||||
await getDriverTeamUseCase.execute(ownerId);
|
||||
const result = driverTeamPresenter.viewModel;
|
||||
expect(result).not.toBeNull();
|
||||
expect(result?.team.id).toBe(team.id);
|
||||
expect(result?.membership.driverId).toBe(ownerId);
|
||||
@@ -489,11 +633,11 @@ describe('Racing application use-cases - teams', () => {
|
||||
|
||||
await joinTeam.execute({ teamId: team.id, driverId: otherDriverId });
|
||||
|
||||
const teams = await getAllTeamsQuery.execute();
|
||||
expect(teams.length).toBe(1);
|
||||
await getAllTeamsUseCase.execute();
|
||||
expect(allTeamsPresenter.teams.length).toBe(1);
|
||||
|
||||
const members = await getTeamMembersQuery.execute({ teamId: team.id });
|
||||
const memberIds = members.map((m) => m.driverId).sort();
|
||||
await getTeamMembersUseCase.execute(team.id);
|
||||
const memberIds = teamMembersPresenter.members.map((m) => m.driverId).sort();
|
||||
expect(memberIds).toEqual([ownerId, otherDriverId].sort());
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user