import { describe, expect, test } from "bun:test"; import { renderEmail, validateAmpEmail, validateMjml, importMjml, type EmailRenderBundle, } from "../src/index.ts"; import type { BlockDocument } from "@wrnexus/blocks"; const document: BlockDocument = { schemaVersion: 1, kind: "email", meta: { subject: "Welcome", preheader: "Preview", lang: "en" }, theme: { tokens: {} }, root: { id: "root", type: "layout.email-document", version: 1, props: { width: "600", background: "#f3f4f6" }, styles: {}, slots: { content: [ { id: "section", type: "layout.section", version: 1, props: { background: "#ffffff", padding: "24px" }, styles: {}, slots: { content: [ { id: "heading", type: "content.heading", version: 1, props: { text: "Hello ", level: "1" }, styles: {}, slots: {}, }, { id: "button", type: "content.button", version: 1, props: { label: "Open", href: "https://example.com/" }, styles: {}, slots: {}, }, ], }, }, ], }, }, }; describe("email renderer", () => { test("renders deterministic HTML, text, AMP, and MJML", async () => { const first = await renderEmail(document, { amp: true, mjml: true }); const second = await renderEmail(document, { amp: true, mjml: true }); expect(first).toEqual(second); expect(first.ok).toBe(true); if (!first.ok) return; const value: EmailRenderBundle = first.value; expect(value.parts.html.content).toContain("Hello <world>"); expect(value.parts.text.content).toContain("Hello "); expect(value.parts.amp?.validation.valid).toBe(true); expect(value.exports?.mjml).toContain(""); }); test("validates AMP output", async () => { expect((await validateAmpEmail("")).valid).toBe(false); }); test("rejects unsafe MJML and imports supported content", () => { expect( importMjml("x", { id: () => crypto.randomUUID(), subject: "x", }).ok, ).toBe(false); let n = 0; const imported = importMjml( "Hello", { id: () => `n${++n}`, subject: "Imported" }, ); expect(imported.ok).toBe(true); }); test("strict MJML validation catches invalid nesting", async () => { expect( (await validateMjml("x")).length, ).toBeGreaterThan(0); }); });