import { describe, it, expect, vi } from 'vitest'; import { UpdateTeamUseCase, type UpdateTeamInput, type UpdateTeamResult, type UpdateTeamErrorCode } from './UpdateTeamUseCase'; import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort'; import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode'; import type { ITeamRepository } from '../../domain/repositories/ITeamRepository'; import type { ITeamMembershipRepository } from '../../domain/repositories/ITeamMembershipRepository'; describe('UpdateTeamUseCase', () => { it('updates team successfully', async () => { const mockMembership = { role: 'owner', }; const mockUpdatedTeam = { id: 'team-1' }; const mockTeam = { id: 'team-1', update: vi.fn().mockReturnValue(mockUpdatedTeam), }; const mockTeamRepository = { findById: vi.fn().mockResolvedValue(mockTeam), update: vi.fn().mockResolvedValue(undefined), } as unknown as ITeamRepository; const mockMembershipRepository = { getMembership: vi.fn().mockResolvedValue(mockMembership), } as unknown as ITeamMembershipRepository; const present = vi.fn<(data: UpdateTeamResult) => void>(); const output: UseCaseOutputPort & { present: typeof present } = { present, }; const useCase = new UpdateTeamUseCase(mockTeamRepository, mockMembershipRepository, output); const command: UpdateTeamInput = { teamId: 'team-1', updatedBy: 'user-1', updates: { name: 'New Name', tag: 'NEW' }, }; const result = await useCase.execute(command); expect(result.isOk()).toBe(true); expect(result.unwrap()).toBeUndefined(); expect(mockMembershipRepository.getMembership).toHaveBeenCalledWith('team-1', 'user-1'); expect(mockTeamRepository.findById).toHaveBeenCalledWith('team-1'); expect(mockTeam.update).toHaveBeenCalledWith({ name: 'New Name', tag: 'NEW' }); expect(mockTeamRepository.update).toHaveBeenCalledWith(mockUpdatedTeam); expect(present).toHaveBeenCalledTimes(1); const firstCall = present.mock.calls[0]; expect(firstCall).toBeDefined(); const presented = firstCall![0] as UpdateTeamResult; expect(presented.team).toBe(mockUpdatedTeam); }); it('returns permission denied error if insufficient permissions', async () => { const mockMembership = { role: 'member', }; const mockMembershipRepository = { getMembership: vi.fn().mockResolvedValue(mockMembership), } as unknown as ITeamMembershipRepository; const present = vi.fn<(data: UpdateTeamResult) => void>(); const output: UseCaseOutputPort & { present: typeof present } = { present, }; const useCase = new UpdateTeamUseCase({} as unknown as ITeamRepository, mockMembershipRepository, output); const command: UpdateTeamInput = { teamId: 'team-1', updatedBy: 'user-1', updates: { name: 'New Name' }, }; const result = await useCase.execute(command); expect(result.isErr()).toBe(true); const error = result.unwrapErr() as ApplicationErrorCode; expect(error.code).toBe('PERMISSION_DENIED'); expect(error.details?.message).toBe('User does not have permission to update this team'); expect(present).not.toHaveBeenCalled(); }); it('returns error if team not found', async () => { const mockMembership = { role: 'owner', }; const mockTeamRepository = { findById: vi.fn().mockResolvedValue(null), } as unknown as ITeamRepository; const mockMembershipRepository = { getMembership: vi.fn().mockResolvedValue(mockMembership), } as unknown as ITeamMembershipRepository; const present = vi.fn<(data: UpdateTeamResult) => void>(); const output: UseCaseOutputPort & { present: typeof present } = { present, }; const useCase = new UpdateTeamUseCase(mockTeamRepository, mockMembershipRepository, output); const command: UpdateTeamInput = { teamId: 'team-1', updatedBy: 'user-1', updates: { name: 'New Name' }, }; const result = await useCase.execute(command); expect(result.isErr()).toBe(true); const error = result.unwrapErr() as ApplicationErrorCode; expect(error.code).toBe('TEAM_NOT_FOUND'); expect(error.details?.message).toBe('Team not found'); expect(present).not.toHaveBeenCalled(); }); it('returns repository error on unexpected failure', async () => { const mockMembership = { role: 'owner', }; const mockTeamRepository = { findById: vi.fn().mockRejectedValue(new Error('db error')), } as unknown as ITeamRepository; const mockMembershipRepository = { getMembership: vi.fn().mockResolvedValue(mockMembership), } as unknown as ITeamMembershipRepository; const present = vi.fn<(data: UpdateTeamResult) => void>(); const output: UseCaseOutputPort & { present: typeof present } = { present, }; const useCase = new UpdateTeamUseCase(mockTeamRepository, mockMembershipRepository, output); const command: UpdateTeamInput = { teamId: 'team-1', updatedBy: 'user-1', updates: { name: 'New Name' }, }; const result = await useCase.execute(command); expect(result.isErr()).toBe(true); const error = result.unwrapErr() as ApplicationErrorCode; expect(error.code).toBe('REPOSITORY_ERROR'); expect(error.details?.message).toBe('db error'); expect(present).not.toHaveBeenCalled(); }); });