This commit is contained in:
Your Name
2026-08-13 14:22:19 +08:00
parent 72a5300b08
commit cbe71905c0
16 changed files with 347 additions and 375 deletions
+41 -1
View File
@@ -7,10 +7,12 @@ from typing import Any
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
import pytest
from PySide6.QtCore import QSettings
from PySide6.QtCore import QEvent, QObject, QSettings
from PySide6.QtWidgets import QApplication, QWidget
from doctor_workstation.services import DemoDoctorRepository
from doctor_workstation.ui.login import LoginWindow
from doctor_workstation.ui.shell import ShellWindow
from doctor_workstation.ui.widgets import BusyOverlay
@@ -87,3 +89,41 @@ def test_login_loading_does_not_spawn_extra_windows(
window.close()
application.processEvents()
def test_shell_construction_never_shows_orphan_business_controls(
application: QApplication,
) -> None:
shown: list[tuple[str, str]] = []
class OrphanShowRecorder(QObject):
def eventFilter(self, watched: QObject, event: QEvent) -> bool: # noqa: N802
if (
event.type() == QEvent.Type.Show
and isinstance(watched, QWidget)
and watched.parentWidget() is None
):
text = getattr(watched, "text", lambda: "")()
shown.append((type(watched).__name__, str(text)))
return False
repository = DemoDoctorRepository()
session = repository.login(repository.DEMO_ACCOUNT, repository.DEMO_PASSWORD)
recorder = OrphanShowRecorder(application)
application.installEventFilter(recorder)
try:
shell = ShellWindow(
repository,
{
"session": session,
"user": session.user,
"demo_mode": True,
},
permissions=session.permissions,
)
finally:
application.removeEventFilter(recorder)
assert shown == []
shell.close()
application.processEvents()
+148 -2
View File
@@ -7,10 +7,10 @@ from typing import Any
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
import pytest
from PySide6.QtCore import QSize, Qt
from PySide6.QtCore import QEvent, QObject, QSize, Qt
from PySide6.QtGui import QColor, QImage, QPainter
from PySide6.QtPdf import QPdfDocument
from PySide6.QtWidgets import QApplication
from PySide6.QtWidgets import QApplication, QDialog, QWidget
from doctor_workstation import app as app_module
from doctor_workstation.core import PermissionSet
@@ -354,6 +354,85 @@ def test_editor_builds_complete_add_payload(
application.processEvents()
def test_prescription_workflows_never_show_orphan_child_controls(
application: QApplication,
immediate_async: None,
) -> None:
shown: list[tuple[str, str]] = []
class OrphanShowRecorder(QObject):
def eventFilter(self, watched: QObject, event: QEvent) -> bool: # noqa: N802
if (
event.type() == QEvent.Type.Show
and isinstance(watched, QWidget)
and not isinstance(watched, QDialog)
and watched.parentWidget() is None
):
text = getattr(watched, "text", lambda: "")()
shown.append((type(watched).__name__, str(text)))
return False
repository = SimpleNamespace(
list_medicines=lambda **_kwargs: {
"lists": [{"id": 31, "name": "黄芪"}],
"count": 1,
}
)
prescription = {
"id": 12,
"diagnosis_id": 6,
"patient_name": "林晓岚",
"phone": "13800000000",
"audit_status": 1,
"herbs": [{"medicine_id": 31, "name": "黄芪", "dosage": 15}],
}
recorder = OrphanShowRecorder(application)
application.installEventFilter(recorder)
widgets: list[QWidget] = []
try:
widgets.extend(
[
dialog_module.HerbRowWidget(
repository,
prescription["herbs"][0],
show_formula=True,
locked=False,
),
dialog_module.HerbEditor(
repository,
show_formula=True,
show_actions=True,
),
PrescriptionEditorDialog(
repository,
prescription,
mode="edit",
permissions=PermissionSet(
["cf.prescription/edit", "tcm.prescriptionLibrary/lists"]
),
),
PrescriptionDetailDialog(
prescription,
can_open_diagnosis=True,
can_open_orders=True,
),
PrescriptionOrderDialog(
repository,
prescription,
can_view_internal_cost=True,
can_edit_pharmacy_remark=True,
),
]
)
finally:
application.removeEventFilter(recorder)
assert shown == []
for widget in widgets:
widget.close()
application.processEvents()
def test_editor_matches_admin_four_observation_fields_and_edit_context(
application: QApplication,
immediate_async: None,
@@ -667,6 +746,73 @@ def test_prescription_detail_can_open_immutable_case_record_tab(
application.processEvents()
def test_case_record_tab_exports_case_record_as_a3_pdf(
application: QApplication,
tmp_path: Any,
monkeypatch: pytest.MonkeyPatch,
) -> None:
prescription = {
"id": 12,
"diagnosis_id": 8169,
"patient_name": "何福萍",
"case_record": {
"diagnosis_id": 8169,
"patient_name": "何福萍",
"phone": "13800138000",
"diagnosis_type": "follow_up",
"local_hospital_name": "市中医院",
"symptoms": "口渴、乏力、睡眠欠佳",
"tongue_coating": "舌红少苔",
"pulse": "脉细数",
"doctor_advice": "规律复诊",
},
}
case_render_calls: list[str] = []
original_case_renderer = dialog_module.render_case_record_image
def render_case(*args: Any, **kwargs: Any) -> QImage:
case_render_calls.append("case")
return original_case_renderer(*args, **kwargs)
def reject_prescription_render(*_args: Any, **_kwargs: Any) -> QImage:
pytest.fail("详细病历页签不应调用处方笺渲染器")
monkeypatch.setattr(dialog_module, "render_case_record_image", render_case)
monkeypatch.setattr(
dialog_module,
"render_prescription_slip_image",
reject_prescription_render,
)
app_module._install_chinese_translations(application)
viewer = PrescriptionDetailDialog(prescription)
case_index = next(
index for index in range(viewer.tabs.count()) if viewer.tabs.tabText(index) == "详细病历"
)
viewer.tabs.setCurrentIndex(case_index)
output = tmp_path / "case-record.pdf"
viewer.export_pdf(output)
pdf = QPdfDocument()
assert pdf.load(str(output)) == QPdfDocument.Error.None_
assert pdf.pageCount() == 1
page_size = pdf.pagePointSize(0)
rendered_page = pdf.render(0, QSize(1400, 1980))
visible_ink = sum(
1
for y in range(0, rendered_page.height(), 4)
for x in range(0, rendered_page.width(), 4)
if (color := rendered_page.pixelColor(x, y)).alpha() > 0 and color.lightness() < 245
)
viewer.close()
application.processEvents()
assert case_render_calls == ["case"]
assert page_size.width() == pytest.approx(842.0, abs=2.0)
assert page_size.height() == pytest.approx(1191.0, abs=2.0)
assert visible_ink > 1_000
def test_demo_repository_pages_render_offscreen(
application: QApplication,
immediate_async: None,