fix(email-renderer): preserve marketing images across output formats
This commit is contained in:
1 parent
371c23db46
commit
baee958c68
4 files changed
+144
-11
No files matched your search
@@ -0,0 +1,114 @@
|
||||
import { expect, test } from "bun:test";
|
||||
import type { BlockDocument } from "@wrnexus/blocks";
|
||||
import { renderEmail, validateMjml } from "../src/index.ts";
|
||||
|
||||
function document(type: string, props: Record<string, string>): BlockDocument {
|
||||
return {
|
||||
schemaVersion: 1,
|
||||
kind: "email",
|
||||
meta: { subject: "Store update", lang: "en" },
|
||||
theme: { tokens: {} },
|
||||
root: {
|
||||
id: "root",
|
||||
type: "layout.email-document",
|
||||
version: 1,
|
||||
props: { width: "600" },
|
||||
styles: {},
|
||||
slots: {
|
||||
content: [
|
||||
{
|
||||
id: "section",
|
||||
type: "layout.section",
|
||||
version: 1,
|
||||
props: { background: "#ffffff", padding: "24px" },
|
||||
styles: {},
|
||||
slots: { content: [{ id: "item", type, version: 1, props, styles: {}, slots: {} }] },
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
test("product and RSS images survive HTML, AMP and strict MJML exports", async () => {
|
||||
for (const type of ["commerce.product", "content.feed-item"]) {
|
||||
const props: Record<string, string> =
|
||||
type === "commerce.product"
|
||||
? {
|
||||
title: "Tea & coffee",
|
||||
image: "https://example.com/product.png",
|
||||
href: "https://example.com/product",
|
||||
price: "$12.00",
|
||||
buttonLabel: "Shop now",
|
||||
width: "320",
|
||||
height: "180",
|
||||
}
|
||||
: {
|
||||
title: "Tea & coffee",
|
||||
image: "https://example.com/article.png",
|
||||
href: "https://example.com/article",
|
||||
summary: "Latest news",
|
||||
width: "320",
|
||||
height: "180",
|
||||
};
|
||||
const result = await renderEmail(document(type, props), { amp: true, mjml: true });
|
||||
expect(result.ok).toBe(true);
|
||||
if (!result.ok) continue;
|
||||
for (const output of [
|
||||
result.value.parts.html.content,
|
||||
result.value.parts.amp?.content,
|
||||
result.value.exports?.mjml,
|
||||
]) {
|
||||
expect(output).toContain(props.image);
|
||||
expect(output).toContain(props.href);
|
||||
expect(output).toContain("Tea & coffee");
|
||||
if (type === "commerce.product") expect(output).toContain("$12.00");
|
||||
}
|
||||
expect(result.value.parts.amp?.validation.valid).toBe(true);
|
||||
expect(result.value.parts.amp?.content).toContain(
|
||||
'width="320" height="180" layout="responsive"',
|
||||
);
|
||||
expect(result.value.parts.amp?.content).toContain(".marketing-image img{object-fit:contain}");
|
||||
expect(await validateMjml(result.value.exports!.mjml!)).toEqual([]);
|
||||
}
|
||||
});
|
||||
|
||||
test("image-free RSS and older product documents remain renderable", async () => {
|
||||
const rss = await renderEmail(
|
||||
document("content.feed-item", {
|
||||
title: "News",
|
||||
summary: "Update",
|
||||
href: "https://example.com",
|
||||
image: "",
|
||||
}),
|
||||
{ amp: true, mjml: true },
|
||||
);
|
||||
expect(rss.ok).toBe(true);
|
||||
if (rss.ok) expect(rss.value.parts.amp?.content).not.toContain("<amp-img");
|
||||
const product = await renderEmail(
|
||||
document("commerce.product", {
|
||||
title: "Product",
|
||||
price: "12",
|
||||
image: "https://example.com/p.png",
|
||||
href: "https://example.com",
|
||||
}),
|
||||
{ amp: true },
|
||||
);
|
||||
expect(product.ok).toBe(true);
|
||||
if (product.ok) expect(product.value.parts.amp?.content).toContain('width="600" height="400"');
|
||||
});
|
||||
|
||||
test("marketing image dimensions reject invalid or injected values", async () => {
|
||||
for (const width of ["0", "4001", "100%", '600" onerror="alert(1)']) {
|
||||
const result = await renderEmail(
|
||||
document("commerce.product", {
|
||||
title: "Product",
|
||||
price: "12",
|
||||
image: "https://example.com/p.png",
|
||||
href: "https://example.com",
|
||||
width,
|
||||
}),
|
||||
);
|
||||
expect(result.ok).toBe(false);
|
||||
}
|
||||
});
|
||||
Reference in new issue
Block a user