134 lines
4.1 KiB
TypeScript
134 lines
4.1 KiB
TypeScript
import { describe, it, expect, beforeEach, vi, Mock } from 'vitest';
|
|
|
|
import { JoinLeagueUseCase } from '@core/racing/application/use-cases/JoinLeagueUseCase';
|
|
import type { ILeagueMembershipRepository } from '@core/racing/domain/repositories/ILeagueMembershipRepository';
|
|
import type { Logger } from '@core/shared/application';
|
|
import { LeagueMembership } from '@core/racing/domain/entities/LeagueMembership';
|
|
import type { JoinRequest } from '@core/racing/domain/entities/LeagueMembership';
|
|
|
|
class InMemoryLeagueMembershipRepository implements ILeagueMembershipRepository {
|
|
private memberships: LeagueMembership[] = [];
|
|
private joinRequests: JoinRequest[] = [];
|
|
|
|
async getMembership(leagueId: string, driverId: string): Promise<LeagueMembership | null> {
|
|
return (
|
|
this.memberships.find(
|
|
(m) => m.leagueId === leagueId && m.driverId === driverId,
|
|
) || null
|
|
);
|
|
}
|
|
|
|
async getLeagueMembers(leagueId: string): Promise<LeagueMembership[]> {
|
|
return this.memberships.filter(
|
|
(m) => m.leagueId === leagueId && m.status === 'active',
|
|
);
|
|
}
|
|
|
|
async getJoinRequests(leagueId: string): Promise<JoinRequest[]> {
|
|
return this.joinRequests.filter(
|
|
(r) => r.leagueId === leagueId,
|
|
);
|
|
}
|
|
|
|
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 saveJoinRequest(request: JoinRequest): Promise<JoinRequest> {
|
|
this.joinRequests.push(request);
|
|
return request;
|
|
}
|
|
|
|
async removeJoinRequest(requestId: string): Promise<void> {
|
|
this.joinRequests = this.joinRequests.filter(
|
|
(r) => r.id !== requestId,
|
|
);
|
|
}
|
|
|
|
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;
|
|
let logger: {
|
|
debug: Mock;
|
|
info: Mock;
|
|
warn: Mock;
|
|
error: Mock;
|
|
};
|
|
|
|
beforeEach(() => {
|
|
repository = new InMemoryLeagueMembershipRepository();
|
|
logger = {
|
|
debug: vi.fn(),
|
|
info: vi.fn(),
|
|
warn: vi.fn(),
|
|
error: vi.fn(),
|
|
};
|
|
useCase = new JoinLeagueUseCase(
|
|
repository as unknown as ILeagueMembershipRepository,
|
|
logger as unknown as Logger,
|
|
);
|
|
});
|
|
|
|
it('creates an active member when driver has no membership', async () => {
|
|
const leagueId = 'league-1';
|
|
const driverId = 'driver-1';
|
|
|
|
const result = await useCase.execute({ leagueId, driverId });
|
|
|
|
expect(result.isOk()).toBe(true);
|
|
const membership = result.unwrap();
|
|
expect(membership.leagueId).toBe(leagueId);
|
|
expect(membership.driverId).toBe(driverId);
|
|
expect(membership.role).toBe('member');
|
|
expect(membership.status).toBe('active');
|
|
expect(membership.joinedAt).toBeInstanceOf(Date);
|
|
});
|
|
|
|
it('returns error 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'),
|
|
}));
|
|
|
|
const result = await useCase.execute({ leagueId, driverId });
|
|
|
|
expect(result.isErr()).toBe(true);
|
|
expect(result.unwrapErr()).toEqual({
|
|
code: 'ALREADY_MEMBER',
|
|
details: { message: 'Already a member or have a pending request' },
|
|
});
|
|
});
|
|
});
|
|
}); |