121 lines
3.7 KiB
TypeScript
121 lines
3.7 KiB
TypeScript
import { describe, it, expect, beforeEach } from 'vitest';
|
|
|
|
import { JoinLeagueUseCase } from '@core/racing/application/use-cases/JoinLeagueUseCase';
|
|
import type { ILeagueMembershipRepository } from '@core/racing/domain/repositories/ILeagueMembershipRepository';
|
|
|
|
|
|
class InMemoryLeagueMembershipRepository implements ILeagueMembershipRepository {
|
|
private memberships: LeagueMembership[] = [];
|
|
|
|
async getMembership(leagueId: string, driverId: string): Promise<LeagueMembership | null> {
|
|
return (
|
|
this.memberships.find(
|
|
(m) => m.leagueId === leagueId && m.driverId === driverId,
|
|
) || null
|
|
);
|
|
}
|
|
|
|
async getActiveMembershipForDriver(driverId: string): Promise<LeagueMembership | null> {
|
|
return (
|
|
this.memberships.find(
|
|
(m) => m.driverId === driverId && m.status === 'active',
|
|
) || null
|
|
);
|
|
}
|
|
|
|
async getLeagueMembers(leagueId: string): Promise<LeagueMembership[]> {
|
|
return this.memberships.filter(
|
|
(m) => m.leagueId === leagueId && m.status === 'active',
|
|
);
|
|
}
|
|
|
|
async getTeamMembers(leagueId: string): Promise<LeagueMembership[]> {
|
|
return this.memberships.filter(
|
|
(m) => m.leagueId === leagueId && m.status === 'active',
|
|
);
|
|
}
|
|
|
|
async saveMembership(membership: LeagueMembership): Promise<LeagueMembership> {
|
|
const existingIndex = this.memberships.findIndex(
|
|
(m) => m.leagueId === membership.leagueId && m.driverId === membership.driverId,
|
|
);
|
|
|
|
if (existingIndex >= 0) {
|
|
this.memberships[existingIndex] = membership;
|
|
} else {
|
|
this.memberships.push(membership);
|
|
}
|
|
|
|
return membership;
|
|
}
|
|
|
|
async removeMembership(leagueId: string, driverId: string): Promise<void> {
|
|
this.memberships = this.memberships.filter(
|
|
(m) => !(m.leagueId === leagueId && m.driverId === driverId),
|
|
);
|
|
}
|
|
|
|
async getJoinRequests(): Promise<never> {
|
|
throw new Error('Not implemented for this test');
|
|
}
|
|
|
|
async saveJoinRequest(): Promise<never> {
|
|
throw new Error('Not implemented for this test');
|
|
}
|
|
|
|
async removeJoinRequest(): Promise<never> {
|
|
throw new Error('Not implemented for this test');
|
|
}
|
|
|
|
seedMembership(membership: LeagueMembership): void {
|
|
this.memberships.push(membership);
|
|
}
|
|
|
|
getAllMemberships(): LeagueMembership[] {
|
|
return [...this.memberships];
|
|
}
|
|
}
|
|
|
|
describe('Membership use-cases', () => {
|
|
describe('JoinLeagueUseCase', () => {
|
|
let repository: InMemoryLeagueMembershipRepository;
|
|
let useCase: JoinLeagueUseCase;
|
|
|
|
beforeEach(() => {
|
|
repository = new InMemoryLeagueMembershipRepository();
|
|
useCase = new JoinLeagueUseCase(repository);
|
|
});
|
|
|
|
it('creates an active member when driver has no membership', async () => {
|
|
const leagueId = 'league-1';
|
|
const driverId = 'driver-1';
|
|
|
|
await useCase.execute({ leagueId, driverId });
|
|
|
|
const membership = await repository.getMembership(leagueId, driverId);
|
|
expect(membership).not.toBeNull();
|
|
expect(membership?.leagueId).toBe(leagueId);
|
|
expect(membership?.driverId).toBe(driverId);
|
|
expect(membership?.role as MembershipRole).toBe('member');
|
|
expect(membership?.status as MembershipStatus).toBe('active');
|
|
expect(membership?.joinedAt).toBeInstanceOf(Date);
|
|
});
|
|
|
|
it('throws when driver already has membership for league', async () => {
|
|
const leagueId = 'league-1';
|
|
const driverId = 'driver-1';
|
|
|
|
repository.seedMembership(LeagueMembership.create({
|
|
leagueId,
|
|
driverId,
|
|
role: 'member',
|
|
status: 'active',
|
|
joinedAt: new Date('2024-01-01'),
|
|
}));
|
|
|
|
await expect(
|
|
useCase.execute({ leagueId, driverId }),
|
|
).rejects.toThrow('Already a member or have a pending request');
|
|
});
|
|
});
|
|
}); |