157 lines
6.5 KiB
Python
157 lines
6.5 KiB
Python
from __future__ import annotations
|
|
|
|
import os
|
|
from typing import Any
|
|
|
|
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
|
|
|
|
import pytest
|
|
from PySide6.QtCore import QPoint, QTimer
|
|
from PySide6.QtWidgets import QApplication, QLabel, QPushButton
|
|
|
|
from doctor_workstation.services import DemoDoctorRepository
|
|
from doctor_workstation.ui import apply_theme
|
|
from doctor_workstation.ui.pages import (
|
|
appointments,
|
|
consultations,
|
|
patients,
|
|
prescription_library,
|
|
prescriptions,
|
|
)
|
|
from doctor_workstation.ui.widgets import PageHeader
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def application() -> QApplication:
|
|
app = QApplication.instance() or QApplication([])
|
|
apply_theme(app)
|
|
return app
|
|
|
|
|
|
@pytest.fixture
|
|
def page_factory(application: QApplication, monkeypatch: pytest.MonkeyPatch):
|
|
def immediate(function: Any, *args: Any, on_success=None, on_error=None,
|
|
on_finished=None, **kwargs: Any) -> object:
|
|
try:
|
|
result = function(*args, **kwargs)
|
|
except Exception as error:
|
|
if on_error:
|
|
on_error(error)
|
|
else:
|
|
if on_success:
|
|
on_success(result)
|
|
finally:
|
|
if on_finished:
|
|
on_finished()
|
|
return object()
|
|
|
|
modules = (appointments, consultations, patients, prescription_library, prescriptions)
|
|
for module in modules:
|
|
monkeypatch.setattr(module, "run_async", immediate)
|
|
opened = []
|
|
|
|
def create(kind: str, width: int = 1040):
|
|
repo = DemoDoctorRepository()
|
|
session = repo.login(repo.DEMO_ACCOUNT, repo.DEMO_PASSWORD)
|
|
classes = {
|
|
"appointments": appointments.AppointmentsPage,
|
|
"patients": patients.PatientsPage,
|
|
"consultations": consultations.ConsultationsPage,
|
|
"prescriptions": prescriptions.PrescriptionsPage,
|
|
"prescription_library": prescription_library.PrescriptionLibraryPage,
|
|
}
|
|
page = classes[kind](repo, permissions=session.permissions, current_user=session.user)
|
|
opened.append(page)
|
|
page.resize(width, 700)
|
|
page.show()
|
|
page.refresh()
|
|
for _ in range(4):
|
|
application.processEvents()
|
|
return page
|
|
|
|
yield create
|
|
for page in opened:
|
|
for timer in page.findChildren(QTimer):
|
|
timer.stop()
|
|
page.close()
|
|
page.deleteLater()
|
|
application.processEvents()
|
|
|
|
|
|
@pytest.mark.parametrize("kind", ["appointments", "patients", "consultations", "prescriptions", "prescription_library"])
|
|
def test_list_header_fits_the_real_bundled_font(page_factory, kind: str) -> None:
|
|
page = page_factory(kind)
|
|
header = page.findChild(PageHeader)
|
|
assert header is not None
|
|
for label in header.findChildren(QLabel):
|
|
if label.isVisible() and label.text() and label.property("role"):
|
|
assert label.height() >= label.fontMetrics().height(), (
|
|
kind, label.text(), label.height(), label.fontMetrics().height()
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize("kind", ["patients", "prescription_library"])
|
|
@pytest.mark.parametrize("width", [1040, 1200])
|
|
def test_row_actions_are_fully_reachable_at_each_width(page_factory, kind, width):
|
|
page = page_factory(kind, width)
|
|
table = page.patient_workspace.table if kind == "patients" else page.table
|
|
assert table.rowCount() > 0
|
|
assert table.horizontalHeader().visualIndex(9) == 9
|
|
actions = table.cellWidget(0, 9)
|
|
assert actions is not None
|
|
assert table.horizontalScrollBar().value() == 0
|
|
# Both approved layouts put actions after the nine data columns. Preserve
|
|
# full-size controls and the existing reachability assertion after scrolling.
|
|
table.horizontalScrollBar().setValue(table.horizontalScrollBar().maximum())
|
|
QApplication.processEvents()
|
|
assert actions.geometry().left() >= 0
|
|
assert actions.geometry().right() < table.viewport().width()
|
|
assert actions.height() >= actions.minimumSizeHint().height()
|
|
for child in actions.findChildren(QPushButton):
|
|
assert actions.rect().contains(child.mapTo(actions, QPoint()))
|
|
assert actions.rect().contains(child.mapTo(actions, child.rect().bottomRight()))
|
|
|
|
|
|
def test_appointment_detail_lines_and_cancel_fit_without_overlapping(page_factory) -> None:
|
|
page = page_factory("appointments")
|
|
table = page.table
|
|
assert table.rowCount() > 0
|
|
host = table.cellWidget(0, 4)
|
|
assert host.width() >= host.minimumSizeHint().width()
|
|
assert host.height() >= host.minimumSizeHint().height()
|
|
for label in host.findChildren(QLabel):
|
|
assert label.height() >= label.fontMetrics().height()
|
|
assert host.rect().contains(label.geometry())
|
|
cancel = next(button for button in host.findChildren(QPushButton) if button.text() == "取消")
|
|
for label in host.findChildren(QLabel):
|
|
assert not label.geometry().intersects(cancel.geometry())
|
|
# Underlying text is still available to sorting while a delegate paints only
|
|
# the selection surface beneath the actual controls.
|
|
assert table.item(0, 4).text()
|
|
assert isinstance(table.itemDelegateForColumn(4), appointments._AppointmentInfoDelegate)
|
|
assert table.horizontalScrollBar().maximum() == 0
|
|
search = page.findChild(QPushButton, "AppointmentSearchButton")
|
|
assert search.height() == page.patient_input.height()
|
|
assert all(button.height() == search.height() for button in page.date_buttons.values() if button.isVisible())
|
|
|
|
|
|
@pytest.mark.parametrize("kind", ["patients", "prescriptions", "prescription_library", "consultations"])
|
|
def test_filter_actions_align_with_their_inputs(page_factory, kind: str) -> None:
|
|
page = page_factory(kind)
|
|
if kind == "patients":
|
|
controls = page.patient_workspace
|
|
widgets = (controls.keyword_edit, controls.search_button, controls.reset_button)
|
|
statuses = tuple(controls.status_buttons.values())
|
|
assert len({widget.height() for widget in statuses}) == 1
|
|
assert len({widget.mapTo(controls.status_host, QPoint()).y() for widget in statuses}) == 1
|
|
for widget in statuses:
|
|
assert controls.status_host.rect().contains(widget.geometry())
|
|
assert widget.height() >= widget.fontMetrics().height()
|
|
elif kind == "prescriptions":
|
|
widgets = (page.sn_filter, page.query_button, page.reset_button, page.doctor_filter.button)
|
|
elif kind == "prescription_library":
|
|
widgets = (page.name_filter, page.query_button, page.reset_button)
|
|
else:
|
|
widgets = (page.search_button, page.reset_button, page.custom_date_edit)
|
|
assert len({widget.height() for widget in widgets}) == 1
|