Files
zyt/app/tests/test_prescription_list_prompts.py
T
2026-09-07 10:07:47 +08:00

198 lines
6.7 KiB
Python

from __future__ import annotations
import os
from types import SimpleNamespace
from typing import Any
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
import pytest
from PySide6.QtCore import Qt
from PySide6.QtGui import QImage
from PySide6.QtWidgets import QApplication, QStyleOptionViewItem
from doctor_workstation.ui.pages import prescriptions as prescriptions_module
from doctor_workstation.ui.pages.prescriptions import PrescriptionsPage, _order_warnings
@pytest.fixture(scope="module")
def application() -> QApplication:
return QApplication.instance() or QApplication([])
@pytest.fixture(autouse=True)
def immediate_async(monkeypatch: pytest.MonkeyPatch) -> None:
def run_immediately(
function: Any,
*args: Any,
on_success: Any = None,
on_error: Any = None,
on_finished: Any = None,
**kwargs: Any,
) -> object:
try:
result = function(*args, **kwargs)
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()
return object()
monkeypatch.setattr(prescriptions_module, "run_async", run_immediately)
def row(
record_id: int,
number: str,
*,
has_order: Any,
herbs: Any,
) -> dict[str, Any]:
return {
"id": record_id,
"sn": number,
"patient_name": "列表提示测试患者",
"gender": 1,
"age": 45,
"prescription_type": "浓缩水丸",
"is_system_auto": 1,
"audit_status": 0,
"void_status": 0,
"has_prescription_order": has_order,
"herbs": herbs,
"doctor_name": "测试医生",
"assistant_name": "测试医助",
"create_time": "2026-09-01 09:30:00",
}
class Repository:
def __init__(self, rows: list[dict[str, Any]]) -> None:
self.rows = rows
def list_diagnosis_doctors(self) -> list[Any]:
return []
def list_prescriptions(self, **_filters: Any) -> dict[str, Any]:
return {"lists": self.rows, "count": len(self.rows)}
def test_order_warnings_exactly_match_pc_rules() -> None:
assert _order_warnings(row(1, "RX-1", has_order=0, herbs=[])) == []
assert _order_warnings(row(2, "RX-2", has_order=1, herbs=[])) == ["请开方,当前处方药材为空白"]
assert _order_warnings(
row(3, "RX-3", has_order="1.0", herbs=[{}, {"name": ""}, {"name": " "}])
) == ["请开方,当前处方药材为空白"]
assert _order_warnings(
row(
4,
"RX-4",
has_order=1,
herbs=[{"name": "黄芪"}, {"name": " 黄 芪 "}, {"name": "党参"}],
)
) == ["已有关联业务订单,当前处方存在重复药材:黄 芪"]
# The PC implementation only reads the canonical `name` field.
assert _order_warnings(row(5, "RX-5", has_order=1, herbs=[{"medicine_name": "黄芪"}])) == [
"请开方,当前处方药材为空白"
]
def test_number_column_renders_sn_id_and_visible_warning_with_dynamic_height(
application: QApplication,
) -> None:
rows = [
row(11, "RX-NORMAL", has_order=0, herbs=[]),
row(22, "RX-BLANK", has_order=1, herbs=[{"name": ""}]),
row(
33,
"RX-DUPLICATE",
has_order=1,
herbs=[{"name": "黄芪"}, {"name": "黄 芪"}],
),
]
page = PrescriptionsPage(Repository(rows), {"*"}, SimpleNamespace(id=7, name="测试医生"))
page.resize(1366, 768)
page.show()
page.refresh()
for _ in range(6):
application.processEvents()
rendered: dict[int, tuple[int, str, str]] = {}
for visual_row in range(page.table.rowCount()):
item = page.table.item(visual_row, 1)
source = item.data(Qt.ItemDataRole.UserRole)
rendered[source["id"]] = (
page.table.rowHeight(visual_row),
item.toolTip(),
item.data(Qt.ItemDataRole.AccessibleTextRole),
)
normal_height, normal_tip, normal_accessible = rendered[11]
blank_height, blank_tip, blank_accessible = rendered[22]
duplicate_height, duplicate_tip, _duplicate_accessible = rendered[33]
assert normal_tip == normal_accessible == "RX-NORMAL\nID: 11"
assert "请开方,当前处方药材为空白" in blank_tip == blank_accessible
assert "已有关联业务订单,当前处方存在重复药材:黄 芪" in duplicate_tip
assert blank_height > normal_height
assert duplicate_height > normal_height
assert page.table.columnWidth(1) == 192
image = page.table.viewport().grab().toImage().convertToFormat(QImage.Format.Format_RGB32)
red_pixels = 0
for y in range(image.height()):
for x in range(image.width()):
color = image.pixelColor(x, y)
if color.red() > 170 and color.green() < 90 and color.blue() < 100:
red_pixels += 1
assert red_pixels > 40
page.close()
application.processEvents()
def test_number_warning_survives_sort_and_column_resize(application: QApplication) -> None:
rows = [
row(41, "RX-Z", has_order=1, herbs=[]),
row(42, "RX-A", has_order=0, herbs=[{"name": "黄芪"}]),
]
page = PrescriptionsPage(Repository(rows), {"*"}, SimpleNamespace(id=7, name="测试医生"))
page.resize(1200, 700)
page.show()
page.refresh()
page.table.sortItems(1, Qt.SortOrder.AscendingOrder)
page.table.setColumnWidth(1, 190)
for _ in range(5):
application.processEvents()
assert page.table.item(0, 1).text() == "RX-A"
assert page.table.item(1, 1).text() == "RX-Z"
assert page.table.item(1, 1).data(Qt.ItemDataRole.UserRole)["id"] == 41
assert "请开方,当前处方药材为空白" in page.table.item(1, 1).toolTip()
assert page.table.rowHeight(1) > page.table.rowHeight(0)
page.close()
application.processEvents()
def test_number_html_is_escaped_but_remains_readable(application: QApplication) -> None:
unsafe_number = "RX-<b>NOT HTML</b>"
page = PrescriptionsPage(
Repository([row(51, unsafe_number, has_order=1, herbs=[])]),
{"*"},
SimpleNamespace(id=7, name="测试医生"),
)
page.refresh()
delegate = page.table.itemDelegateForColumn(1)
option = QStyleOptionViewItem()
option.initFrom(page.table)
index = page.table.model().index(0, 1)
plain_text = delegate.document(option, index, page.table.columnWidth(1)).toPlainText()
assert unsafe_number in plain_text
assert "ID: 51" in plain_text
assert "请开方,当前处方药材为空白" in plain_text
page.close()
application.processEvents()