import { expect, test } from "bun:test"; import { importMjml, renderEmail } from "../src/index.ts"; const parse = (columns: string) => { let id = 0; return importMjml(`${columns}`, { subject: "Imported", id: () => `n${++id}`, }); }; test("imported columns form one native row with preserved order and exact width totals", async () => { for (const widths of [ ["", ""], ["33%", ""], ["", "", ""], ["25%", "75%"], ]) { const result = parse( widths .map( (width, index) => `Column ${index}`, ) .join(""), ); expect(result.ok).toBe(true); if (!result.ok) continue; const row = result.value.root.slots.content[0]!.slots.content[0]!; expect(row.type).toBe("layout.columns"); expect(row.slots.columns.map((column) => column.slots.content[0]!.props.text)).toEqual( widths.map((_, index) => `Column ${index}`), ); expect( row.slots.columns.reduce( (sum, column) => sum + Number.parseFloat(String(column.props.width)), 0, ), ).toBeCloseTo(100, 8); const rendered = await renderEmail(result.value, { mjml: true }); expect(rendered.ok).toBe(true); if (rendered.ok) expect(rendered.value.exports?.mjml).toContain(" { for (const input of [ 'Bad', '', '', '', Array(5).fill("X").join(""), ]) expect(parse(input).ok).toBe(false); }); test("import enforces depth limits and rejects repeated instance IDs", () => { const nested = "" + "".repeat(100) + "X" + "".repeat(100) + ""; expect(importMjml(nested, { subject: "Depth", id: () => "id" }).ok).toBe(false); expect( importMjml( "X", { subject: "IDs", id: () => "same" }, ).ok, ).toBe(false); });