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", linkColor: "#a12345", }, 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"); expect(imported.value.root.props.linkColor).toBe("#a12345"); 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); } });