70 lines
3.5 KiB
TypeScript
70 lines
3.5 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import { createEvent } from './setup'
|
|
|
|
vi.mock('nodemailer', () => ({
|
|
default: { createTransport: vi.fn(() => ({ sendMail: vi.fn().mockResolvedValue({ messageId: 'real' }) })) }
|
|
}))
|
|
vi.mock('../server/utils/auth.js', () => ({
|
|
readUsers: vi.fn().mockResolvedValue([]),
|
|
getTokenFromEvent: vi.fn(),
|
|
getUserFromToken: vi.fn()
|
|
}))
|
|
|
|
import nodemailer from 'nodemailer'
|
|
import * as auth from '../server/utils/auth.js'
|
|
import { createMailTransport } from '../server/utils/mail-transport.js'
|
|
import { sendMembershipEmail, sendRegistrationNotification } from '../server/utils/email-service.js'
|
|
|
|
describe('Mail delivery gate', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
vi.stubEnv('MAIL_DELIVERY_DISABLED', '')
|
|
vi.stubEnv('PLAYSTORE_REVIEW_EMAIL', '')
|
|
auth.readUsers.mockResolvedValue([])
|
|
auth.getTokenFromEvent.mockReturnValue(undefined)
|
|
})
|
|
afterEach(() => vi.unstubAllEnvs())
|
|
|
|
it('does not create an SMTP transport when all delivery is disabled', async () => {
|
|
vi.stubEnv('MAIL_DELIVERY_DISABLED', 'TRUE')
|
|
expect(await createMailTransport(createEvent(), {}).sendMail({ to: 'board@example.com' }))
|
|
.toMatchObject({ suppressed: true, accepted: [] })
|
|
expect(nodemailer.createTransport).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('suppresses board mail for an authenticated review user with another form address', async () => {
|
|
auth.getTokenFromEvent.mockReturnValue('verified-by-auth')
|
|
auth.getUserFromToken.mockResolvedValue({ accountType: 'playstore_review' })
|
|
await createMailTransport(createEvent(), {}).sendMail({ to: 'board@example.com', replyTo: 'other@example.com' })
|
|
expect(auth.getUserFromToken).toHaveBeenCalledWith('verified-by-auth')
|
|
expect(nodemailer.createTransport).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('suppresses signed-out contact mail using the configured review reply address', async () => {
|
|
vi.stubEnv('PLAYSTORE_REVIEW_EMAIL', 'review@example.com')
|
|
await createMailTransport(undefined, {}).sendMail({ to: 'board@example.com', replyTo: 'Review <REVIEW@example.com>' })
|
|
expect(nodemailer.createTransport).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('checks stored review accounts in cc and bcc as well', async () => {
|
|
auth.readUsers.mockResolvedValue([{ email: 'review@example.com', accountType: 'playstore_review' }])
|
|
await createMailTransport(undefined, {}).sendMail({ to: 'member@example.com', bcc: [{ address: 'review@example.com' }] })
|
|
expect(nodemailer.createTransport).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('suppresses membership and registration notifications before SMTP/config loading', async () => {
|
|
vi.stubEnv('PLAYSTORE_REVIEW_EMAIL', 'review@example.com')
|
|
expect(await sendMembershipEmail({ email: 'review@example.com' }, '/unused.pdf')).toMatchObject({ success: true, suppressed: true })
|
|
expect(await sendRegistrationNotification({ email: 'review@example.com' })).toMatchObject({ success: true, suppressed: true })
|
|
expect(nodemailer.createTransport).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('delivers ordinary member mail and does not trust a client demo flag', async () => {
|
|
const event = createEvent({ body: { demo: true, accountType: 'playstore_review' } })
|
|
const mail = { to: 'member@example.com', text: 'Hello' }
|
|
expect(await createMailTransport(event, { host: 'smtp.example.com' }).sendMail(mail)).toEqual({ messageId: 'real' })
|
|
expect(nodemailer.createTransport).toHaveBeenCalledWith({ host: 'smtp.example.com' })
|
|
expect(nodemailer.createTransport.mock.results[0].value.sendMail).toHaveBeenCalledWith(mail)
|
|
})
|
|
})
|