import { beforeEach, expect, mock, test } from 'bun:test'; import type { InviteComplexUserResponse } from '@repo/api-contract'; import { createInviteComplexUserHandler } from '@/modules/complex/handlers/invite-complex-user.handler'; const inviteComplexUserMock = mock( async () => undefined as unknown as InviteComplexUserResponse ); class MockComplexMembersError extends Error { status: 400 | 403 | 404 | 409; constructor(message: string, status: 400 | 403 | 404 | 409 = 400) { super(message); this.name = 'ComplexMembersError'; this.status = status; } } const inviteComplexUserHandler = createInviteComplexUserHandler({ inviteComplexUser: inviteComplexUserMock, ComplexMembersError: MockComplexMembersError, }); type HandlerContext = { get: (key: 'user' | 'session') => { id: string } | undefined; req: { param: () => Record; valid: () => unknown; }; json: ReturnType; }; function createContext(input: { userId: string; params: Record; body: unknown; }) { const json = mock((payload: unknown, init?: unknown) => ({ payload, init, })); const c = { get: (key: 'user' | 'session') => { if (key === 'user') { return { id: input.userId }; } return undefined; }, req: { param: () => input.params, valid: () => input.body, }, json, } as unknown as HandlerContext; return { c, json }; } beforeEach(() => { inviteComplexUserMock.mockReset(); mock.clearAllMocks(); }); test('returns 201 with the service result', async () => { const serviceResult = { invitation: { id: 'inv-1', complexId: 'complex-1', email: 'new.member@example.com', status: 'PENDING', createdAt: '2026-04-22T00:00:00.000Z', expiresAt: '2026-04-29T00:00:00.000Z', acceptedAt: null, revokedAt: null, }, } as const; inviteComplexUserMock.mockResolvedValue(serviceResult); const { c, json } = createContext({ userId: 'admin-1', params: { id: '11111111-1111-4111-8111-111111111111' }, body: { email: 'new.member@example.com' }, }); const response = await inviteComplexUserHandler(c as never); expect(inviteComplexUserMock).toHaveBeenCalledWith( 'admin-1', '11111111-1111-4111-8111-111111111111', { email: 'new.member@example.com' } ); expect(json.mock.calls[0]?.[0]).toEqual(serviceResult); expect(json.mock.calls[0]?.[1]).toBe(201); expect(response).toBeDefined(); }); test('maps ComplexMembersError to an error response', async () => { inviteComplexUserMock.mockRejectedValue( new MockComplexMembersError('Solo un ADMIN puede administrar usuarios.', 403) ); const { c, json } = createContext({ userId: 'employee-1', params: { id: '11111111-1111-4111-8111-111111111111' }, body: { email: 'new.member@example.com' }, }); const response = await inviteComplexUserHandler(c as never); expect(inviteComplexUserMock).toHaveBeenCalledWith( 'employee-1', '11111111-1111-4111-8111-111111111111', { email: 'new.member@example.com' } ); expect(json.mock.calls[0]?.[0]).toEqual({ message: 'Solo un ADMIN puede administrar usuarios.', }); expect(json.mock.calls[0]?.[1]).toEqual({ status: 403 }); expect(response).toBeDefined(); });