from datetime import date from decimal import Decimal from uuid import UUID, uuid4 import pytest pytestmark = pytest.mark.requires_postgres def test_generate_meal_plan_against_seeded_data(): """Smoke test: with the seeded 30 recipes and a seeded grocery scrape, generate produces a MealPlan with up to 3 items. """ from datetime import datetime, timezone from app.database import SessionLocal from app.models import ( FamilyProfile, GroceryItem, Ingredient, IngredientGroceryMatch, IngredientMatchSource, MealPlan, MealPlanItem, ) from app.services.matcher import run_match_job from app.services.planner.generate import generate_meal_plan setup = SessionLocal() try: family = FamilyProfile( id=uuid4(), name="Generate Smoke Family", household_size=4, adult_count=2, child_count=2, calorie_target=500, ) setup.add(family) setup.commit() family_id = family.id # Seed at least one grocery_item per ingredient that the recipes use # so cost matching can find prices. Pick a handful to keep runtime low. for ing in setup.query(Ingredient).limit(20).all(): setup.add( GroceryItem( id=uuid4(), name=ing.name, source="lucky_california", external_id=f"ext-test-{ing.id}", current_price=Decimal("3.99"), regular_price=Decimal("4.99"), is_on_sale=True, scraped_at=datetime.now(timezone.utc), ) ) setup.commit() finally: setup.close() work = SessionLocal() try: run_match_job(work) result = generate_meal_plan(work, family_id=family_id, week_start_date=date(2026, 5, 11)) assert result.meal_plan_id is not None assert 1 <= len(result.selected) <= 3 # at least 1, at most 3 plan = work.query(MealPlan).filter(MealPlan.id == result.meal_plan_id).first() assert plan is not None items = work.query(MealPlanItem).filter(MealPlanItem.meal_plan_id == plan.id).all() assert len(items) == len(result.selected) finally: cleanup = SessionLocal() try: cleanup.query(MealPlanItem).filter( MealPlanItem.meal_plan_id.in_( [r[0] for r in cleanup.query(MealPlan.id).filter(MealPlan.family_profile_id == family_id).all()] ) ).delete(synchronize_session=False) cleanup.query(MealPlan).filter(MealPlan.family_profile_id == family_id).delete(synchronize_session=False) cleanup.query(FamilyProfile).filter(FamilyProfile.id == family_id).delete(synchronize_session=False) cleanup.query(GroceryItem).filter(GroceryItem.external_id.like("ext-test-%")).delete(synchronize_session=False) cleanup.query(IngredientGroceryMatch).filter( IngredientGroceryMatch.source == IngredientMatchSource.AUTO ).delete(synchronize_session=False) cleanup.commit() finally: cleanup.close() work.close()