import { Logger } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { InvitationService } from './invitation.service'; import { SubscriptionService } from './subscription.service'; import { InvitationToken } from '@domain/entities/invitation-token.entity'; import { UserRole } from '@domain/entities/user.entity'; import { InvitationTokenRepository } from '@domain/ports/out/invitation-token.repository'; import { UserRepository } from '@domain/ports/out/user.repository'; import { OrganizationRepository } from '@domain/ports/out/organization.repository'; import { EmailPort } from '@domain/ports/out/email.port'; describe('invitation secret handling', () => { it('keeps the token in the email but out of success and failure logs', async () => { const log = jest.spyOn(Logger.prototype, 'log').mockImplementation(() => undefined); const error = jest.spyOn(Logger.prototype, 'error').mockImplementation(() => undefined); try { const invitation = InvitationToken.create({ id: 'invite-id', token: 'test-only-invitation-secret', email: 'user@example.org', firstName: 'Test', lastName: 'User', role: UserRole.USER, organizationId: 'org', invitedById: 'admin', expiresAt: new Date(Date.now() + 60_000), }); const send = jest.fn().mockResolvedValue(undefined); const service = new InvitationService( { findByToken: async () => invitation, update: async () => invitation, } as unknown as InvitationTokenRepository, { findById: async () => ({ firstName: 'Test', lastName: 'Admin' }), } as unknown as UserRepository, { findById: async () => ({ name: 'Company' }) } as unknown as OrganizationRepository, { sendInvitationWithToken: send } as unknown as EmailPort, new ConfigService({ FRONTEND_URL: 'https://example.org' }), {} as SubscriptionService ); await service['sendInvitationEmail'](invitation); expect(send.mock.calls[0][5]).toBe( 'https://example.org/register?token=test-only-invitation-secret' ); send.mockRejectedValue(new Error('test-only-invitation-secret')); await expect(service['sendInvitationEmail'](invitation)).rejects.toThrow(); await service.markInvitationAsUsed(invitation.token); expect(JSON.stringify([...log.mock.calls, ...error.mock.calls])).not.toContain( invitation.token ); } finally { log.mockRestore(); error.mockRestore(); } }); });