import {vi, describe, it, expect, beforeEach, type Mock} from 'vitest'; vi.mock('../../src/common/common.mail.js', () => ({ MailService: {sendMail: vi.fn()} })); vi.mock('../../src/models/admin/admin.config.js', () => ({ ADMIN_APP_URL: 'https://admin.nachklang.art' })); import {MailService} from '../../src/common/common.mail.js'; import {sendInvitationMail, sendPasswordResetMail} from '../../src/models/admin/admin.mail.js'; const sendMail = MailService.sendMail as Mock; beforeEach(() => { sendMail.mockReset(); sendMail.mockResolvedValue(true); }); describe('sendInvitationMail', () => { it('points at the admin app and carries the token in the query string', async () => { await sendInvitationMail('a@nachklang.art', 'Anna', 'tok-en_123', new Date('2026-09-12T10:00:00Z')); const [to, subject, text, options] = sendMail.mock.calls[0]; expect(to).toBe('a@nachklang.art'); expect(subject).toBeTruthy(); expect(text).toContain('https://admin.nachklang.art/accept-invite?token=tok-en_123'); expect(options.html).toContain('https://admin.nachklang.art/accept-invite?token=tok-en_123'); }); it('url-encodes a token containing url-significant characters', async () => { await sendInvitationMail('a@nachklang.art', 'Anna', 'a+b/c=d', new Date()); const [, , text] = sendMail.mock.calls[0]; expect(text).toContain('token=a%2Bb%2Fc%3Dd'); }); it('sends both a text and an html part', async () => { await sendInvitationMail('a@nachklang.art', 'Anna', 'tok', new Date()); const [, , text, options] = sendMail.mock.calls[0]; expect(text.length).toBeGreaterThan(0); expect(options.html).toContain(' { await sendInvitationMail('a@nachklang.art', '', 'tok', new Date()); const [, , , options] = sendMail.mock.calls[0]; expect(options.html).not.toContain('