import { describe, expect, test } from "bun:test"; import type { MealPlanState } from "@/app/types"; import { activeRecipeIds, mealKindFor, mealLabel, visibleMeals } from "./plan"; import { DEFAULT_STATE } from "./sanitize"; import { RECIPES } from "./recipes"; import { planReducer } from "./usePlanState"; // --------------------------------------------------------------------------- // Meal slots. Regression tests for the "change meals per day and your // breakfast turns into lunch" bug. Meal numbers are fixed: // 1 = Breakfast, 2 = Lunch, 3 = Dinner // and "meals per day" only decides which ones you can see. // --------------------------------------------------------------------------- // Any real recipes will do; names are just for readability. const PANCAKES = RECIPES.find((r) => r.kind === "breakfast")!.id; const [SANDWICH, STEW] = RECIPES.filter((r) => r.kind === "main").map((r) => r.id); /** Monday with all three meals planned. */ const fullMonday: MealPlanState = { ...DEFAULT_STATE, daysCount: 1, mealsPerDay: 3, slots: { "0-1": PANCAKES, "0-2": SANDWICH, "0-3": STEW }, }; /** What the grid shows, as "Label: recipe". */ function visibleGrid(state: MealPlanState): string[] { return visibleMeals(state.mealsPerDay).map((meal) => `${mealLabel(meal)}: ${state.slots[`0-${meal}`] ?? "—"}`); } describe("visible meals", () => { test("fewer meals hides from the front of the day", () => { expect(visibleMeals(3).map(mealLabel)).toEqual(["Breakfast", "Lunch", "Dinner"]); expect(visibleMeals(2).map(mealLabel)).toEqual(["Lunch", "Dinner"]); expect(visibleMeals(1).map(mealLabel)).toEqual(["Dinner"]); }); test("only meal 1 is breakfast", () => { expect([1, 2, 3].map(mealKindFor)).toEqual(["breakfast", "main", "main"]); }); }); describe("changing meals per day", () => { test("3 → 2 keeps lunch as lunch and dinner as dinner", () => { const state = planReducer(fullMonday, { type: "setMealsPerDay", value: 2 }); expect(visibleGrid(state)).toEqual([`Lunch: ${SANDWICH}`, `Dinner: ${STEW}`]); }); test("3 → 1 → 3 brings breakfast and lunch back (nothing deleted)", () => { const down = planReducer(fullMonday, { type: "setMealsPerDay", value: 1 }); expect(visibleGrid(down)).toEqual([`Dinner: ${STEW}`]); const backUp = planReducer(down, { type: "setMealsPerDay", value: 3 }); expect(visibleGrid(backUp)).toEqual([`Breakfast: ${PANCAKES}`, `Lunch: ${SANDWICH}`, `Dinner: ${STEW}`]); }); test("hidden meals don't count toward the cart", () => { expect(activeRecipeIds({ ...fullMonday, mealsPerDay: 1 })).toEqual([STEW]); expect(activeRecipeIds({ ...fullMonday, mealsPerDay: 2 })).toEqual([SANDWICH, STEW]); }); }); describe("Clear", () => { test("empties the visible grid but keeps hidden meals", () => { const lunchAndDinner = { ...fullMonday, mealsPerDay: 2 }; const cleared = planReducer(lunchAndDinner, { type: "clearSlots" }); expect(visibleGrid(cleared)).toEqual(["Lunch: —", "Dinner: —"]); expect(cleared.slots).toEqual({ "0-1": PANCAKES }); // breakfast was hidden, so untouched }); });