Files
Meal-Planner/backend/tests/test_ingredient_api.py
T

139 lines
4.5 KiB
Python

import pytest
pytestmark = pytest.mark.requires_postgres
def _admin_headers() -> dict:
return {"Authorization": "Bearer test-admin-token"}
def test_create_ingredient_returns_201_with_id(client):
body = {
"name": "Test Chicken Thighs",
"aliases": ["chicken thigh", "BSL chicken thighs"],
"aisle": "meat_seafood",
"unit": "lb",
}
r = client.post("/api/admin/ingredients", json=body, headers=_admin_headers())
assert r.status_code == 201, r.text
data = r.json()
assert data["id"]
assert data["aliases"] == ["chicken thigh", "BSL chicken thighs"]
def test_create_ingredient_rejects_duplicate_name(client):
body = {"name": "Test Garlic Bulb", "aliases": [], "aisle": "produce", "unit": "clove"}
r1 = client.post("/api/admin/ingredients", json=body, headers=_admin_headers())
assert r1.status_code == 201
r2 = client.post("/api/admin/ingredients", json=body, headers=_admin_headers())
assert r2.status_code == 409
def test_list_ingredients_supports_search(client):
client.post(
"/api/admin/ingredients",
json={"name": "Test Avocado Oil", "aliases": ["EVOO-test"], "aisle": "pantry", "unit": "tbsp"},
headers=_admin_headers(),
)
r = client.get("/api/ingredients?q=avocado")
assert r.status_code == 200
names = {row["name"] for row in r.json()}
assert "Test Avocado Oil" in names
def test_create_ingredient_requires_admin_token(client):
body = {"name": "Test Meyer Lemon", "aisle": "produce", "unit": "ea", "aliases": []}
r = client.post("/api/admin/ingredients", json=body)
assert r.status_code == 401
def test_update_ingredient_replaces_aliases(client):
create = client.post(
"/api/admin/ingredients",
json={"name": "Onion, Yellow", "aliases": ["yellow onion"], "aisle": "produce", "unit": "ea"},
headers=_admin_headers(),
)
iid = create.json()["id"]
r = client.patch(
f"/api/admin/ingredients/{iid}",
json={"aliases": ["yellow onion", "spanish onion"]},
headers=_admin_headers(),
)
assert r.status_code == 200
assert r.json()["aliases"] == ["yellow onion", "spanish onion"]
def _seed_grocery(db_session, name: str) -> str:
from datetime import datetime, timezone
from decimal import Decimal
from uuid import uuid4
from app.models import GroceryItem
gid = uuid4()
db_session.add(
GroceryItem(
id=gid,
name=name,
source="lucky_california",
external_id=f"ext-{gid}",
current_price=Decimal("4.99"),
regular_price=Decimal("4.99"),
is_on_sale=False,
scraped_at=datetime.now(timezone.utc),
)
)
db_session.commit()
return str(gid)
def test_pin_manual_match(client, db_session):
create = client.post(
"/api/admin/ingredients",
json={"name": "Test Manual Pin Veggie", "aliases": [], "aisle": "produce", "unit": "ea"},
headers=_admin_headers(),
)
iid = create.json()["id"]
gid = _seed_grocery(db_session, "Some Other Veggie Brand Test")
r = client.post(
f"/api/admin/ingredients/{iid}/matches",
json={"grocery_item_id": gid, "confidence": 1.0},
headers=_admin_headers(),
)
assert r.status_code == 201, r.text
body = r.json()
assert body["source"] == "manual"
assert body["grocery_item_id"] == gid
def test_unpin_manual_match(client, db_session):
create = client.post(
"/api/admin/ingredients",
json={"name": "Test Unpin Test Item", "aliases": [], "aisle": "produce", "unit": "ea"},
headers=_admin_headers(),
)
iid = create.json()["id"]
gid = _seed_grocery(db_session, "Brand X Test Product")
pin = client.post(
f"/api/admin/ingredients/{iid}/matches",
json={"grocery_item_id": gid, "confidence": 1.0},
headers=_admin_headers(),
)
match_id = pin.json()["id"]
r = client.delete(f"/api/admin/ingredient-matches/{match_id}", headers=_admin_headers())
assert r.status_code == 204
def test_delete_ingredient_removes_row(client):
create = client.post(
"/api/admin/ingredients",
json={"name": "Sage", "aliases": [], "aisle": "produce", "unit": "tsp"},
headers=_admin_headers(),
)
iid = create.json()["id"]
r = client.delete(f"/api/admin/ingredients/{iid}", headers=_admin_headers())
assert r.status_code == 204
r2 = client.get(f"/api/ingredients/{iid}")
assert r2.status_code == 404