All five resend.js send wrappers (registration, cancellation, waitlist, series pass, welcome) dispatched live in dev. Add a skipEmailInDev guard mirroring the gate in pre-registrants/invite.post.js so dev runs and e2e don't fire real Resend sends. Also add the monthly-onboarding Slack-timing line to the welcome email. Unit-tested.
85 lines
2.6 KiB
JavaScript
85 lines
2.6 KiB
JavaScript
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
|
|
|
import {
|
|
sendEventRegistrationEmail,
|
|
sendEventCancellationEmail,
|
|
sendWaitlistNotificationEmail,
|
|
sendSeriesPassConfirmation,
|
|
sendWelcomeEmail,
|
|
} from '../../../server/utils/resend.js'
|
|
|
|
// Hoisted spy so the resend mock and the assertions share one reference.
|
|
const { sendSpy } = vi.hoisted(() => ({ sendSpy: vi.fn() }))
|
|
|
|
vi.mock('resend', () => ({
|
|
Resend: class {
|
|
constructor() {
|
|
this.emails = { send: sendSpy }
|
|
}
|
|
},
|
|
}))
|
|
|
|
const eventData = {
|
|
title: 'Co-op Basics',
|
|
startDate: '2026-06-01T17:00:00.000Z',
|
|
endDate: '2026-06-01T18:00:00.000Z',
|
|
location: 'Online',
|
|
slug: 'co-op-basics',
|
|
}
|
|
|
|
const registration = { email: 'reg@example.com', name: 'Reg', ticketType: 'member', amountPaid: 0 }
|
|
|
|
const seriesPassOptions = {
|
|
to: 'pass@example.com',
|
|
name: 'Pass Holder',
|
|
series: { title: 'Workshop Series' },
|
|
ticket: { type: 'member', price: 0, currency: 'CAD', isFree: true },
|
|
events: [eventData],
|
|
paymentId: null,
|
|
}
|
|
|
|
const member = { email: 'welcome@example.com', name: 'New Member', circle: 'Community' }
|
|
|
|
describe('resend email wrappers — ALLOW_DEV_TEST_ENDPOINTS gate', () => {
|
|
beforeEach(() => {
|
|
sendSpy.mockReset()
|
|
sendSpy.mockResolvedValue({ data: { id: 'email_1' }, error: null })
|
|
})
|
|
afterEach(() => {
|
|
delete process.env.ALLOW_DEV_TEST_ENDPOINTS
|
|
})
|
|
|
|
describe('when ALLOW_DEV_TEST_ENDPOINTS=true', () => {
|
|
beforeEach(() => {
|
|
process.env.ALLOW_DEV_TEST_ENDPOINTS = 'true'
|
|
})
|
|
|
|
const cases = [
|
|
['registration', () => sendEventRegistrationEmail(registration, eventData)],
|
|
['cancellation', () => sendEventCancellationEmail(registration, eventData)],
|
|
['waitlist', () => sendWaitlistNotificationEmail(registration, eventData)],
|
|
['series pass', () => sendSeriesPassConfirmation(seriesPassOptions)],
|
|
['welcome', () => sendWelcomeEmail(member)],
|
|
]
|
|
|
|
it.each(cases)('skips the live send for %s', async (_label, call) => {
|
|
const result = await call()
|
|
expect(result).toEqual({ success: true, skipped: true })
|
|
expect(sendSpy).not.toHaveBeenCalled()
|
|
})
|
|
})
|
|
|
|
describe('when the gate is off', () => {
|
|
it('dispatches a live send and returns success', async () => {
|
|
const result = await sendWelcomeEmail(member)
|
|
expect(sendSpy).toHaveBeenCalledTimes(1)
|
|
expect(result).toEqual({ success: true, data: { id: 'email_1' } })
|
|
})
|
|
|
|
it('includes the monthly-onboarding Slack-timing line in the welcome email', async () => {
|
|
await sendWelcomeEmail(member)
|
|
const sent = sendSpy.mock.calls[0][0]
|
|
expect(sent.text).toContain('monthly onboarding waves')
|
|
})
|
|
})
|
|
})
|