82 lines
2.8 KiB
TypeScript
82 lines
2.8 KiB
TypeScript
import { beforeEach, expect, test } from 'bun:test';
|
|
|
|
import { prismaMock, sendMailMock, transactionMock } from '../support/prisma.mock';
|
|
|
|
const { inviteComplexUser } = await import(
|
|
'@/modules/complex/features/invite-complex-user/invite-complex-user.business'
|
|
);
|
|
|
|
beforeEach(() => {
|
|
prismaMock._reset();
|
|
sendMailMock.mockClear();
|
|
transactionMock.mockClear();
|
|
});
|
|
|
|
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('2027-01-01T00:00:00.000Z'),
|
|
acceptedAt: null,
|
|
revokedAt: null,
|
|
createdAt: new Date('2026-12-01T00:00:00.000Z'),
|
|
} as never);
|
|
|
|
const result = await inviteComplexUser('admin-1', 'complex-1', {
|
|
email: ' New.Member@example.com ',
|
|
});
|
|
|
|
expect(result.ok).toBe(true);
|
|
if (!result.ok) return;
|
|
expect(result.value.invitation.email).toBe('new.member@example.com');
|
|
expect(result.value.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);
|
|
|
|
const result = await inviteComplexUser('admin-1', 'complex-1', {
|
|
email: 'member@example.com',
|
|
});
|
|
|
|
expect(result.ok).toBe(false);
|
|
expect(transactionMock).not.toHaveBeenCalled();
|
|
expect(sendMailMock).not.toHaveBeenCalled();
|
|
});
|