import { beforeEach, expect, mock, test } from 'bun:test'; import { Errors } from '@/lib/errors'; import { type Result, err, ok } from '@/lib/result'; import type { InviteComplexUserResponse } from '@repo/api-contract'; type InviteComplexUserFn = ( userId: string, complexId: string, input: { email: string } ) => Promise>; const inviteComplexUserMock = mock(async () => undefined as never); const { createInviteComplexUserHandler } = await import( '@/modules/complex/features/invite-complex-user/invite-complex-user.handler' ); const inviteComplexUserHandler = createInviteComplexUserHandler({ inviteComplexUser: inviteComplexUserMock, }); 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(); }); 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(ok(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.mockResolvedValue( err(Errors.forbidden('Solo un ADMIN puede administrar usuarios.')) ); 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({ type: 'https://api.myapp.dev/problems/forbidden', title: 'Forbidden', status: 403, detail: 'Solo un ADMIN puede administrar usuarios.', }); expect(json.mock.calls[0]?.[1]).toBe(403); expect(response).toBeDefined(); });