from __future__ import annotations from app import demo_gap from app.models import Tenant class _Chunk: pass async def test_gap_report_labels_hit_and_miss(db_session, monkeypatch): t = Tenant(slug="demo-x", name="X", brand_name="Tienda X", is_demo=True) db_session.add(t) await db_session.flush() # Deterministic retrieval: only the shipping questions are "answered" by the # store's pages (score above threshold); everything else is a gap. async def fake_search(db, q, k=3, tenant_id=None): score = 0.55 if "env" in q.lower() else 0.10 return [(_Chunk(), score)] monkeypatch.setattr(demo_gap.rag_index, "search", fake_search) rep = await demo_gap.generate_gap_report(db_session, t, lang="es") assert rep["brand"] == "Tienda X" assert rep["total"] == len(demo_gap.GAP_QUESTIONS["es"]) hits = [r for r in rep["questions"] if r["status"] == "hit"] assert hits and all("env" in r["q"].lower() for r in hits) # only shipping = HIT assert rep["answered"] == len(hits) assert rep["gap_count"] == rep["total"] - len(hits) assert all(g not in [h["q"] for h in hits] for g in rep["gaps"]) async def test_gap_report_all_miss_when_nothing_indexed(db_session, monkeypatch): t = Tenant(slug="demo-empty", is_demo=True) db_session.add(t) await db_session.flush() async def empty_search(db, q, k=3, tenant_id=None): return [] # store crawled nothing useful -> every buyer question is a gap monkeypatch.setattr(demo_gap.rag_index, "search", empty_search) rep = await demo_gap.generate_gap_report(db_session, t, lang="en") assert rep["gap_count"] == rep["total"] and rep["answered"] == 0