feat(dashboard): replace home with approved minimal design
CI / ruff · pytest (pull_request) Successful in 2m1s
CI / ruff · pytest (pull_request) Successful in 2m1s
Refs #73
This commit is contained in:
@@ -23,12 +23,13 @@ class FakeApi:
|
||||
def __init__(self) -> None:
|
||||
self.calls: list[tuple[str, str]] = []
|
||||
self.extra_alerts: list = []
|
||||
self.patients = list(fixtures.PATIENTS)
|
||||
|
||||
def __call__(self, req: httpx.Request) -> httpx.Response:
|
||||
path = req.url.path.removeprefix("/api/v1")
|
||||
self.calls.append((req.method, path))
|
||||
if path == "/doctors/doc-smirnova/patients":
|
||||
return httpx.Response(200, json=_dump(fixtures.PATIENTS))
|
||||
return httpx.Response(200, json=_dump(self.patients))
|
||||
if path.startswith("/patients/tok-"):
|
||||
card = fixtures.card(path.rsplit("/", 1)[1])
|
||||
return httpx.Response(200, json=_dump(card)) if card else httpx.Response(404)
|
||||
@@ -64,6 +65,7 @@ def test_list_page_renders_sorted_patients(api):
|
||||
assert not at.exception
|
||||
html = _html(at)
|
||||
assert "Кабинет д-ра Смирновой Е. А." in html
|
||||
assert "Пациенты под наблюдением" in html
|
||||
assert html.index("Андрей С.") < html.index("Сергей П.") < html.index("Павел Р.")
|
||||
assert "Высокий · 70" in html # discontinuation-risk badge
|
||||
open_buttons = [b for b in at.button if b.label == "Открыть"]
|
||||
@@ -72,7 +74,9 @@ def test_list_page_renders_sorted_patients(api):
|
||||
|
||||
def test_list_filter_and_open_card(api):
|
||||
at = AppTest.from_file(LIST_PAGE, default_timeout=20).run()
|
||||
at.segmented_control(key="status_filter").set_value("🔴 Красные").run()
|
||||
at.segmented_control(key="status_filter").set_value("Срочно").run()
|
||||
at.text_input(key="patient_query").set_value("андр").run()
|
||||
at.toggle(key="patient_details").set_value(True).run()
|
||||
assert len([b for b in at.button if b.label == "Открыть"]) == 1
|
||||
at.button(key="open-tok-andrey").click().run()
|
||||
assert not at.exception
|
||||
@@ -81,6 +85,76 @@ def test_list_filter_and_open_card(api):
|
||||
assert "PHQ-9 п.9 = 2" in html and "План безопасности" in html
|
||||
assert "Решения принимает врач" in html
|
||||
assert ("GET", "/patients/tok-andrey") in api.calls
|
||||
next(b for b in at.button if b.label == "Все пациенты").click().run()
|
||||
assert not at.exception
|
||||
assert not at.query_params.get("patient")
|
||||
assert len([b for b in at.button if b.label == "Открыть"]) == 1 # the selected filter is retained
|
||||
assert at.text_input(key="patient_query").value == "андр"
|
||||
assert at.toggle(key="patient_details").value is True
|
||||
|
||||
|
||||
@pytest.mark.parametrize("choice,expected", [("Внимание", 4), ("Без уведомлений", 3), ("Все пациенты", 8)])
|
||||
def test_home_status_filters(api, choice, expected):
|
||||
at = AppTest.from_file(LIST_PAGE, default_timeout=20).run()
|
||||
at.segmented_control(key="status_filter").set_value(choice).run()
|
||||
assert not at.exception
|
||||
assert len([b for b in at.button if b.label == "Открыть"]) == expected
|
||||
assert f"Показано {expected} из 8 пациентов" in _html(at)
|
||||
|
||||
|
||||
def test_home_search_empty_result_and_reset(api):
|
||||
at = AppTest.from_file(LIST_PAGE, default_timeout=20).run()
|
||||
at.text_input(key="patient_query").set_value(" ПАРОКСЕТИН ").run()
|
||||
assert len([b for b in at.button if b.label == "Открыть"]) == 1
|
||||
assert "Сергей П." in _html(at)
|
||||
at.segmented_control(key="status_filter").set_value("Без уведомлений").run()
|
||||
assert "Пациенты не найдены" in _html(at)
|
||||
next(b for b in at.button if b.label == "Сбросить фильтры").click().run()
|
||||
assert not at.exception
|
||||
assert len([b for b in at.button if b.label == "Открыть"]) == 8
|
||||
assert at.text_input(key="patient_query").value == ""
|
||||
|
||||
|
||||
def test_home_empty_cabinet_keeps_connect_action(api):
|
||||
api.patients = []
|
||||
at = AppTest.from_file(LIST_PAGE, default_timeout=20).run()
|
||||
assert not at.exception
|
||||
assert "Пациентов пока нет" in _html(at)
|
||||
assert "Показано 0 из 0 пациентов" in _html(at)
|
||||
assert any(b.label == "Подключить пациента" for b in at.button)
|
||||
assert not any(b.label == "Открыть" for b in at.button)
|
||||
|
||||
|
||||
def test_home_details_preserve_clinical_information(api):
|
||||
at = AppTest.from_file(LIST_PAGE, default_timeout=20).run()
|
||||
assert "PHQ-9" in _html(at) and "PCL-5" in _html(at)
|
||||
at.toggle(key="patient_details").set_value(True).run()
|
||||
assert not at.exception
|
||||
html = _html(at)
|
||||
assert "сертралин 50 мг" in html
|
||||
assert "PHQ-9 п.9 = 2 — кризисный протокол" in html
|
||||
assert "пропуски 3 из 7" in html
|
||||
|
||||
|
||||
def test_home_info_only_patient_and_missing_scores(api):
|
||||
api.patients = [
|
||||
fixtures.PATIENTS[0].model_copy(
|
||||
update={
|
||||
"status_color": "grey",
|
||||
"top_alert_level": "info",
|
||||
"phq9_last": None,
|
||||
"pcl5_last": None,
|
||||
"adherence_7d": None,
|
||||
"open_alerts": 1,
|
||||
}
|
||||
)
|
||||
]
|
||||
at = AppTest.from_file(LIST_PAGE, default_timeout=20).run()
|
||||
at.segmented_control(key="status_filter").set_value("Нет ответа").run()
|
||||
assert not at.exception
|
||||
assert len([b for b in at.button if b.label == "Открыть"]) == 1
|
||||
assert "Из них только инфо: 1" in _html(at)
|
||||
assert 'mt-dim">—' in _html(at)
|
||||
|
||||
|
||||
def test_card_ack_posts_and_marks_alert(api):
|
||||
@@ -103,6 +177,8 @@ def test_api_down_shows_banner(monkeypatch):
|
||||
at = AppTest.from_file(LIST_PAGE, default_timeout=20).run()
|
||||
assert not at.exception
|
||||
assert "API недоступен" in _html(at)
|
||||
assert any(b.label == "Повторить загрузку" for b in at.button)
|
||||
assert "Всего пациентов" not in _html(at) # failed loading is not a zero-patient cabinet
|
||||
|
||||
|
||||
def test_connect_flow_shows_code(api):
|
||||
|
||||
Reference in New Issue
Block a user