This commit is contained in:
Your Name
2026-09-07 12:30:42 +08:00
parent d5164b7369
commit 9ef6eb8d67
369 changed files with 11733 additions and 0 deletions
+198
View File
@@ -0,0 +1,198 @@
"""Native Qt coverage for presentation-only filter folding on both queues."""
from __future__ import annotations
import json
import os
from datetime import date
from pathlib import Path
from typing import Any
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
import pytest
from PySide6.QtCore import QPoint, QRect, Qt, Signal
from PySide6.QtTest import QTest
from PySide6.QtWidgets import QApplication, QPushButton, QWidget
from doctor_workstation.ui import shell as shell_module
from doctor_workstation.ui.pages import appointments, consultations
from doctor_workstation.ui.shell import NavigationItem, ShellWindow
from doctor_workstation.ui.theme import apply_theme
class _Dialog(QWidget):
saved = Signal()
def __init__(self, _repository: Any, parent: QWidget | None = None) -> None:
super().__init__(parent)
class _Repository:
def __init__(self) -> None:
self.calls: list[dict[str, Any]] = []
def _list(self, **query: Any) -> dict[str, Any]:
self.calls.append(query)
rows = [{
"id": index, "diagnosis_id": index, "patient_id": index + 2000,
"source_patient_id": index + 2000, "patient_name": f"演示患者{index:02d}",
"patient_phone": "13800001234", "gender": 2, "age": 38,
"status": 1, "status_desc": "待接诊", "doctor_name": "演示医生",
"doctor_id": 30, "assistant_name": "演示医助", "has_appointment": True,
"appointment_id": index + 1000, "appointment_status": 1,
"appointment_date": date.today().isoformat(), "appointment_time": "09:00-09:30",
"diagnosis_confirmed": True, "has_prescription": False,
"appointments": [{"id": index + 1000, "status": 1,
"doctor_name": "演示医生", "time_text": "09:00-09:30"}],
} for index in range(1, 16)]
return {"lists": rows, "count": 15, "extend": {"status_count": {"1": 15}}}
list_appointments = _list
list_consultations = _list
def _inline(function: Any, *, on_success=None, on_error=None, on_finished=None) -> None:
try:
result = function()
except Exception as error:
if on_error is not None:
on_error(error)
else:
if on_success is not None:
on_success(result)
finally:
if on_finished is not None:
on_finished()
def _settle(application: QApplication) -> None:
for _ in range(4):
application.processEvents()
QTest.qWait(10)
@pytest.fixture(scope="module")
def application() -> QApplication:
app = QApplication.instance() or QApplication([])
apply_theme(app)
return app
@pytest.fixture
def list_window(application: QApplication, monkeypatch: pytest.MonkeyPatch):
monkeypatch.setattr(appointments, "run_async", _inline)
monkeypatch.setattr(consultations, "run_async", _inline)
monkeypatch.setattr(consultations, "DiagnosisDialog", _Dialog)
monkeypatch.setattr(consultations.ConsultationsPage, "_load_filter_options", lambda self: None)
monkeypatch.setattr(consultations.ConsultationsPage, "_refresh_counts", lambda self: None)
monkeypatch.setattr(appointments.AppointmentsPage, "_load_departments", lambda self: None)
monkeypatch.setattr(shell_module.motion, "reduced_motion", lambda: True)
navigation = [
NavigationItem("appointments", "挂号列表", "", appointments.AppointmentsPage,
("doctor.appointment/lists",)),
NavigationItem("consultations", "问诊列表", "", consultations.ConsultationsPage,
("tcm.diagnosis/lists",)),
]
monkeypatch.setattr(shell_module, "_resolve_navigation",
lambda *_args, **_kwargs: [(item, item.title) for item in navigation])
repository = _Repository()
window = ShellWindow(repository, {"user": {"name": "演示医生", "role_id": 1},
"demo_mode": True}, permissions={"*"})
yield window, repository
window.close()
window.deleteLater()
_settle(application)
@pytest.mark.parametrize("kind", ["appointments", "consultations"])
@pytest.mark.parametrize(("width", "height"), [(1366, 768), (1536, 960)])
def test_folding_reclaims_rows_and_retains_query_refresh_and_navigation_state(
application: QApplication, list_window: Any, kind: str, width: int, height: int,
) -> None:
window, repository = list_window
window.resize(width, height)
window.show()
assert window.navigate(kind)
_settle(application)
page = window.pages[kind]
page.poll_timer.stop()
panel = page.filter_panel if kind == "appointments" else page.filters_card
header = page.header if kind == "appointments" else page.page_header
search = page.patient_input if kind == "appointments" else page.patient_name_edit
nested = page.more_filters_button if kind == "appointments" else page.more_filter_button
action = page.toolbar_edit_button if kind == "appointments" else page.add_button
disclosure = page.filter_disclosure
filters = page._query_filters if kind == "appointments" else page._filters
assert not disclosure.expanded
assert panel.isHidden() and not search.isVisible()
assert header.height() <= 44
assert not header.subtitle_label.isVisible()
assert disclosure.button.isVisible() and action.isVisible()
assert 30 <= disclosure.button.height() <= 34
assert window.refresh_button.isVisible()
assert any(button.isVisible() and button.text() == "刷新"
for button in page.findChildren(QPushButton))
collapsed_height = page.table.viewport().height()
capture_dir = os.environ.get("COLLAPSIBLE_LIST_SCREENSHOTS")
if capture_dir:
Path(capture_dir).mkdir(parents=True, exist_ok=True)
assert window.grab().save(str(Path(capture_dir) / f"{kind}-{width}-collapsed.png"))
calls_before = len(repository.calls)
QTest.mouseClick(disclosure.button, Qt.MouseButton.LeftButton)
_settle(application)
assert len(repository.calls) == calls_before
assert panel.isVisible() and search.isVisible()
assert collapsed_height >= page.table.viewport().height() + 100
assert panel.rect().contains(QRect(search.mapTo(panel, QPoint()), search.size()))
assert search.parentWidget().rect().contains(search.geometry())
assert not page.advanced_filters.isVisible()
if capture_dir:
assert window.grab().save(str(Path(capture_dir) / f"{kind}-{width}-expanded.png"))
(Path(capture_dir) / f"{kind}-{width}-metrics.json").write_text(
json.dumps({"window": [width, height], "header_height": header.height(),
"toggle_height": disclosure.button.height(),
"collapsed_viewport_height": collapsed_height,
"expanded_viewport_height": page.table.viewport().height(),
"viewport_gain": collapsed_height - page.table.viewport().height()},
indent=2), encoding="utf-8",
)
search.setText("演示患者")
query_button = (page.findChild(QPushButton, "AppointmentSearchButton")
if kind == "appointments" else page.search_button)
QTest.mouseClick(query_button, Qt.MouseButton.LeftButton)
_settle(application)
assert len(repository.calls) > calls_before
assert repository.calls[-1]["patient_name"] == "演示患者"
QTest.mouseClick(nested, Qt.MouseButton.LeftButton)
_settle(application)
assert page.advanced_filters.isVisible()
query = dict(filters())
calls_before = len(repository.calls)
QTest.mouseClick(disclosure.button, Qt.MouseButton.LeftButton)
_settle(application)
assert len(repository.calls) == calls_before
assert filters() == query
assert search.text() == "演示患者"
assert panel.isHidden()
assert page.table.viewport().height() == collapsed_height
window.resize(width - 50, height - 20)
window.refresh_button.click()
_settle(application)
assert not disclosure.expanded and panel.isHidden()
assert filters() == query
other = "consultations" if kind == "appointments" else "appointments"
assert window.navigate(other)
assert window.navigate(kind)
_settle(application)
assert not disclosure.expanded and panel.isHidden()
QTest.mouseClick(disclosure.button, Qt.MouseButton.LeftButton)
_settle(application)
assert page.advanced_filters.isVisible() and nested.isChecked()
window.refresh_button.click()
_settle(application)
assert disclosure.expanded and panel.isVisible()
assert filters() == query