diff --git a/bun.lock b/bun.lock index f99312f88..62a8a0d77 100644 --- a/bun.lock +++ b/bun.lock @@ -534,6 +534,7 @@ "react-dom": "^19.1.0", "tsup": "^8.5.0", "typescript": "^5.8.3", + "vitest": "^3.2.4", }, "peerDependencies": { "react": "^19.1.1", diff --git a/packages/email/emails/all-policy-notification.tsx b/packages/email/emails/all-policy-notification.tsx index d794bc901..cc2852ddf 100644 --- a/packages/email/emails/all-policy-notification.tsx +++ b/packages/email/emails/all-policy-notification.tsx @@ -34,7 +34,8 @@ export const AllPolicyNotificationEmail = ({ return ( -{subjectText} + + {subjectText} -You've been invited to the Comp AI Portal + + You've been invited to the Comp AI Portal { return ( -You've been invited to join Comp AI + + You've been invited to join Comp AI { return ( -Login Link for Comp AI + + Login Link for Comp AI { return ( -Get started with Comp AI + + Get started with Comp AI { return ( -One-Time Password for Comp AI + + One-Time Password for Comp AI -{subjectText} + + {subjectText} return ( -Comp AI - Task Reminder + + Comp AI - Task Reminder - + + Task "{taskName}" {statusLabel} - {organizationName} diff --git a/packages/email/emails/reminders/weekly-task-digest.tsx b/packages/email/emails/reminders/weekly-task-digest.tsx index 7f1f18f94..fd06f0246 100644 --- a/packages/email/emails/reminders/weekly-task-digest.tsx +++ b/packages/email/emails/reminders/weekly-task-digest.tsx @@ -45,7 +45,8 @@ export const WeeklyTaskDigestEmail = ({ return ( -{taskCountMessage} + + {taskCountMessage} from every template, which broke +// @react-email/tailwind's media-query injection (md:* classes) and caused +// every email to render to an empty Suspense fallback in production. +// These tests fail if any template renders to that fallback or otherwise +// produces broken output, so the same mistake can't ship again. + +const SUSPENSE_ERROR_MARKER = ''; + +const cases = [ + { + name: 'weekly-task-digest', + el: ( + + ), + }, + { + name: 'task-reminder', + el: ( + + ), + }, + { + name: 'task-status-notification', + el: ( + + ), + }, + { + name: 'invite-portal', + el: ( + + ), + }, + { + name: 'invite', + el: ( + + ), + }, + { name: 'welcome', el: }, + { + name: 'policy-notification', + el: ( + + ), + }, + { + name: 'magic-link', + el: ( + + ), + }, + { + name: 'all-policy-notification', + el: ( + + ), + }, + { name: 'otp', el: }, + { + name: 'training-completed', + el: ( + + ), + }, + { + name: 'unassigned-items-notification', + el: ( + + ), + }, +]; + +describe('email templates render to non-empty HTML', () => { + for (const { name, el } of cases) { + it(name, async () => { + const html = await render(el); + expect(html).not.toContain(SUSPENSE_ERROR_MARKER); + expect(html).toContain(' -Congratulations! You've completed your Security Awareness Training + + Congratulations! You've completed your Security Awareness Training -Member removed - items require reassignment + + Member removed - items require reassignment