/** * 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) }) })