更新
This commit is contained in:
@@ -9,7 +9,7 @@ os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
|
||||
|
||||
import pytest
|
||||
from PySide6.QtCore import QPoint, Qt
|
||||
from PySide6.QtGui import QImage
|
||||
from PySide6.QtGui import QImage, QTextCursor
|
||||
from PySide6.QtWidgets import (
|
||||
QApplication,
|
||||
QDialog,
|
||||
@@ -29,6 +29,7 @@ from doctor_workstation.ui.diagnosis_drawer import (
|
||||
DiagnosisLineEdit,
|
||||
DiagnosisNumberEdit,
|
||||
DiagnosisSwitch,
|
||||
ExpandableDiagnosisTextEdit,
|
||||
SaveStateButton,
|
||||
)
|
||||
from doctor_workstation.ui.dialogs import diagnosis as diagnosis_module
|
||||
@@ -751,6 +752,186 @@ def test_semantic_form_controls_keep_desktop_grid_and_canonical_diagnosis_type(
|
||||
dialog.close()
|
||||
|
||||
|
||||
def _settle_text_layout(application: QApplication) -> None:
|
||||
# Editor measurement and the containing scroll area's layout are deferred.
|
||||
for _ in range(12):
|
||||
application.processEvents()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("key", ["symptoms", "current_medications"])
|
||||
@pytest.mark.parametrize("size", [(1024, 640), (1440, 900)])
|
||||
@pytest.mark.parametrize(
|
||||
"text",
|
||||
[
|
||||
"这是一段用于验证自动换行的测试记录。" * 40,
|
||||
"\n".join(f"第{index + 1}条:测试记录,保留原始换行。" for index in range(18)),
|
||||
"LongUnbrokenTestValue" * 80,
|
||||
],
|
||||
ids=["wrapped-chinese", "multiline", "unbroken-text"],
|
||||
)
|
||||
def test_long_diagnosis_fields_expand_inline_without_inner_scrolling(
|
||||
application: QApplication, key: str, size: tuple[int, int], text: str
|
||||
) -> None:
|
||||
repository = VisualRepository()
|
||||
repository.detail["diagnosis"][key] = text
|
||||
dialog = _open_dialog(application, size, mode="edit", repository=repository)
|
||||
try:
|
||||
_settle_text_layout(application)
|
||||
editor = dialog.edit_fields[key]
|
||||
assert isinstance(editor, ExpandableDiagnosisTextEdit)
|
||||
assert editor.height() == 72
|
||||
assert editor.expand_button.isVisibleTo(dialog)
|
||||
assert not editor.expand_button.autoDefault()
|
||||
assert editor.expand_button.text() == "展开全部"
|
||||
body = dialog.findChild(QScrollArea, "DiagnosisDrawerBody")
|
||||
footer = dialog.findChild(QFrame, "DiagnosisDrawerFooter")
|
||||
footer_before = footer.geometry()
|
||||
outer_range_before = body.verticalScrollBar().maximum()
|
||||
horizontal_range_before = body.horizontalScrollBar().maximum()
|
||||
editor.verticalScrollBar().setValue(editor.verticalScrollBar().maximum())
|
||||
|
||||
editor.expand_button.click()
|
||||
_settle_text_layout(application)
|
||||
assert editor.expand_button.text() == "收起"
|
||||
assert editor.height() > 72
|
||||
assert editor.sizeHint().height() == editor.height()
|
||||
assert not editor._height_sync.isActive()
|
||||
assert editor.verticalScrollBar().maximum() == 0
|
||||
assert editor.horizontalScrollBar().maximum() == 0
|
||||
assert not editor.verticalScrollBar().isVisibleTo(dialog)
|
||||
last_block = editor.blockBoundingGeometry(editor.document().lastBlock())
|
||||
assert last_block.translated(editor.contentOffset()).bottom() <= editor.viewport().height()
|
||||
assert body.verticalScrollBar().maximum() > outer_range_before
|
||||
# The existing narrow form has a small minimum-width overflow; expanding
|
||||
# these fields must not increase it or clip their right edge.
|
||||
assert body.horizontalScrollBar().maximum() == horizontal_range_before
|
||||
assert editor.mapTo(body.viewport(), QPoint(editor.width(), 0)).x() <= body.viewport().width()
|
||||
assert footer.geometry() == footer_before
|
||||
assert editor.toPlainText() == text
|
||||
assert not repository.updates
|
||||
|
||||
editor.expand_button.click()
|
||||
_settle_text_layout(application)
|
||||
assert editor.height() == 72
|
||||
assert editor.toPlainText() == text
|
||||
assert editor.expand_button.text() == "展开全部"
|
||||
assert not editor._height_sync.isActive()
|
||||
finally:
|
||||
dialog.close()
|
||||
_settle_text_layout(application)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("key", ["symptoms", "current_medications"])
|
||||
def test_expanded_diagnosis_text_reflows_on_resize_and_keeps_edit_save_contract(
|
||||
application: QApplication, key: str
|
||||
) -> None:
|
||||
repository = VisualRepository()
|
||||
original = "自动换行测试内容,保持完整文本。" * 30
|
||||
repository.detail["diagnosis"][key] = original
|
||||
dialog = _open_dialog(application, (1440, 900), mode="edit", repository=repository)
|
||||
try:
|
||||
_settle_text_layout(application)
|
||||
editor = dialog.edit_fields[key]
|
||||
editor.expand_button.click()
|
||||
_settle_text_layout(application)
|
||||
wide_height = editor.height()
|
||||
dialog.resize(1024, 640)
|
||||
_settle_text_layout(application)
|
||||
assert editor.height() > wide_height
|
||||
assert editor.verticalScrollBar().maximum() == 0
|
||||
dialog.resize(1440, 900)
|
||||
_settle_text_layout(application)
|
||||
assert editor.height() == wide_height
|
||||
|
||||
editor.moveCursor(QTextCursor.MoveOperation.End)
|
||||
added = "\n新增测试记录,保存时不能截断。" * 12
|
||||
editor.insertPlainText(added)
|
||||
_settle_text_layout(application)
|
||||
assert editor.height() > wide_height
|
||||
assert editor.verticalScrollBar().maximum() == 0
|
||||
cursor_position = editor.textCursor().position()
|
||||
editor.expand_button.click()
|
||||
editor.expand_button.click()
|
||||
_settle_text_layout(application)
|
||||
assert editor.textCursor().position() == cursor_position
|
||||
editor.undo()
|
||||
_settle_text_layout(application)
|
||||
assert editor.toPlainText() == original
|
||||
assert editor.height() == wide_height
|
||||
editor.redo()
|
||||
editor.expand_button.click()
|
||||
_settle_text_layout(application)
|
||||
dialog._save()
|
||||
assert repository.updates[-1][key] == original + added
|
||||
finally:
|
||||
dialog.close()
|
||||
_settle_text_layout(application)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("key", ["symptoms", "current_medications"])
|
||||
def test_short_and_cleared_diagnosis_text_keep_compact_layout(
|
||||
application: QApplication, key: str
|
||||
) -> None:
|
||||
dialog = _open_dialog(application, (1024, 640), mode="edit")
|
||||
try:
|
||||
editor = dialog.edit_fields[key]
|
||||
for text in ("", "简短测试记录"):
|
||||
editor.setPlainText(text)
|
||||
_settle_text_layout(application)
|
||||
assert editor.height() == 72
|
||||
assert not editor.expand_button.isVisibleTo(dialog)
|
||||
editor.insertPlainText("\n很长的测试记录" * 20)
|
||||
_settle_text_layout(application)
|
||||
assert editor.expand_button.isVisibleTo(dialog)
|
||||
editor.expand_button.click()
|
||||
_settle_text_layout(application)
|
||||
editor.selectAll()
|
||||
editor.insertPlainText("")
|
||||
_settle_text_layout(application)
|
||||
assert editor.toPlainText() == ""
|
||||
assert editor.height() == 72
|
||||
assert editor.expand_button.text() == "收起"
|
||||
editor.expand_button.click()
|
||||
_settle_text_layout(application)
|
||||
assert not editor.expand_button.isVisibleTo(dialog)
|
||||
assert not isinstance(dialog.edit_fields["remark"], ExpandableDiagnosisTextEdit)
|
||||
assert not isinstance(dialog.edit_fields["present_illness"], ExpandableDiagnosisTextEdit)
|
||||
finally:
|
||||
dialog.close()
|
||||
_settle_text_layout(application)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("key", ["symptoms", "current_medications"])
|
||||
def test_readonly_diagnosis_text_can_expand_and_reopen_starts_collapsed(
|
||||
application: QApplication, key: str
|
||||
) -> None:
|
||||
repository = VisualRepository()
|
||||
text = "只读长文本测试\n" * 20
|
||||
repository.detail["diagnosis"][key] = text
|
||||
dialog = _open_dialog(application, (1024, 640), mode="viewOnly", repository=repository)
|
||||
try:
|
||||
_settle_text_layout(application)
|
||||
editor = dialog.edit_fields[key]
|
||||
assert editor.isReadOnly()
|
||||
assert editor.expand_button.isEnabled()
|
||||
editor.expand_button.click()
|
||||
_settle_text_layout(application)
|
||||
assert editor.height() > 72
|
||||
assert editor.verticalScrollBar().maximum() == 0
|
||||
assert editor.isReadOnly()
|
||||
assert not dialog.save_button.isVisibleTo(dialog)
|
||||
assert not repository.updates
|
||||
dialog.close()
|
||||
dialog.open_view_only(501)
|
||||
_settle_text_layout(application)
|
||||
assert editor.height() == 72
|
||||
assert not editor.expand_button.isChecked()
|
||||
assert editor.toPlainText() == text
|
||||
finally:
|
||||
dialog.close()
|
||||
_settle_text_layout(application)
|
||||
|
||||
|
||||
def test_hpi_choice_chips_are_visible_after_dictionary_load(
|
||||
application: QApplication,
|
||||
) -> None:
|
||||
|
||||
@@ -1436,6 +1436,102 @@ def test_im_consult_is_visible_immediately_after_history(
|
||||
application.processEvents()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("width", [1280, 1494])
|
||||
@pytest.mark.parametrize("permissions", [[], ["*"]])
|
||||
def test_notify_assistant_is_a_visible_header_action_not_a_more_menu_item(
|
||||
application: QApplication,
|
||||
queued_async: list[dict[str, Any]],
|
||||
width: int,
|
||||
permissions: list[str],
|
||||
) -> None:
|
||||
page = ReceptionPage(DemoDoctorRepository(), PermissionSet(permissions))
|
||||
page.resize(width, 760)
|
||||
page.show()
|
||||
try:
|
||||
application.processEvents()
|
||||
# The first show initiates a queue reload and clears the selection.
|
||||
# Present a synthetic selected patient after that initial reset.
|
||||
page.patient_name_label.setText("测试患者")
|
||||
page.patient_meta_label.setText("女 · 42岁 · 138****8000 | 就诊号:31")
|
||||
page.detail_stack.setCurrentIndex(1)
|
||||
for _ in range(4):
|
||||
application.processEvents()
|
||||
hero = page.notify_button.parentWidget()
|
||||
assert hero.objectName() == "ReceptionHero"
|
||||
assert page.notify_button.isVisibleTo(page)
|
||||
assert page.notify_button.text() == "通知医助"
|
||||
assert page.notify_button.width() >= page.notify_button.sizeHint().width()
|
||||
assert page.notify_button.height() > 0
|
||||
assert "通知医助" not in [action.text() for action in page.more_button.menu().actions()]
|
||||
buttons = [
|
||||
button
|
||||
for button in (
|
||||
page.complete_button,
|
||||
page.notify_button,
|
||||
page.history_button,
|
||||
page.video_button,
|
||||
page.more_button,
|
||||
)
|
||||
if button.isVisibleTo(page)
|
||||
]
|
||||
for button in buttons:
|
||||
assert hero.rect().contains(button.geometry())
|
||||
assert button.width() >= button.sizeHint().width()
|
||||
right = button.mapTo(page.detail_scroll.viewport(), QPoint(button.width(), 0)).x()
|
||||
assert right <= page.detail_scroll.viewport().width()
|
||||
for previous, following in zip(buttons, buttons[1:], strict=False):
|
||||
assert previous.geometry().right() < following.geometry().left()
|
||||
finally:
|
||||
page.close()
|
||||
application.processEvents()
|
||||
|
||||
|
||||
def test_notify_header_button_keeps_appointment_context_and_pending_state(
|
||||
application: QApplication,
|
||||
queued_async: list[dict[str, Any]],
|
||||
) -> None:
|
||||
sent: list[int] = []
|
||||
|
||||
class Repository:
|
||||
def notify_assistant(self, appointment_id: int) -> dict[str, bool]:
|
||||
sent.append(appointment_id)
|
||||
return {"success": True}
|
||||
|
||||
page = ReceptionPage(Repository(), PermissionSet([]))
|
||||
try:
|
||||
page._update_action_state({}, {})
|
||||
assert not page.notify_button.isEnabled()
|
||||
page._selected_appointment_id = 31
|
||||
page._selected_record = {"id": 31, "status": 1}
|
||||
page._update_action_state(page._selected_record, {})
|
||||
assert page.notify_button.isEnabled()
|
||||
queued_async.clear()
|
||||
page.notify_button.click()
|
||||
assert not page.notify_button.isEnabled()
|
||||
page.notify_button.click()
|
||||
assert len(queued_async) == 1
|
||||
notification = queued_async.pop()
|
||||
notification["function"]()
|
||||
assert sent == [31]
|
||||
notification["on_finished"]()
|
||||
assert page.notify_button.isEnabled()
|
||||
|
||||
page.notify_button.click()
|
||||
notification = queued_async.pop()
|
||||
page._selected_appointment_id = 32
|
||||
page._selected_record = {"id": 32, "status": 1}
|
||||
page._detail_generation += 1
|
||||
# An old request still targets its original appointment and cannot
|
||||
# re-enable a pending notification for a newly selected patient.
|
||||
notification["function"]()
|
||||
notification["on_finished"]()
|
||||
assert sent == [31, 31]
|
||||
assert not page.notify_button.isEnabled()
|
||||
finally:
|
||||
page.close()
|
||||
application.processEvents()
|
||||
|
||||
|
||||
def test_reception_ai_report_button_follows_permission(
|
||||
application: QApplication,
|
||||
immediate_async: None,
|
||||
|
||||
Reference in New Issue
Block a user