# ============================================================================== # Author: Simon-Pierre Boucher # File: tests/test_doordash.py # Desc: Connecteur DoorDash (enrichissement livraison) — parsing JSON-LD # (Restaurant + Menu, sections imbriquées, prix « $X.XX »), croisement # CONSERVATEUR verify_store (gps+nom / civique+ville+nom, jamais de # fusion hasardeuse), slugs candidats par préfixe. # ============================================================================== import json from restoka.connectors.doordash import (DoorDashConnector, build_menu, parse_ldjson, slugify, verify_store) LD_RESTO = { "@type": "Restaurant", "name": "Chez Test", "address": {"streetAddress": "123 Rue Principale", "addressLocality": "Montréal", "addressRegion": "QC"}, "geo": {"latitude": "45.5200", "longitude": "-73.5800"}, "servesCuisine": ["Pizza"], "priceRange": "$$", "aggregateRating": {"ratingValue": 4.6, "reviewCount": 210}, } LD_MENU = { "@type": "Menu", "hasMenuSection": [[{ "name": "Pizzas", "hasMenuItem": [ {"name": "Margherita", "description": "Tomate, basilic", "offers": {"price": "$16.50"}}, {"name": "Sans prix", "offers": {}}, ], }, { "name": "Pizzas", # doublon : ignoré "hasMenuItem": [{"name": "Dup", "offers": {"price": "$1.00"}}], }]], } def _page(*blocks) -> str: return "".join( f'' for b in blocks) def test_parse_ldjson_et_build_menu(): resto, menu = parse_ldjson(_page(LD_RESTO, LD_MENU)) assert resto["name"] == "Chez Test" m = build_menu(menu, "2026-08-25T00:00:00Z") assert m["price_context"] == "delivery" and m["price_source"] == "doordash" assert len(m["sections"]) == 1 # doublon de section écarté items = m["sections"][0]["items"] assert items[0]["price"] == 16.50 assert items[1]["price"] is None # prix absent toléré assert build_menu({}, "x") is None def test_parse_ldjson_page_sans_blocs(): assert parse_ldjson("rien") == (None, None) def _row(**over): base = {"uid": "osm:1", "name": "Chez Test", "address": "123 Rue Principale", "city": "Montréal", "postal_code": "H2X1Y4", "phone": "", "lat": 45.5201, "lng": -73.5801} base.update(over) return base def test_verify_store_gps_nom(): assert verify_store(_row(), LD_RESTO) == "gps+nom" def test_verify_store_civique_ville_nom(): # GPS absent côté base : retombe sur civique + ville + nom assert verify_store(_row(lat=None, lng=None), LD_RESTO) \ == "civique+ville+nom" def test_verify_store_rejets(): # autre resto au même endroit : nom différent -> rejet autre = dict(LD_RESTO, name="Pizzeria Autre Chose Complètement") assert verify_store(_row(), autre) == "" # même nom mais loin (>120 m) et civique différent -> rejet loin = dict(LD_RESTO, geo={"latitude": "45.60", "longitude": "-73.70"}, address={"streetAddress": "999 Autre Rue", "addressLocality": "Laval"}) assert verify_store(_row(), loin) == "" def test_slugify_et_candidats(): assert slugify("Café L'Époque & Fils") == "cafe-lepoque-fils" slugs = sorted(["chez-test-montreal-123", "chez-test-laval-456", "chez-testeur-999", "autre-resto-1"]) cand = DoorDashConnector.candidates_for("Chez Test", slugs) assert set(cand) == {"chez-test-montreal-123", "chez-test-laval-456"} assert DoorDashConnector.candidates_for("Ab", slugs) == [] # trop court