"""Tests for the crawlable SEO content pages: the city set, robots/sitemap, and that the server-rendered pages contain the stats in the HTML (with the weather layer faked, like test_api.py).""" import pytest from fastapi.testclient import TestClient import app as appmod import cities import climate # BASE defaults to /thermograph in tests (THERMOGRAPH_BASE unset). B = "/thermograph" SLUG = "london-england-gb" # present in cities.json @pytest.fixture def client(monkeypatch, history, recent): monkeypatch.setattr(climate, "load_cached_history", lambda cell: history.clone()) monkeypatch.setattr(climate, "get_recent_forecast", lambda cell: recent.clone()) monkeypatch.setattr(climate, "get_history", lambda cell: (history.clone(), {"cached": True})) return TestClient(appmod.app) def test_city_set_slugs_unique_and_lookup(): slugs = cities.all_slugs() assert len(slugs) == len(set(slugs)) >= 100 assert cities.get(SLUG) is not None assert cities.get("does-not-exist") is None def test_robots_txt(client): r = client.get(f"{B}/robots.txt") assert r.status_code == 200 assert "Sitemap:" in r.text and "/sitemap.xml" in r.text assert "Disallow: /thermograph/api/" in r.text def test_sitemap_lists_city_urls(client): r = client.get(f"{B}/sitemap.xml") assert r.status_code == 200 assert "" in r.text assert f"/climate/{SLUG}/july" in r.text assert f"/climate/{SLUG}/records" in r.text def test_city_page_renders_stats_in_html(client): r = client.get(f"{B}/climate/{SLUG}") assert r.status_code == 200 b = r.text assert "London" in b and "climate" in b.lower() assert 'rel="canonical"' in b and f"/climate/{SLUG}" in b assert '"@type":"Dataset"' in b assert "average temperatures by month" in b.lower() # a real number rendered (°F appears in the normals/today text) assert "°F" in b def test_city_404(client): assert client.get(f"{B}/climate/nope-not-a-city").status_code == 404 def test_city_travel_cta_prefills_compare(client): b = client.get(f"{B}/climate/{SLUG}").text assert "Thinking of visiting" in b assert "/compare#loc=" in b # the city is pre-loaded on the compare page def test_city_blurb_renders_with_attribution(client, monkeypatch): monkeypatch.setattr(cities, "flavor", lambda slug: {"extract": "Testville is a lovely place to test.", "url": "https://en.wikipedia.org/wiki/Testville", "title": "Testville"}) b = client.get(f"{B}/climate/{SLUG}").text assert "Testville is a lovely place to test." in b assert "via Wikipedia" in b # CC BY-SA attribution link def test_month_and_records(client): assert client.get(f"{B}/climate/{SLUG}/july").status_code == 200 assert client.get(f"{B}/climate/{SLUG}/records").status_code == 200 assert client.get(f"{B}/climate/{SLUG}/notamonth").status_code == 404 def test_hub_glossary_about(client): assert client.get(f"{B}/climate").status_code == 200 assert client.get(f"{B}/glossary").status_code == 200 assert client.get(f"{B}/glossary/percentile").status_code == 200 assert client.get(f"{B}/glossary/not-a-term").status_code == 404 assert client.get(f"{B}/about").status_code == 200