import { describe, it, expect, vi } from 'vitest'; import { UpdateLeagueMemberRoleUseCase, type UpdateLeagueMemberRoleInput, type UpdateLeagueMemberRoleErrorCode, } from './UpdateLeagueMemberRoleUseCase'; import type { LeagueMembershipRepository } from '../../domain/repositories/LeagueMembershipRepository'; import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode'; describe('UpdateLeagueMemberRoleUseCase', () => { it('updates league member role successfully', async () => { const mockMembership = { id: 'league-1:driver-1', leagueId: { toString: () => 'league-1' }, driverId: { toString: () => 'driver-1' }, role: { toString: () => 'member' }, status: { toString: () => 'active' }, joinedAt: { toDate: () => new Date() }, }; const mockLeagueMembershipRepository = { getLeagueMembers: vi.fn().mockResolvedValue([mockMembership]), saveMembership: vi.fn().mockResolvedValue(undefined), }; const useCase = new UpdateLeagueMemberRoleUseCase(mockLeagueMembershipRepository as unknown as LeagueMembershipRepository); const input: UpdateLeagueMemberRoleInput = { leagueId: 'league-1', targetDriverId: 'driver-1', newRole: 'admin', }; const result = await useCase.execute(input); expect(result.isOk()).toBe(true); const presented = result.unwrap(); expect(mockLeagueMembershipRepository.getLeagueMembers).toHaveBeenCalledWith('league-1'); expect(mockLeagueMembershipRepository.saveMembership).toHaveBeenCalledTimes(1); expect(presented.membership.id).toBe('league-1:driver-1'); expect(presented.membership.leagueId.toString()).toBe('league-1'); expect(presented.membership.driverId.toString()).toBe('driver-1'); expect(presented.membership.role.toString()).toBe('admin'); }); it('returns error if membership not found', async () => { const mockLeagueMembershipRepository = { getLeagueMembers: vi.fn().mockResolvedValue([]), saveMembership: vi.fn(), }; const useCase = new UpdateLeagueMemberRoleUseCase(mockLeagueMembershipRepository as unknown as LeagueMembershipRepository); const input: UpdateLeagueMemberRoleInput = { leagueId: 'league-1', targetDriverId: 'driver-1', newRole: 'admin', }; const result = await useCase.execute(input); expect(result.isErr()).toBe(true); const error = result.unwrapErr() as ApplicationErrorCode< UpdateLeagueMemberRoleErrorCode, { message: string } >; expect(error.code).toBe('MEMBERSHIP_NOT_FOUND'); expect(error.details.message).toBe('League membership not found'); }); it('handles repository errors', async () => { const mockLeagueMembershipRepository = { getLeagueMembers: vi .fn() .mockRejectedValue(new Error('Database connection failed')), saveMembership: vi.fn(), }; const useCase = new UpdateLeagueMemberRoleUseCase(mockLeagueMembershipRepository as unknown as LeagueMembershipRepository); const input: UpdateLeagueMemberRoleInput = { leagueId: 'league-1', targetDriverId: 'driver-1', newRole: 'admin', }; const result = await useCase.execute(input); expect(result.isErr()).toBe(true); const error = result.unwrapErr() as ApplicationErrorCode< UpdateLeagueMemberRoleErrorCode, { message: string } >; expect(error.code).toBe('REPOSITORY_ERROR'); expect(error.details.message).toBe('Database connection failed'); }); it('rejects invalid roles', async () => { const mockMembership = { id: 'league-1:driver-1', leagueId: { toString: () => 'league-1' }, driverId: { toString: () => 'driver-1' }, role: { toString: () => 'member' }, status: { toString: () => 'active' }, joinedAt: { toDate: () => new Date() }, }; const mockLeagueMembershipRepository = { getLeagueMembers: vi.fn().mockResolvedValue([mockMembership]), saveMembership: vi.fn().mockResolvedValue(undefined), }; const useCase = new UpdateLeagueMemberRoleUseCase(mockLeagueMembershipRepository as unknown as LeagueMembershipRepository); const result = await useCase.execute({ leagueId: 'league-1', targetDriverId: 'driver-1', newRole: 'manager' as unknown as 'member', }); expect(result.isErr()).toBe(true); const error = result.unwrapErr() as ApplicationErrorCode< UpdateLeagueMemberRoleErrorCode, { message: string } >; expect(error.code).toBe('INVALID_ROLE'); expect(mockLeagueMembershipRepository.saveMembership).not.toHaveBeenCalled(); }); it('prevents downgrading the last owner', async () => { const mockOwnerMembership = { id: 'league-1:owner-1', leagueId: { toString: () => 'league-1' }, driverId: { toString: () => 'owner-1' }, role: { toString: () => 'owner' }, status: { toString: () => 'active' }, joinedAt: { toDate: () => new Date() }, }; const mockLeagueMembershipRepository = { getLeagueMembers: vi.fn().mockResolvedValue([mockOwnerMembership]), saveMembership: vi.fn().mockResolvedValue(undefined), }; const useCase = new UpdateLeagueMemberRoleUseCase(mockLeagueMembershipRepository as unknown as LeagueMembershipRepository); const result = await useCase.execute({ leagueId: 'league-1', targetDriverId: 'owner-1', newRole: 'admin', }); expect(result.isErr()).toBe(true); const error = result.unwrapErr() as ApplicationErrorCode< UpdateLeagueMemberRoleErrorCode, { message: string } >; expect(error.code).toBe('CANNOT_DOWNGRADE_LAST_OWNER'); expect(mockLeagueMembershipRepository.saveMembership).not.toHaveBeenCalled(); }); });