The registry is cached for the process and reset by the same admin endpoint that rebuilds the sitemaps, so places and sitemap always describe the same corpus rather than drifting apart. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015mWQnpye9F299NVRCCSRvj
72 lines
2.4 KiB
Python
72 lines
2.4 KiB
Python
"""Tests for the places API (spec 2026-08-21)."""
|
|
|
|
import numpy as np
|
|
import pandas as pd
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
|
|
|
|
def _schools_df() -> pd.DataFrame:
|
|
base = {
|
|
"local_authority": "Essex", "school_type": "Academy",
|
|
"phase": "Primary", "year": 202425, "ofsted_grade": 2.0,
|
|
"ofsted_date": None, "attainment_8_score": np.nan,
|
|
"town": "Brentwood", "postcode": "CM13 1AA", "status": "Open",
|
|
"address": "1 Test Street", "latitude": 51.6, "longitude": 0.3,
|
|
}
|
|
return pd.DataFrame([
|
|
{**base, "urn": 100000 + i, "school_name": f"Brentwood School {i}",
|
|
"rwm_expected_pct": 50.0 + i}
|
|
for i in range(6)
|
|
])
|
|
|
|
|
|
@pytest.fixture()
|
|
def client(monkeypatch):
|
|
from backend import app as app_module
|
|
|
|
monkeypatch.setattr(app_module, "load_school_data", _schools_df)
|
|
monkeypatch.setattr(app_module, "load_latest_school_data", _schools_df)
|
|
monkeypatch.setattr(app_module, "_place_registry", None)
|
|
return TestClient(app_module.app, raise_server_exceptions=False)
|
|
|
|
|
|
def test_registry_lists_each_published_place(client):
|
|
body = client.get("/api/places").json()
|
|
slugs = {(p["kind"], p["slug"]) for p in body["places"]}
|
|
assert ("town", "brentwood") in slugs
|
|
assert ("authority", "essex") in slugs
|
|
assert ("outcode", "cm13") in slugs
|
|
|
|
|
|
def test_registry_carries_a_count_per_place(client):
|
|
body = client.get("/api/places").json()
|
|
town = next(p for p in body["places"] if p["slug"] == "brentwood")
|
|
assert town["count"] == 6
|
|
|
|
|
|
def test_place_detail_returns_its_schools_ranked(client):
|
|
body = client.get("/api/places/town/brentwood").json()
|
|
assert body["place"]["name"] == "Brentwood"
|
|
scores = [s["rwm_expected_pct"] for s in body["schools"]]
|
|
assert scores == sorted(scores, reverse=True)
|
|
|
|
|
|
def test_place_detail_carries_the_local_average(client):
|
|
body = client.get("/api/places/town/brentwood").json()
|
|
# 50..55 inclusive
|
|
assert body["averages"]["rwm_expected_pct"] == pytest.approx(52.5)
|
|
|
|
|
|
def test_phase_filter_narrows_the_school_list(client):
|
|
body = client.get("/api/places/town/brentwood?phase=secondary").json()
|
|
assert body["schools"] == []
|
|
|
|
|
|
def test_unknown_place_404s(client):
|
|
assert client.get("/api/places/town/atlantis").status_code == 404
|
|
|
|
|
|
def test_unknown_kind_404s(client):
|
|
assert client.get("/api/places/planet/mars").status_code == 404
|