def test_search_requires_authentication(client): response = client.get("/api/v1/search", params={"q": "MO-001"}) assert response.status_code == 401 def test_search_finds_a_vehicle_by_reference(ops_client): response = ops_client.get("/api/v1/search", params={"q": "MO-001"}) assert response.status_code == 200 body = response.json() match = next((r for r in body["results"] if r["type"] == "vehicle"), None) assert match is not None assert match["label"] == "MO-001" assert match["link"] == "/vehicles/MO-001" # The backend must never send localizable prose -- only a stable code plus raw # data params, so the frontend can render it in the operator's selected language. assert match["detail_code"] == "vehicleSummary" assert set(match["detail_params"]) == {"make", "model", "location"} def test_search_finds_a_booking_by_reference(ops_client): response = ops_client.get("/api/v1/search", params={"q": "BK-DEMO-RETURN"}) assert response.status_code == 200 match = next((r for r in response.json()["results"] if r["type"] == "booking"), None) assert match is not None assert match["link"] == "/bookings/BK-DEMO-RETURN" def test_search_finds_a_data_quality_issue_for_operations_manager(ops_client): response = ops_client.get("/api/v1/search", params={"q": "DQ-DEMO-OVERLAP"}) assert response.status_code == 200 match = next((r for r in response.json()["results"] if r["type"] == "data_quality_issue"), None) assert match is not None assert match["link"] == "/data-quality/DQ-DEMO-OVERLAP" def test_search_never_returns_data_quality_issues_for_rental_employee(employee_client): response = employee_client.get("/api/v1/search", params={"q": "DQ-DEMO-OVERLAP"}) assert response.status_code == 200 assert all(r["type"] != "data_quality_issue" for r in response.json()["results"]) def test_search_section_result_visible_to_operations_manager(ops_client): result = ops_client.get("/api/v1/search", params={"q": "audit"}).json() match = next( (r for r in result["results"] if r["type"] == "section" and r["link"] == "/audit"), None ) assert match is not None # Section results must ship a stable id, not English prose -- the frontend looks up # navigation:items. and search:sections..detail in the selected locale. assert match["label"] == "audit" assert match["detail_code"] == "audit" def test_search_section_matches_dutch_and_french_terms(ops_client): nl_result = ops_client.get("/api/v1/search", params={"q": "wagenpark"}).json() assert any(r["type"] == "section" and r["link"] == "/vehicles" for r in nl_result["results"]) fr_result = ops_client.get("/api/v1/search", params={"q": "réservation"}).json() assert any(r["type"] == "section" and r["link"] == "/bookings" for r in fr_result["results"]) def test_search_section_result_hidden_from_rental_employee(employee_client): result = employee_client.get("/api/v1/search", params={"q": "audit"}).json() assert all(r["link"] != "/audit" for r in result["results"]) def test_search_never_returns_customer_results(ops_client): response = ops_client.get("/api/v1/search", params={"q": "CUS-0012"}) assert response.status_code == 200 assert all(r["type"] != "customer" for r in response.json()["results"]) def test_search_no_match_returns_empty_results(ops_client): response = ops_client.get("/api/v1/search", params={"q": "zzz-no-such-thing-zzz"}) assert response.status_code == 200 assert response.json()["results"] == []