import { vi } from 'vitest'; // Mock data types that match what the use cases expect export interface DriverData { id: string; iracingId: string; name: string; country: string; bio?: string; joinedAt: Date; category?: string; } export interface TeamData { id: string; name: string; tag: string; description: string; ownerId: string; leagues: string[]; category?: string; isRecruiting: boolean; createdAt: Date; } export interface TeamMembership { teamId: string; driverId: string; role: 'owner' | 'manager' | 'driver'; status: 'active' | 'pending' | 'none'; joinedAt: Date; } // Simple in-memory repositories for testing export class TestDriverRepository { private drivers = new Map(); async findById(id: string): Promise { return this.drivers.get(id) || null; } async create(driver: DriverData): Promise { if (this.drivers.has(driver.id)) { throw new Error('Driver already exists'); } this.drivers.set(driver.id, driver); return driver; } clear(): void { this.drivers.clear(); } } export class TestTeamRepository { private teams = new Map(); async findById(id: string): Promise { return this.teams.get(id) || null; } async create(team: TeamData): Promise { // Check for duplicate team name/tag const existingTeams = Array.from(this.teams.values()); for (const existing of existingTeams) { if (existing.name === team.name && existing.tag === team.tag) { const error: any = new Error(`Team already exists: ${team.name} (${team.tag})`); error.code = 'DUPLICATE_TEAM'; throw error; } } this.teams.set(team.id, team); return team; } async findAll(): Promise { return Array.from(this.teams.values()); } clear(): void { this.teams.clear(); } } export class TestTeamMembershipRepository { private memberships = new Map(); async getMembership(teamId: string, driverId: string): Promise { const teamMemberships = this.memberships.get(teamId) || []; return teamMemberships.find(m => m.driverId === driverId) || null; } async getActiveMembershipForDriver(driverId: string): Promise { for (const teamMemberships of this.memberships.values()) { const active = teamMemberships.find(m => m.driverId === driverId && m.status === 'active'); if (active) return active; } return null; } async saveMembership(membership: TeamMembership): Promise { const teamMemberships = this.memberships.get(membership.teamId) || []; const existingIndex = teamMemberships.findIndex( m => m.driverId === membership.driverId ); if (existingIndex >= 0) { // Check if already active const existing = teamMemberships[existingIndex]; if (existing && existing.status === 'active') { const error: any = new Error('Already a member'); error.code = 'ALREADY_MEMBER'; throw error; } teamMemberships[existingIndex] = membership; } else { teamMemberships.push(membership); } this.memberships.set(membership.teamId, teamMemberships); return membership; } clear(): void { this.memberships.clear(); } } // Mock use case implementations export class CreateTeamUseCase { constructor( private driverRepository: TestDriverRepository, private teamRepository: TestTeamRepository, private membershipRepository: TestTeamMembershipRepository ) {} async execute(input: { name: string; tag: string; description: string; ownerId: string; leagues: string[]; }): Promise<{ isOk: () => boolean; isErr: () => boolean; error?: any }> { try { // Check if driver exists const driver = await this.driverRepository.findById(input.ownerId); if (!driver) { return { isOk: () => false, isErr: () => true, error: { code: 'VALIDATION_ERROR', details: { message: 'Driver not found' } } }; } // Check if driver already belongs to a team const existingMembership = await this.membershipRepository.getActiveMembershipForDriver(input.ownerId); if (existingMembership) { return { isOk: () => false, isErr: () => true, error: { code: 'VALIDATION_ERROR', details: { message: 'Driver already belongs to a team' } } }; } const teamId = `team-${Date.now()}-${Math.random()}`; const team: TeamData = { id: teamId, name: input.name, tag: input.tag, description: input.description, ownerId: input.ownerId, leagues: input.leagues, isRecruiting: false, createdAt: new Date(), }; await this.teamRepository.create(team); // Create owner membership const membership: TeamMembership = { teamId: team.id, driverId: input.ownerId, role: 'owner', status: 'active', joinedAt: new Date(), }; await this.membershipRepository.saveMembership(membership); return { isOk: () => true, isErr: () => false, }; } catch (error: any) { return { isOk: () => false, isErr: () => true, error: { code: error.code || 'REPOSITORY_ERROR', details: { message: error.message } } }; } } } export class JoinTeamUseCase { constructor( private driverRepository: TestDriverRepository, private teamRepository: TestTeamRepository, private membershipRepository: TestTeamMembershipRepository ) {} async execute(input: { teamId: string; driverId: string; }): Promise<{ isOk: () => boolean; isErr: () => boolean; error?: any }> { try { // Check if team exists const team = await this.teamRepository.findById(input.teamId); if (!team) { return { isOk: () => false, isErr: () => true, error: { code: 'TEAM_NOT_FOUND', details: { message: 'Team not found' } } }; } // Check if driver exists const driver = await this.driverRepository.findById(input.driverId); if (!driver) { return { isOk: () => false, isErr: () => true, error: { code: 'DRIVER_NOT_FOUND', details: { message: 'Driver not found' } } }; } // Check if driver already belongs to a team const existingActive = await this.membershipRepository.getActiveMembershipForDriver(input.driverId); if (existingActive) { return { isOk: () => false, isErr: () => true, error: { code: 'ALREADY_MEMBER', details: { message: 'Driver already belongs to a team' } } }; } // Check if already has membership (pending or active) const existingMembership = await this.membershipRepository.getMembership(input.teamId, input.driverId); if (existingMembership) { return { isOk: () => false, isErr: () => true, error: { code: 'ALREADY_MEMBER', details: { message: 'Already a member or have a pending request' } } }; } const membership: TeamMembership = { teamId: input.teamId, driverId: input.driverId, role: 'driver', status: 'active', joinedAt: new Date(), }; await this.membershipRepository.saveMembership(membership); return { isOk: () => true, isErr: () => false, }; } catch (error: any) { return { isOk: () => false, isErr: () => true, error: { code: error.code || 'REPOSITORY_ERROR', details: { message: error.message } } }; } } } export class DatabaseTestContext { public readonly driverRepository: TestDriverRepository; public readonly teamRepository: TestTeamRepository; public readonly teamMembershipRepository: TestTeamMembershipRepository; public readonly createTeamUseCase: CreateTeamUseCase; public readonly joinTeamUseCase: JoinTeamUseCase; constructor() { this.driverRepository = new TestDriverRepository(); this.teamRepository = new TestTeamRepository(); this.teamMembershipRepository = new TestTeamMembershipRepository(); this.createTeamUseCase = new CreateTeamUseCase(this.driverRepository, this.teamRepository, this.teamMembershipRepository); this.joinTeamUseCase = new JoinTeamUseCase(this.driverRepository, this.teamRepository, this.teamMembershipRepository); } public clear(): void { this.driverRepository.clear(); this.teamRepository.clear(); this.teamMembershipRepository.clear(); vi.clearAllMocks(); } public static create(): DatabaseTestContext { return new DatabaseTestContext(); } }