Starlette 1.3.x prefers httpx2 for starlette.testclient.TestClient; plain httpx still works but emits StarletteDeprecationWarning. - Pin httpx2==2.9.1 (keep httpx for MCP/runtime) - Centralize Web UI TestClient import via tests/webui_testclient.py - Point all test_webui_* modules at the helper - Add regression tests that the deprecation warning is gone Closes #682
136 lines
4.4 KiB
Python
136 lines
4.4 KiB
Python
"""Tests for the Phase 1 operator console application shell (#638)."""
|
|
import sys
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
|
|
|
from starlette.routing import Route
|
|
from webui_testclient import TestClient
|
|
|
|
from webui import layout
|
|
from webui.app import create_app
|
|
from webui.nav import NAV_GROUPS, STUB_PAGES, nav_hrefs
|
|
|
|
|
|
class TestShellNav(unittest.TestCase):
|
|
def setUp(self):
|
|
self.client = TestClient(create_app())
|
|
|
|
def test_nav_group_labels_present(self):
|
|
text = self.client.get("/").text
|
|
for group in NAV_GROUPS:
|
|
with self.subTest(group=group.label):
|
|
self.assertIn(f">{group.label}<", text)
|
|
|
|
def test_phase1_group_labels_cover_expected_ia(self):
|
|
labels = {group.label for group in NAV_GROUPS}
|
|
for expected in (
|
|
"Health",
|
|
"Traffic",
|
|
"Runtime/Sessions",
|
|
"Projects",
|
|
"Inventory",
|
|
"Timeline",
|
|
"Policy",
|
|
"Insights",
|
|
):
|
|
with self.subTest(label=expected):
|
|
self.assertIn(expected, labels)
|
|
|
|
def test_every_nav_href_resolves_to_a_get_route(self):
|
|
app = create_app()
|
|
get_paths = {
|
|
route.path
|
|
for route in app.routes
|
|
if isinstance(route, Route) and "GET" in route.methods
|
|
}
|
|
for href in nav_hrefs():
|
|
with self.subTest(href=href):
|
|
self.assertIn(href, get_paths, f"nav href {href} has no GET route")
|
|
|
|
def test_legacy_hrefs_still_navigable(self):
|
|
text = self.client.get("/").text
|
|
for href in ("/queue", "/projects", "/prompts", "/runtime",
|
|
"/audit", "/worktrees", "/leases", "/actions"):
|
|
with self.subTest(href=href):
|
|
self.assertIn(f'href="{href}"', text)
|
|
|
|
|
|
class TestShellBadges(unittest.TestCase):
|
|
def setUp(self):
|
|
self.client = TestClient(create_app())
|
|
|
|
def test_mode_badge_present(self):
|
|
self.assertIn("mode: read-only", self.client.get("/").text)
|
|
|
|
def test_environment_badge_present(self):
|
|
self.assertIn("env:", self.client.get("/").text)
|
|
|
|
def test_default_environment_is_local(self):
|
|
self.assertEqual(layout.environment_label(), "local")
|
|
|
|
def test_remote_bind_reports_remote_environment(self):
|
|
import os
|
|
|
|
prior = os.environ.get("WEBUI_HOST")
|
|
os.environ["WEBUI_HOST"] = "10.0.0.5"
|
|
try:
|
|
self.assertEqual(layout.environment_label(), "remote")
|
|
finally:
|
|
if prior is None:
|
|
os.environ.pop("WEBUI_HOST", None)
|
|
else:
|
|
os.environ["WEBUI_HOST"] = prior
|
|
|
|
def test_docs_link_present(self):
|
|
text = self.client.get("/").text
|
|
self.assertIn(layout.DOCS_URL, text)
|
|
self.assertIn(">Docs<", text)
|
|
|
|
|
|
class TestShellStubs(unittest.TestCase):
|
|
def setUp(self):
|
|
self.client = TestClient(create_app())
|
|
|
|
def test_stub_routes_render_200(self):
|
|
for path, (title, _desc) in STUB_PAGES.items():
|
|
with self.subTest(path=path):
|
|
response = self.client.get(path)
|
|
self.assertEqual(response.status_code, 200, path)
|
|
self.assertIn(title, response.text)
|
|
self.assertIn("placeholder", response.text)
|
|
|
|
def test_stub_routes_are_read_only(self):
|
|
for path in STUB_PAGES:
|
|
with self.subTest(path=path):
|
|
response = self.client.post(path)
|
|
self.assertEqual(response.status_code, 405)
|
|
self.assertEqual(response.json()["error"], "read-only-mvp")
|
|
|
|
def test_stub_pages_carry_nav_and_badges(self):
|
|
response = self.client.get("/inventory")
|
|
self.assertIn("mode: read-only", response.text)
|
|
self.assertIn('href="/queue"', response.text)
|
|
|
|
|
|
class TestShellHome(unittest.TestCase):
|
|
def setUp(self):
|
|
self.client = TestClient(create_app())
|
|
|
|
def test_home_summarizes_console(self):
|
|
text = self.client.get("/").text
|
|
self.assertIn("Operator console", text)
|
|
self.assertIn("Phase 1", text)
|
|
|
|
def test_home_links_legacy_pages(self):
|
|
text = self.client.get("/").text
|
|
self.assertIn("MVP legacy pages", text)
|
|
for href in ("/queue", "/audit", "/leases"):
|
|
with self.subTest(href=href):
|
|
self.assertIn(f'href="{href}"', text)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|