import { describe, expect, test } from "bun:test"; import { jsPDF } from "jspdf"; import { buildPlanModel, pdfSafe, renderPlanPdf } from "./exportPlan"; import { RECIPES } from "./recipes"; const breakfast = RECIPES.find((r) => r.kind === "breakfast")!; const dinner = RECIPES.find((r) => r.kind === "main")!; const state = { daysCount: 2, mealsPerDay: 3, householdSize: 4, // Monday breakfast + dinner, Tuesday dinner; "6-3" is outside daysCount and must not export. slots: { "0-1": breakfast.id, "0-3": dinner.id, "1-3": dinner.id, "6-3": dinner.id }, }; describe("plan export", () => { const model = buildPlanModel(state); test("organizes meals under each planned day, in meal order", () => { expect(model.days.map((d) => d.name)).toEqual(["Monday", "Tuesday"]); const [monday, tuesday] = model.days; expect(monday.meals.map((m) => ("empty" in m ? `${m.label}: -` : `${m.label}: ${m.title}`))).toEqual([ `Breakfast: ${breakfast.title}`, "Lunch: -", `Dinner: ${dinner.title}`, ]); expect(tuesday.meals.filter((m) => !("empty" in m))).toHaveLength(1); }); test("each meal carries its full recipe, scaled to the household", () => { const meal = model.days[0].meals[0]; if ("empty" in meal) throw new Error("expected a planned meal"); expect(meal.steps).toEqual(breakfast.steps); expect(meal.ingredients).toHaveLength(breakfast.ingredients.length); expect(meal.meta).toContain("serves 4"); }); test("text is made printable in the base PDF font", () => { expect(pdfSafe("1⅓ cup flour")).toBe("1 1/3 cup flour"); expect(pdfSafe("⅛ tsp salt")).toBe("1/8 tsp salt"); expect(pdfSafe("½ cup · 350°F — Rakı")).toBe("½ cup · 350°F — Raki"); }); test("renders a real multi-page PDF (one day per page)", () => { const bytes = new Uint8Array(renderPlanPdf(model, jsPDF).output("arraybuffer")); expect(new TextDecoder().decode(bytes.slice(0, 5))).toBe("%PDF-"); expect(renderPlanPdf(model, jsPDF).getNumberOfPages()).toBeGreaterThanOrEqual(2); }); });