Public Access
POST/PATCH validate every ingredient_id against the ingredient table and return 422 with the missing list when refs don't resolve. Replaces the prior recipes.py stub. Public read routes + admin write routes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
84 lines
2.6 KiB
Python
84 lines
2.6 KiB
Python
import pytest
|
|
|
|
pytestmark = pytest.mark.requires_postgres
|
|
|
|
|
|
def _admin_headers() -> dict:
|
|
return {"Authorization": "Bearer test-admin-token"}
|
|
|
|
|
|
def _new_ingredient(client, name: str) -> str:
|
|
r = client.post(
|
|
"/api/admin/ingredients",
|
|
json={"name": name, "aliases": [], "aisle": "pantry", "unit": "ea"},
|
|
headers=_admin_headers(),
|
|
)
|
|
assert r.status_code == 201, r.text
|
|
return r.json()["id"]
|
|
|
|
|
|
def test_create_recipe_with_canonical_ingredients(client):
|
|
chicken = _new_ingredient(client, "Test Chicken Thighs Recipe1")
|
|
olive_oil = _new_ingredient(client, "Test Olive Oil Recipe1")
|
|
body = {
|
|
"name": "Test Sheet-Pan Chicken",
|
|
"prep_time_minutes": 10,
|
|
"cook_time_minutes": 30,
|
|
"servings": 4,
|
|
"cuisine_tags": ["american"],
|
|
"dietary_tags": [],
|
|
"protein_type": "chicken",
|
|
"calories_per_serving": 520,
|
|
"ingredients": [
|
|
{"ingredient_id": chicken, "qty": 2.0, "unit": "lb"},
|
|
{"ingredient_id": olive_oil, "qty": 2.0, "unit": "tbsp"},
|
|
],
|
|
"instructions": ["Preheat oven to 425", "Roast 30 min"],
|
|
}
|
|
r = client.post("/api/admin/recipes", json=body, headers=_admin_headers())
|
|
assert r.status_code == 201, r.text
|
|
data = r.json()
|
|
assert data["id"]
|
|
assert len(data["ingredients"]) == 2
|
|
|
|
|
|
def test_create_recipe_rejects_unknown_ingredient_id(client):
|
|
body = {
|
|
"name": "Test Bogus Recipe",
|
|
"prep_time_minutes": 5,
|
|
"cook_time_minutes": 5,
|
|
"servings": 4,
|
|
"cuisine_tags": [],
|
|
"dietary_tags": [],
|
|
"protein_type": "vegetarian",
|
|
"ingredients": [
|
|
{"ingredient_id": "00000000-0000-0000-0000-000000000000", "qty": 1, "unit": "ea"}
|
|
],
|
|
"instructions": ["nope"],
|
|
}
|
|
r = client.post("/api/admin/recipes", json=body, headers=_admin_headers())
|
|
assert r.status_code == 422
|
|
|
|
|
|
def test_list_recipes_returns_seeded_data(client):
|
|
chicken = _new_ingredient(client, "Test Chicken Thighs Recipe2")
|
|
client.post(
|
|
"/api/admin/recipes",
|
|
json={
|
|
"name": "Test Listable Recipe",
|
|
"prep_time_minutes": 5,
|
|
"cook_time_minutes": 25,
|
|
"servings": 4,
|
|
"cuisine_tags": ["american"],
|
|
"dietary_tags": [],
|
|
"protein_type": "chicken",
|
|
"ingredients": [{"ingredient_id": chicken, "qty": 1, "unit": "lb"}],
|
|
"instructions": ["cook"],
|
|
},
|
|
headers=_admin_headers(),
|
|
)
|
|
r = client.get("/api/recipes")
|
|
assert r.status_code == 200
|
|
names = {row["name"] for row in r.json()}
|
|
assert "Test Listable Recipe" in names
|