Files
playzer/apps/backend/test/complex/invite-complex-user.handler.test.ts

125 lines
3.3 KiB
TypeScript

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<Result<InviteComplexUserResponse>>;
const inviteComplexUserMock = mock<InviteComplexUserFn>(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<string, string>;
valid: () => unknown;
};
json: ReturnType<typeof mock>;
};
function createContext(input: {
userId: string;
params: Record<string, string>;
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();
});