82 lines
2.9 KiB
Python
82 lines
2.9 KiB
Python
"""Главная страница и изолированные UI модулей."""
|
||
|
||
from unittest.mock import patch
|
||
|
||
from fastapi.testclient import TestClient
|
||
|
||
|
||
def test_root_html_includes_module_cards(client: TestClient) -> None:
|
||
r = client.get("/")
|
||
assert r.status_code == 200
|
||
body = r.text
|
||
assert "Модули" in body
|
||
assert "module-card" in body
|
||
assert "/ui/modules/schedules/" in body
|
||
assert "Календарь дежурств" in body
|
||
assert "app-rail" in body
|
||
assert "rail-nav" in body
|
||
|
||
|
||
def test_module_ui_page_schedules(client: TestClient) -> None:
|
||
r = client.get("/ui/modules/schedules/")
|
||
assert r.status_code == 200
|
||
assert "text/html" in r.headers.get("content-type", "")
|
||
assert "Календарь дежурств" in r.text
|
||
assert "app-rail" in r.text
|
||
assert 'aria-current="page"' in r.text
|
||
|
||
|
||
def test_rail_lists_all_registered_ui_modules(client: TestClient) -> None:
|
||
"""Правое меню синхронизировано с реестром: все модули с ui_router."""
|
||
r = client.get("/")
|
||
assert r.status_code == 200
|
||
t = r.text
|
||
expected = (
|
||
("grafana-catalog", "Каталог Grafana"),
|
||
("incidents", "Инциденты"),
|
||
("tasks", "Задачи"),
|
||
("escalations", "Эскалации"),
|
||
("schedules", "Календарь дежурств"),
|
||
("contacts", "Контакты"),
|
||
("statusboard", "Светофор"),
|
||
)
|
||
for slug, title in expected:
|
||
assert f"/ui/modules/{slug}/" in t
|
||
assert title in t
|
||
|
||
|
||
def test_each_module_page_single_active_nav_item(client: TestClient) -> None:
|
||
"""На странице модуля ровно один пункт с aria-current (текущий раздел)."""
|
||
for slug in (
|
||
"grafana-catalog",
|
||
"incidents",
|
||
"tasks",
|
||
"escalations",
|
||
"schedules",
|
||
"contacts",
|
||
"statusboard",
|
||
):
|
||
r = client.get(f"/ui/modules/{slug}/")
|
||
assert r.status_code == 200
|
||
assert r.text.count('aria-current="page"') == 1
|
||
|
||
|
||
def test_root_survives_broken_module_fragment(client: TestClient) -> None:
|
||
"""MODULE_MOUNTS держит ссылки на функции при импорте — ломаем фрагмент через обёртку safe_fragment."""
|
||
|
||
async def bad_fragment(_request):
|
||
raise RuntimeError("simulated module bug")
|
||
|
||
async def patched_safe_fragment(slug, fn, request):
|
||
from onguard24.modules import ui_support as us
|
||
|
||
if slug == "schedules":
|
||
return await us.safe_fragment(slug, bad_fragment, request)
|
||
return await us.safe_fragment(slug, fn, request)
|
||
|
||
with patch("onguard24.root_html.safe_fragment", new=patched_safe_fragment):
|
||
r = client.get("/")
|
||
assert r.status_code == 200
|
||
assert "module-err" in r.text
|
||
assert "schedules" in r.text
|