mirror of
https://github.com/sstent/foodplanner.git
synced 2025-12-06 08:01:47 +00:00
275 lines
8.8 KiB
Python
275 lines
8.8 KiB
Python
import pytest
|
||
from fastapi.testclient import TestClient
|
||
from sqlalchemy import create_engine
|
||
from sqlalchemy.orm import sessionmaker
|
||
from main import app
|
||
from app.database import get_db, Base, Food, Meal, MealFood, Plan, Template, TemplateMeal
|
||
from datetime import date, timedelta
|
||
|
||
# Setup test database to match Docker environment
|
||
import os
|
||
from pathlib import Path
|
||
|
||
# Create test database directory if it doesn't exist
|
||
test_db_dir = "/app/data"
|
||
os.makedirs(test_db_dir, exist_ok=True)
|
||
|
||
# Use the same database path as Docker container
|
||
SQLALCHEMY_DATABASE_URL = "sqlite:////app/data/test_detailed.db"
|
||
print(f"Using test database at: {SQLALCHEMY_DATABASE_URL}")
|
||
|
||
test_engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False})
|
||
TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=test_engine)
|
||
|
||
@pytest.fixture(name="session")
|
||
def session_fixture():
|
||
Base.metadata.create_all(bind=test_engine)
|
||
db = TestingSessionLocal()
|
||
try:
|
||
yield db
|
||
finally:
|
||
db.close()
|
||
Base.metadata.drop_all(bind=test_engine)
|
||
|
||
@pytest.fixture(name="client")
|
||
def client_fixture(session):
|
||
def override_get_db():
|
||
yield session
|
||
app.dependency_overrides[get_db] = override_get_db
|
||
with TestClient(app) as client:
|
||
yield client
|
||
app.dependency_overrides.clear()
|
||
|
||
def test_detailed_page_no_params(client):
|
||
response = client.get("/detailed")
|
||
assert response.status_code == 200
|
||
assert "Detailed Plan for Sarah" in response.text
|
||
|
||
|
||
def test_detailed_page_default_date(client, session):
|
||
# Create mock data for today
|
||
food = Food(
|
||
name="Apple",
|
||
serving_size="100",
|
||
serving_unit="g",
|
||
calories=52,
|
||
protein=0.3,
|
||
carbs=14,
|
||
fat=0.2,
|
||
fiber=2.4, # Added fiber
|
||
sugar=10.0, # Added sugar
|
||
sodium=1.0, # Added sodium
|
||
calcium=6.0, # Added calcium
|
||
source="manual"
|
||
)
|
||
session.add(food)
|
||
session.commit()
|
||
session.refresh(food)
|
||
|
||
meal = Meal(name="Fruit Snack", meal_type="snack", meal_time="Snack")
|
||
session.add(meal)
|
||
session.commit()
|
||
session.refresh(meal)
|
||
|
||
meal_food = MealFood(meal_id=meal.id, food_id=food.id, quantity=1.0)
|
||
session.add(meal_food)
|
||
session.commit()
|
||
|
||
test_date = date.today()
|
||
plan = Plan(person="Sarah", date=test_date, meal_id=meal.id, meal_time="Snack")
|
||
session.add(plan)
|
||
session.commit()
|
||
|
||
# Test that when no plan_date is provided, today's date is used by default
|
||
response = client.get("/detailed?person=Sarah")
|
||
assert response.status_code == 200
|
||
# Check for the unescaped version or the page title
|
||
assert "Detailed Plan for" in response.text
|
||
assert test_date.strftime('%B %d, %Y') in response.text
|
||
assert "Fruit Snack" in response.text
|
||
|
||
|
||
def test_detailed_page_with_plan_date(client, session):
|
||
# Create mock data
|
||
food = Food(
|
||
name="Apple",
|
||
serving_size="100",
|
||
serving_unit="g",
|
||
calories=52,
|
||
protein=0.3,
|
||
carbs=14,
|
||
fat=0.2,
|
||
fiber=2.4,
|
||
sugar=10.0,
|
||
sodium=1.0,
|
||
calcium=6.0,
|
||
source="manual"
|
||
)
|
||
session.add(food)
|
||
session.commit()
|
||
session.refresh(food)
|
||
|
||
meal = Meal(name="Fruit Snack", meal_type="snack", meal_time="Snack")
|
||
session.add(meal)
|
||
session.commit()
|
||
session.refresh(meal)
|
||
|
||
meal_food = MealFood(meal_id=meal.id, food_id=food.id, quantity=1.0)
|
||
session.add(meal_food)
|
||
session.commit()
|
||
|
||
test_date = date.today()
|
||
plan = Plan(person="Sarah", date=test_date, meal_id=meal.id, meal_time="Snack")
|
||
session.add(plan)
|
||
session.commit()
|
||
|
||
response = client.get(f"/detailed?person=Sarah&plan_date={test_date.isoformat()}")
|
||
assert response.status_code == 200
|
||
# Check for the page content without assuming apostrophe encoding
|
||
assert "Detailed Plan for" in response.text
|
||
assert "Fruit Snack" in response.text
|
||
|
||
|
||
def test_detailed_page_with_template_id(client, session):
|
||
# Create mock data
|
||
food = Food(
|
||
name="Banana",
|
||
serving_size="100",
|
||
serving_unit="g",
|
||
calories=89,
|
||
protein=1.1,
|
||
carbs=23,
|
||
fat=0.3,
|
||
fiber=2.6,
|
||
sugar=12.0,
|
||
sodium=1.0,
|
||
calcium=5.0,
|
||
source="manual"
|
||
)
|
||
session.add(food)
|
||
session.commit()
|
||
session.refresh(food)
|
||
|
||
meal = Meal(name="Banana Smoothie", meal_type="breakfast", meal_time="Breakfast")
|
||
session.add(meal)
|
||
session.commit()
|
||
session.refresh(meal)
|
||
|
||
meal_food = MealFood(meal_id=meal.id, food_id=food.id, quantity=1.0)
|
||
session.add(meal_food)
|
||
session.commit()
|
||
|
||
template = Template(name="Morning Boost")
|
||
session.add(template)
|
||
session.commit()
|
||
session.refresh(template)
|
||
|
||
template_meal = TemplateMeal(template_id=template.id, meal_id=meal.id, meal_time="Breakfast")
|
||
session.add(template_meal)
|
||
session.commit()
|
||
|
||
response = client.get(f"/detailed?template_id={template.id}")
|
||
assert response.status_code == 200
|
||
assert "Morning Boost Template" in response.text
|
||
assert "Banana Smoothie" in response.text
|
||
|
||
def test_detailed_page_with_tracked_day_food_breakdown(client, session):
|
||
# Create mock data for a tracked day
|
||
food1 = Food(
|
||
name="Chicken Breast",
|
||
serving_size="100",
|
||
serving_unit="g",
|
||
calories=165, protein=31, carbs=0, fat=3.6,
|
||
fiber=0, sugar=0, sodium=74, calcium=11,
|
||
source="manual"
|
||
)
|
||
food2 = Food(
|
||
name="Broccoli",
|
||
serving_size="100",
|
||
serving_unit="g",
|
||
calories=55, protein=3.7, carbs=11.2, fat=0.6,
|
||
fiber=5.1, sugar=2.2, sodium=33, calcium=47,
|
||
source="manual"
|
||
)
|
||
session.add_all([food1, food2])
|
||
session.commit()
|
||
session.refresh(food1)
|
||
session.refresh(food2)
|
||
|
||
meal = Meal(name="Chicken and Broccoli", meal_type="dinner", meal_time="Dinner")
|
||
session.add(meal)
|
||
session.commit()
|
||
session.refresh(meal)
|
||
|
||
meal_food1 = MealFood(meal_id=meal.id, food_id=food1.id, quantity=1.5) # 150g chicken
|
||
meal_food2 = MealFood(meal_id=meal.id, food_id=food2.id, quantity=2.0) # 200g broccoli
|
||
session.add_all([meal_food1, meal_food2])
|
||
session.commit()
|
||
|
||
test_date = date.today()
|
||
|
||
# Simulate adding a tracked meal
|
||
response_add_meal = client.post(
|
||
"/tracker/add_meal",
|
||
data={
|
||
"person": "Sarah",
|
||
"date": test_date.isoformat(),
|
||
"meal_id": meal.id,
|
||
"meal_time": "Dinner"
|
||
}
|
||
)
|
||
assert response_add_meal.status_code == 200
|
||
assert response_add_meal.json()["status"] == "success"
|
||
|
||
# Now request the detailed view for the tracked day (this will be the new endpoint)
|
||
response = client.get(f"/detailed_tracked_day?person=Sarah&date={test_date.isoformat()}")
|
||
assert response.status_code == 200
|
||
|
||
# Assert that the meal and individual food items are present
|
||
assert "Detailed Day for Sarah" in response.text
|
||
assert "Chicken and Broccoli" in response.text
|
||
assert "Chicken Breast" in response.text
|
||
assert "Broccoli" in response.text
|
||
assert "1.5 × 100g" in response.text # Check quantity and unit for chicken
|
||
assert "2.0 × 100g" in response.text # Check quantity and unit for broccoli
|
||
assert "248" in response.text # Check calories for chicken (1.5 * 165 = 247.5, rounded to 248)
|
||
assert "110" in response.text # Check calories for broccoli (2.0 * 55 = 110)
|
||
|
||
def test_detailed_page_with_invalid_plan_date(client):
|
||
invalid_date = date.today() + timedelta(days=100)
|
||
response = client.get(f"/detailed?person=Sarah&plan_date={invalid_date.isoformat()}")
|
||
assert response.status_code == 200
|
||
# Check for content that indicates empty plan
|
||
assert "Detailed Plan for" in response.text
|
||
assert "No meals planned for this day." in response.text
|
||
|
||
|
||
def test_detailed_page_with_invalid_template_id(client):
|
||
response = client.get(f"/detailed?template_id=99999")
|
||
assert response.status_code == 200
|
||
assert "Template Not Found" in response.text
|
||
|
||
|
||
def test_detailed_page_template_dropdown(client, session):
|
||
# Create multiple templates
|
||
template1 = Template(name="Morning Boost")
|
||
template2 = Template(name="Evening Energy")
|
||
session.add(template1)
|
||
session.add(template2)
|
||
session.commit()
|
||
session.refresh(template1)
|
||
session.refresh(template2)
|
||
|
||
# Test that the template dropdown shows available templates
|
||
response = client.get("/detailed")
|
||
assert response.status_code == 200
|
||
|
||
# Check that the response contains template selection UI elements
|
||
assert "View Template" in response.text
|
||
assert "Morning Boost" in response.text
|
||
assert "Evening Energy" in response.text
|
||
|
||
# Verify that template IDs are present in the dropdown options
|
||
# Use url_for style or direct check
|
||
assert str(template1.id) in response.text
|
||
assert str(template2.id) in response.text |