# ============================================================================== # Author: Simon-Pierre Boucher # File: tests/test_ueat.py # Desc: Régression du connecteur UEAT — rejeu HORS LIGNE d'une fixture réelle # (extrait Poulet Rouge capté sur api.ueat.io). Vérifie : une fiche par # succursale QC, filtrage hors-province, prix exacts, options # (variations + questions), contexte takeout, tags diète. # ============================================================================== import json from pathlib import Path import pytest from restoka.connectors.ueat import UeatConnector FIXTURE = json.loads( (Path(__file__).parent / "fixtures" / "ueat" / "poulet_rouge.json") .read_text(encoding="utf-8")) class OfflineUeat(UeatConnector): """Connecteur rejoué depuis la fixture (aucun appel réseau).""" use_detail_cache = False def _integrations(self): return [{"key": "fixture-guid", "label": "Poulet Rouge (fixture)"}] def _gql(self, api_key, query, variables=None, operation=None): if operation == "getFranchises": return FIXTURE["getFranchises"] if operation == "menuCategories" or "menuCategories" in query: return FIXTURE["menuCategories"] if operation == "items": return {"items": FIXTURE["items"][str(variables["categoryId"])]} if operation == "questions": return FIXTURE["questions"][str(variables["menuItemId"])] raise AssertionError(f"requête inattendue : {operation}") @pytest.fixture(scope="module") def restos(): return [r.finalize() for r in OfflineUeat().fetch()] def test_une_fiche_par_succursale_quebec(restos): # 3 succursales dans la fixture, mais Ottawa (Ontario) est hors périmètre assert len(restos) == 2 assert {r.city for r in restos} == {"Québec", "Sherbrooke"} assert all(r.chain == "Poulet Rouge" for r in restos) assert len({r.uid for r in restos}) == 2 def test_regions_rattachees(restos): regions = {r.city: r.region for r in restos} assert regions["Québec"] == "Capitale-Nationale" assert regions["Sherbrooke"] == "Estrie" def test_prix_exacts(restos): """Les prix sont l'actif le plus critique : ils doivent être EXACTS.""" menu = restos[0].menu assert menu["price_context"] == "takeout" assert menu["price_source"] == "ueat" prix = {it["name"]: it["price"] for sec in menu["sections"] for it in sec["items"]} assert prix["Créez Votre Rouge Bol (1 Saveur)"] == 14.29 assert prix["Rouge Bol (Végé)"] == 11.29 assert prix["Patates Frites"] == 4.99 def test_sections(restos): noms = [s["name"] for s in restos[0].menu["sections"]] assert noms == ["Rouge Bol", "À-Côtés & Desserts"] def test_options_variations(restos): frites = next(it for sec in restos[0].menu["sections"] for it in sec["items"] if it["name"] == "Patates Frites") fmt = next(op for op in frites["options"] if op["group"] == "Format") assert fmt["required"] is True deltas = {c["name"]: c["price_delta"] for c in fmt["choices"]} assert deltas["Régulière"] == 0.0 assert deltas["Grande"] == 2.0 # 6,99 − 4,99 def test_options_questions(restos): bol = next(it for sec in restos[0].menu["sections"] for it in sec["items"] if it["name"] == "Créez Votre Rouge Bol (1 Saveur)") base = next(op for op in bol["options"] if op["group"] == "Choisissez votre base") assert base["required"] is True deltas = {c["name"]: c["price_delta"] for c in base["choices"]} assert deltas["Riz basmati"] == 0.0 assert deltas["Salade César"] == 1.5 def test_tags_diete(restos): vege = next(it for sec in restos[0].menu["sections"] for it in sec["items"] if it["name"] == "Rouge Bol (Végé)") assert "vegetarien" in vege["tags"] assert "vegetarien" in restos[0].dietary_options