import datetime import unittest from fastapi.testclient import TestClient import main from db import connect, create class TestMealsWriteV2(unittest.IsolatedAsyncioTestCase): async def asyncSetUp(self): self.conn = await connect(":memory:") await create(self.conn) async def override_get_db(): try: yield self.conn finally: pass main.app.dependency_overrides[main.get_db] = override_get_db self.client = TestClient(main.app) # Auth user and create household r = self.client.post( "/api/v1/auth/register", json={"email": "w@test.com", "password": "pw", "displayName": "W"}, ) assert r.status_code == 200, r.text token = r.json()["accessToken"] self.headers = {"Authorization": f"Bearer {token}"} r = self.client.post("/api/v1/households", headers=self.headers, json={"name": "H"}) assert r.status_code == 200, r.text self.slug = r.json()["slug"] async def asyncTearDown(self): await self.conn.close() main.app.dependency_overrides.clear() def test_create_update_delete_scoped(self): # Create a meal with suggested date and one extra ingredient body = { "suggestedDate": datetime.datetime.now().astimezone().isoformat(), "chefs": [{"id": 1, "displayName": "A"}], "cleanup": [{"id": 1, "displayName": "A"}], "consumers": [{"id": 1, "displayName": "A"}], "recipes": [], "extraIngredients": [ {"name": "Salt", "line": "Salt", "unit": "Items", "quantity": 1, "preparation": ""} ], } r = self.client.post( f"/api/v1/households/{self.slug}/meals", headers=self.headers, json=body, ) assert r.status_code == 200, r.text created = r.json() meal_id = created["id"] # Update: add an extra ingredient created["extraIngredients"].append( {"name": "Pepper", "line": "Pepper", "unit": "Items", "quantity": 1, "preparation": ""} ) r2 = self.client.put( f"/api/v1/households/{self.slug}/meals/{meal_id}", headers=self.headers, json=created ) assert r2.status_code == 200, r2.text updated = r2.json() assert len(updated["extraIngredients"]) == 2 # Delete r3 = self.client.delete( f"/api/v1/households/{self.slug}/meals/{meal_id}", headers=self.headers ) assert r3.status_code == 200, r3.text def test_create_meal_validation_errors(self): # Base valid body base = { "suggestedDate": datetime.datetime.now().astimezone().isoformat(), "chefs": [{"id": 1, "displayName": "A"}], "cleanup": [{"id": 1, "displayName": "A"}], "consumers": [{"id": 1, "displayName": "A"}], "recipes": [], "extraIngredients": [ {"name": "Salt", "line": "Salt", "unit": "Items", "quantity": 1, "preparation": ""} ], } # No chefs body = dict(base) body["chefs"] = [] r = self.client.post( f"/api/v1/households/{self.slug}/meals", headers=self.headers, json=body ) assert r.status_code == 400 assert "chef" in r.json()["title"].lower() # No cleanup body = dict(base) body["cleanup"] = [] r = self.client.post( f"/api/v1/households/{self.slug}/meals", headers=self.headers, json=body ) assert r.status_code == 400 assert "cleanup" in r.json()["title"].lower() # No consumers body = dict(base) body["consumers"] = [] r = self.client.post( f"/api/v1/households/{self.slug}/meals", headers=self.headers, json=body ) assert r.status_code == 400 assert "consumer" in r.json()["title"].lower() # No recipes or extra ingredients body = dict(base) body["recipes"] = [] body["extraIngredients"] = [] r = self.client.post( f"/api/v1/households/{self.slug}/meals", headers=self.headers, json=body ) assert r.status_code == 400 assert "recipe" in r.json()["title"].lower() or "ingredient" in r.json()["title"].lower() # Zero servings in recipe body = dict(base) body["recipes"] = [{"mealId": -1, "recipeId": 1, "servings": 0}] r = self.client.post( f"/api/v1/households/{self.slug}/meals", headers=self.headers, json=body ) assert r.status_code == 400 assert "servings" in r.json()["title"].lower() def test_update_id_mismatch_and_not_found_and_delete_not_found(self): # Create a valid meal first body = { "suggestedDate": datetime.datetime.now().astimezone().isoformat(), "chefs": [{"id": 1, "displayName": "A"}], "cleanup": [{"id": 1, "displayName": "A"}], "consumers": [{"id": 1, "displayName": "A"}], "recipes": [], "extraIngredients": [ {"name": "Salt", "line": "Salt", "unit": "Items", "quantity": 1, "preparation": ""} ], } r = self.client.post( f"/api/v1/households/{self.slug}/meals", headers=self.headers, json=body ) assert r.status_code == 200, r.text created = r.json() # ID mismatch mismatch = dict(created) wrong_id = created["id"] + 123 r_mis = self.client.put( f"/api/v1/households/{self.slug}/meals/{wrong_id}", headers=self.headers, json=mismatch ) assert r_mis.status_code == 400 # Not found update mismatch["id"] = wrong_id r_nf = self.client.put( f"/api/v1/households/{self.slug}/meals/{wrong_id}", headers=self.headers, json=mismatch ) assert r_nf.status_code == 404 # Delete not found r_del_nf = self.client.delete( f"/api/v1/households/{self.slug}/meals/{wrong_id}", headers=self.headers ) assert r_del_nf.status_code == 404