import { beforeEach, expect, mock, test } from 'bun:test'; import { prismaMock, sendMailMock, transactionMock } from '../support/prisma.mock'; import { ComplexMembersError, inviteComplexUser, } from '@/modules/complex/services/complex-members.service'; beforeEach(() => { prismaMock._reset(); mock.clearAllMocks(); }); test('creates a pending invitation and sends the email', async () => { prismaMock.complexUser.findUnique.mockResolvedValue({ role: 'ADMIN' } as never); prismaMock.complex.findUnique.mockResolvedValue({ complexName: 'Playzer Norte' } as never); prismaMock.user.findUnique.mockResolvedValue(null); prismaMock.complexInvitation.findFirst.mockResolvedValue(null); prismaMock.complexInvitation.create.mockResolvedValue({ id: 'inv-1', complexId: 'complex-1', email: 'new.member@example.com', tokenHash: 'token-hash', expiresAt: new Date('2026-04-29T00:00:00.000Z'), acceptedAt: null, revokedAt: null, createdAt: new Date('2026-04-22T00:00:00.000Z'), } as never); const result = await inviteComplexUser('admin-1', 'complex-1', { email: ' New.Member@example.com ', }); expect(result.invitation.email).toBe('new.member@example.com'); expect(result.invitation.status).toBe('PENDING'); expect(prismaMock.complexInvitation.create).toHaveBeenCalledTimes(1); const createArgs = prismaMock.complexInvitation.create.mock.calls[0]?.[0] as { data: { complexId: string; email: string; id: string; tokenHash: string; expiresAt: Date; }; }; expect(createArgs.data.complexId).toBe('complex-1'); expect(createArgs.data.email).toBe('new.member@example.com'); expect(typeof createArgs.data.id).toBe('string'); expect(typeof createArgs.data.tokenHash).toBe('string'); expect(sendMailMock).toHaveBeenCalledTimes(1); expect(transactionMock).toHaveBeenCalledTimes(1); const mailArgs = sendMailMock.mock.calls[0][0] as { to: string; subject: string; }; expect(mailArgs.to).toBe('new.member@example.com'); expect(mailArgs.subject).toContain('Playzer Norte'); }); test('rejects when the invite target already belongs to the complex', async () => { prismaMock.complexUser.findUnique .mockResolvedValueOnce({ role: 'ADMIN' } as never) .mockResolvedValueOnce({ userId: 'member-1' } as never); prismaMock.complex.findUnique.mockResolvedValue({ complexName: 'Playzer Norte' } as never); prismaMock.user.findUnique.mockResolvedValue({ id: 'member-1' } as never); let caught: unknown; try { await inviteComplexUser('admin-1', 'complex-1', { email: 'member@example.com', }); } catch (error) { caught = error; } expect(caught).toBeInstanceOf(ComplexMembersError); expect((caught as ComplexMembersError).status).toBe(409); expect(transactionMock).not.toHaveBeenCalled(); expect(sendMailMock).not.toHaveBeenCalled(); });