PR Checks / Frontend Typecheck + Tests (pull_request) Successful in 9m39s
PR Checks / Backend Smoke (pull_request) Successful in 8s
PR Checks / Build Backend (no push) (pull_request) Successful in 30s
PR Checks / Build Frontend (no push) (pull_request) Successful in 42s
PR Checks / Build Pipeline (no push) (pull_request) Successful in 10s
PR Checks / AI Code Review (Claude) (pull_request) Successful in 2m0s
Schools without KS2/KS4 results (special post-16 institutions, sixth-form centres, PRUs, new schools) come back from the marts LEFT JOIN with NaN in every numeric column. school_info passed those raw pandas values straight into JSONResponse, which renders with allow_nan=False, so the detail endpoint 500d and the frontend turned that into a 404 on every such SEO landing page. Run school_info values through convert_to_native (the same treatment yearly_data already gets), add backend unit tests plus a pytest step in PR checks, and an e2e journey that finds a results-less school via the search API and asserts its page renders. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
72 lines
2.5 KiB
Python
72 lines
2.5 KiB
Python
"""Regression tests for GET /api/schools/{urn}.
|
|
|
|
Schools with no performance rows (special post-16 institutions, sixth-form
|
|
centres, PRUs, brand-new schools) come back from the marts LEFT JOIN with
|
|
NaN in every numeric column. The endpoint must still serialize them — a NaN
|
|
that reaches Starlette's JSONResponse raises ValueError (allow_nan=False)
|
|
and the route 500s, which the frontend then renders as a 404.
|
|
"""
|
|
|
|
import numpy as np
|
|
import pandas as pd
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
|
|
|
|
def _no_results_school_df() -> pd.DataFrame:
|
|
"""One school row as produced by the marts query for a school with no
|
|
performance data: GIAS/location fields partly populated, every
|
|
results-linked column NaN (including year)."""
|
|
return pd.DataFrame(
|
|
[
|
|
{
|
|
"urn": 150275,
|
|
"school_name": "West London Performing Arts Academy",
|
|
"phase": "Secondary",
|
|
"school_type": "Special post 16 institution",
|
|
"trust_name": None,
|
|
"religious_denomination": "Does not apply",
|
|
"gender": None,
|
|
"age_range": "16-25",
|
|
"admissions_policy": None,
|
|
"capacity": np.nan,
|
|
"gias_total_pupils": np.nan,
|
|
"headteacher_name": None,
|
|
"website": None,
|
|
"ofsted_grade": np.nan,
|
|
"local_authority": "Ealing",
|
|
"address": "268 Northfield Avenue, London, W5 4UB",
|
|
"postcode": "W5 4UB",
|
|
"latitude": 51.4986,
|
|
"longitude": -0.3148,
|
|
"year": np.nan,
|
|
"total_pupils": np.nan,
|
|
"eligible_pupils": np.nan,
|
|
"rwm_expected_pct": np.nan,
|
|
}
|
|
]
|
|
)
|
|
|
|
|
|
@pytest.fixture()
|
|
def client(monkeypatch):
|
|
from backend import app as app_module
|
|
|
|
monkeypatch.setattr(app_module, "load_school_data", _no_results_school_df)
|
|
monkeypatch.setattr(
|
|
app_module, "get_supplementary_data", lambda db, urn: {}
|
|
)
|
|
return TestClient(app_module.app, raise_server_exceptions=False)
|
|
|
|
|
|
def test_school_without_performance_rows_returns_200(client):
|
|
resp = client.get("/api/schools/150275")
|
|
assert resp.status_code == 200, resp.text
|
|
|
|
|
|
def test_nan_gias_fields_serialize_as_null(client):
|
|
info = client.get("/api/schools/150275").json()["school_info"]
|
|
assert info["capacity"] is None
|
|
assert info["total_pupils"] is None
|
|
assert info["school_name"] == "West London Performing Arts Academy"
|