"""discourse — Q4.6 recipe-specific functional test (2nd functional, beyond create-topic + health). Asserts Discourse's Rails app emits its bootstrap JSON: GET /site.json returns 200 with the site-config envelope the Ember SPA needs (categories list + default trust levels). This distinguishes "the Discourse Rails backend is up and serving its API" from "a static/error page is served" — a wedged backend 5xxs, a misroute 404s. Complements test_create_topic (write path) with a read of the app's characteristic site config. """ from __future__ import annotations import os import sys sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", "..", "runner")) from harness import http as harness_http # noqa: E402 def test_site_json_has_discourse_config(live_app): status, body = harness_http.retry_http_get( f"https://{live_app}/site.json", expect_status=200, max_wait=120, interval=5 ) assert status == 200 and isinstance(body, dict), ( f"GET /site.json failed: HTTP {status}, body type={type(body).__name__}" ) # /site.json carries Discourse-specific structure — `categories` (a list) and `groups` are always # present in a booted Discourse. A non-Discourse 200 (placeholder page) would not parse to this. assert "categories" in body, f"/site.json missing 'categories' key: keys={list(body)[:20]}" assert isinstance(body["categories"], list), ( f"/site.json 'categories' not a list: {type(body['categories']).__name__}" )