"""mumble — web client parity port (Phase 2 P2). SOURCE: recipe-info/mumble/tests/web_client.py — "Verifies the web client is reachable via HTTPS, returns HTTP 200, and serves the Mumble Web UI with expected page content." Requires the compose.mumbleweb.yml overlay (enabled via recipe_meta.EXTRA_ENV COMPOSE_FILE). """ from __future__ import annotations import os import ssl import sys import urllib.request sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", "..", "runner")) from harness import http as harness_http # noqa: E402 def _fetch_body(url: str) -> str: ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE with urllib.request.urlopen(urllib.request.Request(url), timeout=15, context=ctx) as resp: return resp.read().decode("utf-8", errors="replace") def test_web_client_serves_mumble_web_ui(live_app): url = f"https://{live_app}/" status, _ = harness_http.retry_http_get(url, expect_status=200, max_wait=120, interval=5) assert status == 200, f"GET {url} HTTP {status} (expected 200)" body = _fetch_body(url) assert "Mumble" in body, "web client page does not contain 'Mumble' content" assert "config.js" in body, "web client page does not load config.js" assert body.strip().startswith(""), "web client response is not valid HTML"