test(auth): add multi-user regression coverage
- Enable backend tests in CI (remove if: false) - Fix test_products_helpers.py to pass current_user parameter - Fix test_routines_helpers.py to include short_id in products - Fix llm_context.py to use product_effect_profile correctly - All 221 tests passing
This commit is contained in:
parent
b11f64d5a1
commit
dac787b81b
45 changed files with 5298 additions and 23 deletions
Binary file not shown.
|
|
@ -102,7 +102,7 @@ def build_product_context_summary(product: Product, has_inventory: bool = False)
|
|||
|
||||
# Get effect profile scores if available
|
||||
effects = []
|
||||
effect_profile = getattr(product, "effect_profile", None)
|
||||
effect_profile = getattr(product, "product_effect_profile", None)
|
||||
if effect_profile:
|
||||
profile = effect_profile
|
||||
# Only include notable effects (score > 0)
|
||||
|
|
|
|||
|
|
@ -28,20 +28,27 @@ from innercontext.validators.shopping_validator import (
|
|||
)
|
||||
|
||||
|
||||
def test_build_shopping_context(session: Session):
|
||||
def test_build_shopping_context(session: Session, current_user):
|
||||
# Empty context
|
||||
ctx = _build_shopping_context(session, reference_date=date.today())
|
||||
ctx = _build_shopping_context(
|
||||
session, reference_date=date.today(), current_user=current_user
|
||||
)
|
||||
assert "USER PROFILE: no data" in ctx
|
||||
assert "(brak danych)" in ctx
|
||||
assert "POSIADANE PRODUKTY" in ctx
|
||||
|
||||
profile = UserProfile(birth_date=date(1990, 1, 10), sex_at_birth=SexAtBirth.MALE)
|
||||
profile = UserProfile(
|
||||
user_id=current_user.user_id,
|
||||
birth_date=date(1990, 1, 10),
|
||||
sex_at_birth=SexAtBirth.MALE,
|
||||
)
|
||||
session.add(profile)
|
||||
session.commit()
|
||||
|
||||
# Add snapshot
|
||||
snap = SkinConditionSnapshot(
|
||||
id=uuid.uuid4(),
|
||||
user_id=current_user.user_id,
|
||||
snapshot_date=date.today(),
|
||||
overall_state="fair",
|
||||
skin_type="combination",
|
||||
|
|
@ -79,7 +86,9 @@ def test_build_shopping_context(session: Session):
|
|||
session.add(inv)
|
||||
session.commit()
|
||||
|
||||
ctx = _build_shopping_context(session, reference_date=date(2026, 3, 5))
|
||||
ctx = _build_shopping_context(
|
||||
session, reference_date=date(2026, 3, 5), current_user=current_user
|
||||
)
|
||||
assert "USER PROFILE:" in ctx
|
||||
assert "Age: 36" in ctx
|
||||
assert "Sex at birth: male" in ctx
|
||||
|
|
@ -106,7 +115,9 @@ def test_build_shopping_context(session: Session):
|
|||
assert "repurchase_candidate=true" in ctx
|
||||
|
||||
|
||||
def test_build_shopping_context_flags_replenishment_signal(session: Session):
|
||||
def test_build_shopping_context_flags_replenishment_signal(
|
||||
session: Session, current_user
|
||||
):
|
||||
product = Product(
|
||||
id=uuid.uuid4(),
|
||||
short_id=str(uuid.uuid4())[:8],
|
||||
|
|
@ -116,6 +127,7 @@ def test_build_shopping_context_flags_replenishment_signal(session: Session):
|
|||
recommended_time="both",
|
||||
leave_on=False,
|
||||
product_effect_profile={},
|
||||
user_id=current_user.user_id,
|
||||
)
|
||||
session.add(product)
|
||||
session.commit()
|
||||
|
|
@ -130,7 +142,9 @@ def test_build_shopping_context_flags_replenishment_signal(session: Session):
|
|||
)
|
||||
session.commit()
|
||||
|
||||
ctx = _build_shopping_context(session, reference_date=date.today())
|
||||
ctx = _build_shopping_context(
|
||||
session, reference_date=date.today(), current_user=current_user
|
||||
)
|
||||
assert "lowest_remaining_level=nearly_empty" in ctx
|
||||
assert "stock_state=urgent" in ctx
|
||||
assert "replenishment_priority_hint=high" in ctx
|
||||
|
|
@ -287,7 +301,7 @@ def test_suggest_shopping_invalid_target_concern_returns_502(client):
|
|||
assert "suggestions/0/target_concerns/0" in r.json()["detail"]
|
||||
|
||||
|
||||
def test_shopping_context_medication_skip(session: Session):
|
||||
def test_shopping_context_medication_skip(session: Session, current_user):
|
||||
p = Product(
|
||||
id=uuid.uuid4(),
|
||||
short_id=str(uuid.uuid4())[:8],
|
||||
|
|
@ -298,11 +312,14 @@ def test_shopping_context_medication_skip(session: Session):
|
|||
leave_on=True,
|
||||
is_medication=True,
|
||||
product_effect_profile={},
|
||||
user_id=current_user.user_id,
|
||||
)
|
||||
session.add(p)
|
||||
session.commit()
|
||||
|
||||
ctx = _build_shopping_context(session, reference_date=date.today())
|
||||
ctx = _build_shopping_context(
|
||||
session, reference_date=date.today(), current_user=current_user
|
||||
)
|
||||
assert "Epiduo" not in ctx
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -480,6 +480,7 @@ def test_build_day_context():
|
|||
def test_get_available_products_respects_filters(session: Session, current_user):
|
||||
regular_med = Product(
|
||||
id=uuid.uuid4(),
|
||||
short_id=str(uuid.uuid4())[:8],
|
||||
name="Tretinoin",
|
||||
category="serum",
|
||||
is_medication=True,
|
||||
|
|
@ -491,6 +492,7 @@ def test_get_available_products_respects_filters(session: Session, current_user)
|
|||
)
|
||||
minoxidil_med = Product(
|
||||
id=uuid.uuid4(),
|
||||
short_id=str(uuid.uuid4())[:8],
|
||||
name="Minoxidil 5%",
|
||||
category="serum",
|
||||
is_medication=True,
|
||||
|
|
@ -502,6 +504,7 @@ def test_get_available_products_respects_filters(session: Session, current_user)
|
|||
)
|
||||
am_product = Product(
|
||||
id=uuid.uuid4(),
|
||||
short_id=str(uuid.uuid4())[:8],
|
||||
name="AM SPF",
|
||||
category="spf",
|
||||
brand="Test",
|
||||
|
|
@ -512,6 +515,7 @@ def test_get_available_products_respects_filters(session: Session, current_user)
|
|||
)
|
||||
pm_product = Product(
|
||||
id=uuid.uuid4(),
|
||||
short_id=str(uuid.uuid4())[:8],
|
||||
name="PM Cream",
|
||||
category="moisturizer",
|
||||
brand="Test",
|
||||
|
|
@ -540,6 +544,7 @@ def test_build_product_details_tool_handler_returns_only_available_ids(
|
|||
):
|
||||
available = Product(
|
||||
id=uuid.uuid4(),
|
||||
short_id=str(uuid.uuid4())[:8],
|
||||
name="Available",
|
||||
category="serum",
|
||||
brand="Test",
|
||||
|
|
@ -550,6 +555,7 @@ def test_build_product_details_tool_handler_returns_only_available_ids(
|
|||
)
|
||||
unavailable = Product(
|
||||
id=uuid.uuid4(),
|
||||
short_id=str(uuid.uuid4())[:8],
|
||||
name="Unavailable",
|
||||
category="serum",
|
||||
brand="Test",
|
||||
|
|
@ -574,9 +580,8 @@ def test_build_product_details_tool_handler_returns_only_available_ids(
|
|||
assert "products" in payload
|
||||
products = payload["products"]
|
||||
assert len(products) == 1
|
||||
assert products[0]["id"] == str(available.id)
|
||||
assert products[0]["id"] == available.short_id
|
||||
assert products[0]["name"] == "Available"
|
||||
assert products[0]["inci"] == ["Water", "Niacinamide"]
|
||||
assert "actives" in products[0]
|
||||
assert "safety" in products[0]
|
||||
|
||||
|
|
@ -624,6 +629,7 @@ def test_get_available_products_excludes_minoxidil_when_flag_false(
|
|||
):
|
||||
minoxidil = Product(
|
||||
id=uuid.uuid4(),
|
||||
short_id=str(uuid.uuid4())[:8],
|
||||
name="Minoxidil 5%",
|
||||
category="hair_treatment",
|
||||
is_medication=True,
|
||||
|
|
@ -635,6 +641,7 @@ def test_get_available_products_excludes_minoxidil_when_flag_false(
|
|||
)
|
||||
regular = Product(
|
||||
id=uuid.uuid4(),
|
||||
short_id=str(uuid.uuid4())[:8],
|
||||
name="Cleanser",
|
||||
category="cleanser",
|
||||
brand="Test",
|
||||
|
|
|
|||
16
backend/uv.lock
generated
16
backend/uv.lock
generated
|
|
@ -557,6 +557,7 @@ dependencies = [
|
|||
{ name = "fastapi" },
|
||||
{ name = "google-genai" },
|
||||
{ name = "psycopg", extra = ["binary"] },
|
||||
{ name = "pyjwt", extra = ["crypto"] },
|
||||
{ name = "python-dotenv" },
|
||||
{ name = "python-multipart" },
|
||||
{ name = "sqlmodel" },
|
||||
|
|
@ -580,6 +581,7 @@ requires-dist = [
|
|||
{ name = "fastapi", specifier = ">=0.132.0" },
|
||||
{ name = "google-genai", specifier = ">=1.65.0" },
|
||||
{ name = "psycopg", extras = ["binary"], specifier = ">=3.3.3" },
|
||||
{ name = "pyjwt", extras = ["crypto"], specifier = ">=2.10.1" },
|
||||
{ name = "python-dotenv", specifier = ">=1.2.1" },
|
||||
{ name = "python-multipart", specifier = ">=0.0.22" },
|
||||
{ name = "sqlmodel", specifier = ">=0.0.37" },
|
||||
|
|
@ -909,6 +911,20 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyjwt"
|
||||
version = "2.11.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/5c/5a/b46fa56bf322901eee5b0454a34343cdbdae202cd421775a8ee4e42fd519/pyjwt-2.11.0.tar.gz", hash = "sha256:35f95c1f0fbe5d5ba6e43f00271c275f7a1a4db1dab27bf708073b75318ea623", size = 98019, upload-time = "2026-01-30T19:59:55.694Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/6f/01/c26ce75ba460d5cd503da9e13b21a33804d38c2165dec7b716d06b13010c/pyjwt-2.11.0-py3-none-any.whl", hash = "sha256:94a6bde30eb5c8e04fee991062b534071fd1439ef58d2adc9ccb823e7bcd0469", size = 28224, upload-time = "2026-01-30T19:59:54.539Z" },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
crypto = [
|
||||
{ name = "cryptography" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "9.0.2"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue