diff --git a/web/lib/email/templates/base.tsx b/web/lib/email/templates/base.tsx index ebf66e2c..dd3c2e72 100644 --- a/web/lib/email/templates/base.tsx +++ b/web/lib/email/templates/base.tsx @@ -24,7 +24,7 @@ export function BaseEmail({ preview, children, baseUrl }: BaseEmailProps) { {preview} - +
Techulus Cloud
@@ -47,7 +47,9 @@ const container = { margin: "0 auto", padding: "12px 0 32px", marginBottom: "64px", + width: "100%", maxWidth: "600px", + tableLayout: "fixed" as const, }; const header = { @@ -56,6 +58,9 @@ const header = { const content = { padding: "16px 24px", + overflowWrap: "anywhere" as const, + wordBreak: "break-word" as const, + wordWrap: "break-word" as const, }; const footer = { diff --git a/web/tests/email-templates.test.tsx b/web/tests/email-templates.test.tsx new file mode 100644 index 00000000..993e30d5 --- /dev/null +++ b/web/tests/email-templates.test.tsx @@ -0,0 +1,38 @@ +import { render } from "@react-email/render"; +import { describe, expect, it } from "vitest"; +import { Alert } from "@/lib/email/templates/alert"; +import { MemberInvitation } from "@/lib/email/templates/member-invitation"; + +const longContent = "x".repeat(2_000); + +const templates = { + alert: Alert({ + bannerText: "BUILD FAILED", + heading: "Build Failure Alert", + description: "The build failed.", + details: [{ label: "Error", value: longContent }], + }), + invitation: MemberInvitation({ + inviterName: longContent, + role: "member", + inviteUrl: `https://cloud.example.com/invite/${longContent}`, + }), +}; + +describe("email templates", () => { + it.each(Object.entries(templates))( + "constrains and wraps long %s content", + async (_, template) => { + const html = await render(template); + + expect(html).toContain(longContent); + expect(html).toContain('width="600"'); + expect(html).toContain("width:100%"); + expect(html).toContain("max-width:600px"); + expect(html).toContain("table-layout:fixed"); + expect(html).toContain("overflow-wrap:anywhere"); + expect(html).toContain("word-break:break-word"); + expect(html).toContain("word-wrap:break-word"); + }, + ); +});