import { expect, test } from "bun:test"; import { createRequire } from "node:module"; import type { BlockDocument } from "@wrnexus/blocks"; import { renderEmail, importMjml } from "../src/index.ts"; const compile = createRequire(import.meta.url)("mjml"); test("MJML preserves document metadata and global typography in compiled HTML", async () => { const document: BlockDocument = { schemaVersion: 1, kind: "email", meta: { subject: 'Brand & "News" ', preheader: 'Preview & useful', lang: "en" }, theme: { tokens: {} }, root: { id: "root", type: "layout.email-document", version: 1, props: { width: "600", fontFamily: "Georgia, serif", textColor: "#123456" }, styles: {}, slots: { content: [{ id: "text", type: "content.text", version: 1, props: { text: "Brand text" }, styles: {}, slots: {} }, { id: "button", type: "content.button", version: 1, props: { label: "Brand action", href: "https://example.com" }, styles: {}, slots: {} }], } }, }; const before = structuredClone(document); const result = await renderEmail(document, { mjml: true }); expect(result.ok).toBe(true); if (!result.ok) return; const source = result.value.exports!.mjml!; expect(source).toContain('Brand & "News" <today>'); expect(source).toContain('Preview <safe> & useful'); expect(source).toContain(''); const compiled = await compile(source, { validationLevel: "strict", minify: false }); expect(compiled.errors).toEqual([]); expect(compiled.html).toContain("font-family:Georgia, serif"); expect(compiled.html).toContain("color:#123456"); expect(compiled.html).toContain("Preview <safe> & useful"); expect(compiled.html).not.toContain(""); expect(document).toEqual(before); let id = 0; const imported = importMjml(source, { id: () => `import-${++id}` }); expect(imported.ok).toBe(true); if (imported.ok) { expect(imported.value.meta.subject).toBe(document.meta.subject); expect(imported.value.meta.preheader).toBe(document.meta.preheader); expect(imported.value.root.props.fontFamily).toBe("Georgia, serif"); expect(imported.value.root.props.textColor).toBe("#123456"); const rerendered = await renderEmail(imported.value, { mjml: true }); expect(rerendered.ok).toBe(true); } }); test("MJML header import rejects unsupported globals and unsafe typography", () => { for (const header of [ '', '', '', '.test{color:red}', '', ]) { let id = 0; expect(importMjml(`${header}Text`, { id: () => `n${++id}` }).ok).toBe(false); } });