130 lines
4.1 KiB
Python
130 lines
4.1 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 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
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def application() -> QApplication:
|
|
return QApplication.instance() or QApplication([])
|
|
|
|
|
|
def _visible_windows(application: QApplication) -> list[QWidget]:
|
|
return [
|
|
widget
|
|
for widget in application.topLevelWidgets()
|
|
if widget.isWindow() and widget.isVisible()
|
|
]
|
|
|
|
|
|
def test_busy_overlay_children_are_not_windows(application: QApplication) -> None:
|
|
host = QWidget()
|
|
host.resize(360, 240)
|
|
host.show()
|
|
application.processEvents()
|
|
before = {id(widget) for widget in _visible_windows(application)}
|
|
|
|
overlay = BusyOverlay(host, "正在验证账号…")
|
|
overlay.setVisible(True)
|
|
application.processEvents()
|
|
|
|
assert overlay.parentWidget() is host
|
|
assert not overlay.isWindow()
|
|
assert overlay.progress.objectName() == "BusyOverlayProgress"
|
|
assert overlay.progress.parentWidget() is overlay
|
|
assert overlay.label.parentWidget() is overlay
|
|
assert not overlay.progress.isWindow()
|
|
assert not overlay.label.isWindow()
|
|
extra = [
|
|
widget
|
|
for widget in _visible_windows(application)
|
|
if id(widget) not in before and widget is not host
|
|
]
|
|
assert extra == []
|
|
|
|
overlay.setVisible(False)
|
|
host.close()
|
|
application.processEvents()
|
|
|
|
|
|
def test_login_loading_does_not_spawn_extra_windows(
|
|
application: QApplication, tmp_path: Any
|
|
) -> None:
|
|
settings = QSettings(str(tmp_path / "login.ini"), QSettings.Format.IniFormat)
|
|
window = LoginWindow(
|
|
object(),
|
|
config=SimpleNamespace(
|
|
api_base_url="https://127.0.0.1:9",
|
|
request_timeout=30,
|
|
demo_mode=False,
|
|
remembered_account="admin",
|
|
),
|
|
settings=settings,
|
|
)
|
|
window.show()
|
|
application.processEvents()
|
|
before = {id(widget) for widget in _visible_windows(application)}
|
|
|
|
window._set_loading(True)
|
|
application.processEvents()
|
|
|
|
extra = [widget for widget in _visible_windows(application) if id(widget) not in before]
|
|
assert extra == []
|
|
assert window.busy_overlay.isVisible()
|
|
assert not window.busy_overlay.isWindow()
|
|
assert not window.busy_overlay.progress.isWindow()
|
|
assert window.busy_overlay.label.text() == "正在验证账号…"
|
|
|
|
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()
|