- Export `renderNotificationEmail` from email.ts (pure template resolver, no send) - Refactor `sendStyledNotificationEmail` to delegate to `renderNotificationEmail` - Hoist sampleData to module-level `NOTIFICATION_SAMPLE_DATA` in notification router - Add 8 logistics sample entries (FINALIST_*/TRAVEL_CONFIRMED/VISA_STATUS_UPDATE) - Add `notification.previewEmailTemplate` adminProcedure query (returns subject/html/hasStyledTemplate) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
63 lines
2.2 KiB
TypeScript
63 lines
2.2 KiB
TypeScript
/**
|
|
* Task 1: renderNotificationEmail + previewEmailTemplate
|
|
*
|
|
* Tests that:
|
|
* 1. previewEmailTemplate returns rendered HTML and a non-empty subject for a
|
|
* type that has a styled template (VISA_STATUS_UPDATE).
|
|
* 2. previewEmailTemplate returns non-empty HTML for a fallback type
|
|
* (FINALIST_EXPIRED — no registered template, uses generic fallback).
|
|
*/
|
|
import { afterAll, describe, expect, it } from 'vitest'
|
|
import { createCaller, prisma } from '../setup'
|
|
import { createTestUser, cleanupTestData, uid } from '../helpers'
|
|
import { notificationRouter } from '../../src/server/routers/notification'
|
|
|
|
describe('notification.previewEmailTemplate', () => {
|
|
let adminId: string
|
|
let adminEmail: string
|
|
|
|
afterAll(async () => {
|
|
if (adminId) {
|
|
await prisma.user.deleteMany({ where: { id: adminId } })
|
|
}
|
|
})
|
|
|
|
async function getAdminCaller() {
|
|
if (!adminId) {
|
|
const admin = await createTestUser('SUPER_ADMIN', {
|
|
name: 'Preview Admin',
|
|
email: `preview-admin-${uid()}@test.local`,
|
|
})
|
|
adminId = admin.id
|
|
adminEmail = admin.email
|
|
}
|
|
return createCaller(notificationRouter, {
|
|
id: adminId,
|
|
email: adminEmail,
|
|
name: 'Preview Admin',
|
|
role: 'SUPER_ADMIN',
|
|
})
|
|
}
|
|
|
|
it('returns HTML containing a visa-related string and a non-empty subject for VISA_STATUS_UPDATE', async () => {
|
|
const caller = await getAdminCaller()
|
|
const result = await caller.previewEmailTemplate({ notificationType: 'VISA_STATUS_UPDATE' })
|
|
|
|
expect(result.subject).toBeTruthy()
|
|
expect(result.html).toBeTruthy()
|
|
// The visa template includes 'visa' or 'Grand' in its content
|
|
const lower = result.html.toLowerCase()
|
|
expect(lower.includes('visa') || lower.includes('grand')).toBe(true)
|
|
expect(result.hasStyledTemplate).toBe(true)
|
|
})
|
|
|
|
it('returns non-empty HTML for FINALIST_EXPIRED (fallback — no styled template)', async () => {
|
|
const caller = await getAdminCaller()
|
|
const result = await caller.previewEmailTemplate({ notificationType: 'FINALIST_EXPIRED' })
|
|
|
|
expect(result.html).toBeTruthy()
|
|
expect(result.subject).toBeTruthy()
|
|
expect(result.hasStyledTemplate).toBe(false)
|
|
})
|
|
})
|