72 lines
3.2 KiB
Python
72 lines
3.2 KiB
Python
"""Integration tier: run the SSR app against a REAL backend container (pulled by
|
|
scripts/backend-for-tests.sh). Exercises the actual HTTP contract instead of backend
|
|
source — catches drift the unit fixtures can't. Asserts the contract (reachability,
|
|
version negotiation, payload shape, SSR renders 200), not exact climate numbers.
|
|
Skips automatically when Docker/the image isn't available (see tests/conftest.py).
|
|
"""
|
|
import json
|
|
import os
|
|
|
|
import httpx
|
|
import pytest
|
|
|
|
B = "/thermograph"
|
|
SLUG = "london-england-gb"
|
|
MONTH = "july"
|
|
API = "v2" # frontend api_client.API_VERSION
|
|
_FIXTURES = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "fixtures")
|
|
|
|
|
|
def _live(backend_service, path):
|
|
# The backend container runs THERMOGRAPH_BASE=/, so its API is at /api/<ver>/...
|
|
return httpx.get(f"{backend_service}{path}", timeout=40.0)
|
|
|
|
|
|
def test_backend_version_is_compatible(backend_service):
|
|
"""The live backend advertises a contract the frontend (API_VERSION=v2) can talk to."""
|
|
v = _live(backend_service, "/api/version").json()
|
|
assert v["backend_version"] == "2", v # frontend targets /api/v2
|
|
assert int(v["min_frontend"]) <= 2, v # backend still accepts this frontend
|
|
|
|
|
|
@pytest.mark.parametrize("ep", ["home", "sitemap", "hub", "city", "month", "records"])
|
|
def test_fixture_shapes_match_live_backend(backend_service, ep):
|
|
"""The committed unit fixtures still match the live payload shapes — proves the two
|
|
tiers can't silently diverge. Compares top-level structure, not values."""
|
|
paths = {
|
|
"home": f"/api/{API}/content/home",
|
|
"sitemap": f"/api/{API}/content/sitemap",
|
|
"hub": f"/api/{API}/content/hub",
|
|
"city": f"/api/{API}/content/city/{SLUG}",
|
|
"month": f"/api/{API}/content/city/{SLUG}/month/{MONTH}",
|
|
"records": f"/api/{API}/content/city/{SLUG}/records",
|
|
}
|
|
live = _live(backend_service, paths[ep])
|
|
assert live.status_code == 200, live.text[:200]
|
|
live_json = live.json()
|
|
with open(os.path.join(_FIXTURES, f"{ep}.json"), encoding="utf-8") as fh:
|
|
fixture = json.load(fh)
|
|
if isinstance(fixture, dict):
|
|
assert set(live_json.keys()) == set(fixture.keys()), (
|
|
f"{ep}: live keys {sorted(live_json)} != fixture keys {sorted(fixture)} "
|
|
"— run scripts/capture-fixtures.sh")
|
|
else:
|
|
assert type(live_json) is type(fixture)
|
|
|
|
|
|
def test_unknown_city_404(backend_service):
|
|
assert _live(backend_service, f"/api/{API}/content/city/nope-not-a-city").status_code == 404
|
|
|
|
|
|
@pytest.mark.parametrize("path", ["/", "/climate", f"/climate/{SLUG}", f"/climate/{SLUG}/{MONTH}",
|
|
f"/climate/{SLUG}/records", "/sitemap.xml", "/robots.txt"])
|
|
def test_ssr_renders_against_live_backend(live_client, path):
|
|
"""The SSR app rendering each page end-to-end against the live backend proves every
|
|
field content.py reads is actually present in the real payload."""
|
|
r = live_client.get(f"{B}{path}")
|
|
assert r.status_code == 200, f"{path} -> {r.status_code}"
|
|
assert "__ORIGIN__" not in r.text
|
|
|
|
|
|
def test_ssr_unknown_city_404(live_client):
|
|
assert live_client.get(f"{B}/climate/nope-not-a-city").status_code == 404
|