Initial Commit
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
import { describe, expect, it } from "@suaveplan/testing/runner";
|
||||
import { findEvery, findFirst, textOf } from "../../../tests/setup/html.js";
|
||||
import { renderToHtml } from "../../renderer/renderer.js";
|
||||
import { renderVNode } from "../../vnode/vnode.js";
|
||||
import { InvoiceEmail, invoiceTemplate } from "./invoice.js";
|
||||
|
||||
const baseProps = {
|
||||
recipientName: "Jane",
|
||||
invoiceNumber: "INV-001",
|
||||
invoiceDate: "2026-01-01",
|
||||
items: [
|
||||
{ description: "Widget", quantity: 2, unitPrice: 10, total: 20 },
|
||||
{ description: "Gizmo", quantity: 1, unitPrice: 15.5, total: 15.5 },
|
||||
],
|
||||
subtotal: 35.5,
|
||||
total: 35.5,
|
||||
};
|
||||
|
||||
describe("invoiceTemplate", () => {
|
||||
it("renders line-item rows", { timeout: 5000 }, () => {
|
||||
const { html } = renderToHtml(invoiceTemplate, baseProps);
|
||||
const widget = findFirst(
|
||||
html,
|
||||
(el) => el.name === "td" && textOf(el).includes("Widget")
|
||||
);
|
||||
expect(widget).not.toBeNull();
|
||||
const gizmo = findFirst(
|
||||
html,
|
||||
(el) => el.name === "td" && textOf(el).includes("Gizmo")
|
||||
);
|
||||
expect(gizmo).not.toBeNull();
|
||||
});
|
||||
|
||||
it("renders the invoice number in the subject and heading", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const { html, subject } = renderToHtml(invoiceTemplate, baseProps);
|
||||
expect(subject).toBe("Invoice #INV-001");
|
||||
expect(html).toContain("Invoice #INV-001");
|
||||
});
|
||||
|
||||
it("formats currency to two decimal places", { timeout: 5000 }, () => {
|
||||
const html = renderVNode(InvoiceEmail(baseProps));
|
||||
expect(html).toContain("$10.00");
|
||||
expect(html).toContain("$15.50");
|
||||
expect(html).toContain("$35.50");
|
||||
});
|
||||
|
||||
it("uses custom currency symbol", { timeout: 5000 }, () => {
|
||||
const html = renderVNode(
|
||||
InvoiceEmail({
|
||||
...baseProps,
|
||||
currency: "€",
|
||||
})
|
||||
);
|
||||
expect(html).toContain("€10.00");
|
||||
expect(html).not.toContain("$10.00");
|
||||
});
|
||||
|
||||
it("omits dueDate when not provided", { timeout: 5000 }, () => {
|
||||
const html = renderVNode(InvoiceEmail(baseProps));
|
||||
expect(html).toContain("Date: 2026-01-01");
|
||||
expect(html).not.toContain("Due:");
|
||||
});
|
||||
|
||||
it("renders dueDate when provided", { timeout: 5000 }, () => {
|
||||
const html = renderVNode(
|
||||
InvoiceEmail({ ...baseProps, dueDate: "2026-01-31" })
|
||||
);
|
||||
expect(html).toContain("Due: 2026-01-31");
|
||||
});
|
||||
|
||||
it("renders tax row when tax provided", { timeout: 5000 }, () => {
|
||||
const html = renderVNode(
|
||||
InvoiceEmail({ ...baseProps, tax: 3.55, total: 39.05 })
|
||||
);
|
||||
expect(html).toContain("Tax: $3.55");
|
||||
});
|
||||
|
||||
it("omits tax row when not provided", { timeout: 5000 }, () => {
|
||||
const html = renderVNode(InvoiceEmail(baseProps));
|
||||
expect(html).not.toContain("Tax:");
|
||||
});
|
||||
|
||||
it("renders payment button when paymentUrl provided", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const html = renderVNode(
|
||||
InvoiceEmail({ ...baseProps, paymentUrl: "https://x/pay" })
|
||||
);
|
||||
const a = findFirst(
|
||||
html,
|
||||
(el) => el.name === "a" && el.attribs.href === "https://x/pay"
|
||||
);
|
||||
expect(a).not.toBeNull();
|
||||
});
|
||||
|
||||
it("omits payment button when paymentUrl absent", { timeout: 5000 }, () => {
|
||||
const html = renderVNode(InvoiceEmail(baseProps));
|
||||
expect(html).not.toContain("Pay Now");
|
||||
});
|
||||
|
||||
it("uses explicit companyName", { timeout: 5000 }, () => {
|
||||
const html = renderVNode(
|
||||
InvoiceEmail({ ...baseProps, companyName: "Acme" })
|
||||
);
|
||||
expect(html).toContain("from Acme");
|
||||
});
|
||||
|
||||
it("renders the column headers", { timeout: 5000 }, () => {
|
||||
const html = renderVNode(InvoiceEmail(baseProps));
|
||||
const headers = findEvery(html, (el) => el.name === "th");
|
||||
const labels = headers.map((h) => textOf(h));
|
||||
expect(labels).toEqual(["Item", "Qty", "Price", "Total"]);
|
||||
});
|
||||
|
||||
it("renders an empty line-items section when items=[]", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const html = renderVNode(
|
||||
InvoiceEmail({ ...baseProps, items: [], subtotal: 0, total: 0 })
|
||||
);
|
||||
const tbody = findFirst(html, (el) => el.name === "tbody");
|
||||
expect(tbody).not.toBeNull();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user