import { describe, expect, it } from "vitest"; import { defaultBrandTokens } from "@toolctrl/brand"; import EmailTemplates from "./EmailTemplates"; import type { AppConfiguration } from "~/utils/db/appConfiguration.db.server"; const appConfiguration = { app: { name: "Acme Portal" }, email: { fromName: "Acme Support", supportEmail: "help@acme.test" }, branding: { logo: "https://cdn.acme.test/logo.png", favicon: "https://cdn.acme.test/favicon.ico" }, } as AppConfiguration; const actionUrl = "https://app.acme.test/action"; describe("EmailTemplates", () => { it("keeps the exported template registry stable", () => { expect(EmailTemplates.allTemplates.map((template) => template.name)).toEqual([ "welcome", "password-reset", "user-invitation", "email-verification", "account-setup", ]); }); it("renders welcome emails through the React-Email pipeline", () => { const rendered = EmailTemplates.WELCOME_EMAIL.parse({ appConfiguration, data: { name: "Ada", action_url: actionUrl }, }); expect(rendered.subject).toBe("Welcome to Acme Portal, Ada!"); expect(rendered.body).toContain(actionUrl); expect(rendered.body).toContain("Acme Portal"); expect(rendered.body.startsWith("")).toBe(true); expect(rendered.data).toEqual({ name: "Ada", action_url: actionUrl }); }); it("renders password reset emails with brand-aware subject", () => { const rendered = EmailTemplates.PASSWORD_RESET_EMAIL.parse({ appConfiguration, data: { name: "Ada", action_url: actionUrl }, }); expect(rendered.subject).toBe("Reset your Acme Portal password"); expect(rendered.body).toContain(actionUrl); expect(rendered.body).toContain("Acme Portal"); }); it("renders user invitation emails with sender and organization data", () => { const rendered = EmailTemplates.USER_INVITATION_EMAIL.parse({ appConfiguration, data: { name: "Ada", invite_sender_name: "Grace", invite_sender_organization: "Example Org", action_url: actionUrl, }, }); expect(rendered.subject).toBe("Grace invited you to Example Org on Acme Portal"); expect(rendered.body).toContain("Grace"); expect(rendered.body).toContain("Example Org"); expect(rendered.body).toContain(actionUrl); }); it("renders email verification emails via the magic-link template", () => { const rendered = EmailTemplates.VERIFICATION_EMAIL.parse({ appConfiguration, data: { name: "Ada", action_url: actionUrl }, }); expect(rendered.subject).toBe("Verify your Acme Portal email address"); expect(rendered.body).toContain(actionUrl); expect(rendered.body).toMatch(/expires? in 30 minutes/i); }); it("renders account setup emails via the welcome template with plan-aware copy", () => { const rendered = EmailTemplates.ACCOUNT_SETUP_EMAIL.parse({ appConfiguration, data: { email: "ada@example.com", plan: "Pro", action_url: actionUrl }, }); expect(rendered.subject).toBe("Finish setting up your Acme Portal account"); expect(rendered.body).toContain("Pro plan"); expect(rendered.body).toContain("ada@example.com"); expect(rendered.body).toContain(actionUrl); }); it("falls back to default brand tokens when app configuration omits brand values", () => { const rendered = EmailTemplates.WELCOME_EMAIL.parse({ appConfiguration: {} as AppConfiguration, data: { action_url: actionUrl }, }); expect(rendered.subject).toBe(`Welcome to ${defaultBrandTokens.productName}!`); expect(rendered.body).toContain(defaultBrandTokens.productName); }); it("uses the optional translator for subject and body chrome", () => { const baseline = EmailTemplates.WELCOME_EMAIL.parse({ appConfiguration, data: { name: "Ada", action_url: actionUrl }, }); const withTranslator = EmailTemplates.WELCOME_EMAIL.parse({ appConfiguration, data: { name: "Ada", action_url: actionUrl }, t: (key, vars) => { const values: Record = { "welcome.subject_named": `Willkommen bei ${vars?.productName}, ${vars?.name}!`, "welcome.eyebrow": "Willkommen", "welcome.title_named": `Hallo ${vars?.name}!`, "welcome.intro": `Danke fuer ${vars?.productName}.`, "welcome.actionLabel": "Einloggen", "common.signoff.thanks": "Danke,", }; return values[key] ?? key; }, locale: "de", }); expect(withTranslator.subject).toBe("Willkommen bei Acme Portal, Ada!"); expect(withTranslator.body).toContain("Hallo Ada!"); expect(withTranslator.body).toContain("Einloggen"); expect(withTranslator.body).toContain("Danke,"); expect(withTranslator.body).not.toEqual(baseline.body); }); it("localizes registry descriptions when a mail translator is available", () => { const t = (key: string) => (key === "registry.welcomeDescription" ? "Lokalisierte Willkommensbeschreibung" : key); expect(EmailTemplates.WELCOME_EMAIL.describe(t)).toBe("Lokalisierte Willkommensbeschreibung"); expect(EmailTemplates.WELCOME_EMAIL.description).toBe("Welcome email with login link"); }); });