新增
This commit is contained in:
@@ -8,6 +8,7 @@ from PySide6.QtWidgets import QApplication
|
||||
|
||||
from doctor_workstation import app as app_module
|
||||
from doctor_workstation.app import ApplicationController
|
||||
from doctor_workstation.config import AppConfig
|
||||
from doctor_workstation.core.errors import AuthenticationExpiredError
|
||||
from doctor_workstation.services import DemoDoctorRepository
|
||||
from doctor_workstation.ui import login as login_module
|
||||
@@ -16,6 +17,7 @@ from doctor_workstation.ui.login import LoginWindow
|
||||
from doctor_workstation.ui.pages.consultations import _video_payload
|
||||
from doctor_workstation.ui.shell import NAVIGATION
|
||||
from doctor_workstation.ui.widgets import (
|
||||
friendly_error,
|
||||
gender_text,
|
||||
invoke,
|
||||
set_authentication_expired_handler,
|
||||
@@ -47,6 +49,7 @@ def test_gender_text_maps_legacy_codes_and_preserves_labels() -> None:
|
||||
def test_navigation_requires_each_pages_actual_list_capability() -> None:
|
||||
assert {item.key: item.permissions for item in NAVIGATION} == {
|
||||
"reception": ("doctor.appointment/lists",),
|
||||
"appointments": ("doctor.appointment/lists",),
|
||||
"prescription_library": ("tcm.prescriptionLibrary/lists",),
|
||||
"prescriptions": ("tcm.prescription/lists",),
|
||||
"patients": ("firstvisit.myPatient/lists",),
|
||||
@@ -227,3 +230,180 @@ def test_real_demo_login_reaches_success_without_widget_adapter(
|
||||
assert not window._loading
|
||||
window.close()
|
||||
application.processEvents()
|
||||
|
||||
|
||||
def test_remembered_account_survives_a_new_login_window(tmp_path: Any) -> None:
|
||||
application = QApplication.instance() or QApplication([])
|
||||
settings_path = tmp_path / "remember-account.ini"
|
||||
config = SimpleNamespace(
|
||||
api_base_url="",
|
||||
request_timeout=30,
|
||||
verify_ssl=True,
|
||||
demo_mode=False,
|
||||
remembered_account="",
|
||||
)
|
||||
first = LoginWindow(
|
||||
object(),
|
||||
config=config,
|
||||
settings=QSettings(str(settings_path), QSettings.Format.IniFormat),
|
||||
)
|
||||
first._on_login_success({}, "admin", True)
|
||||
first.close()
|
||||
application.processEvents()
|
||||
|
||||
restored = LoginWindow(
|
||||
object(),
|
||||
config=config,
|
||||
settings=QSettings(str(settings_path), QSettings.Format.IniFormat),
|
||||
)
|
||||
assert restored.account_edit.text() == "admin"
|
||||
assert restored.remember_check.isChecked()
|
||||
restored.close()
|
||||
application.processEvents()
|
||||
|
||||
|
||||
def test_server_settings_panel_keeps_controls_separated_at_minimum_window(
|
||||
tmp_path: Any,
|
||||
) -> None:
|
||||
application = QApplication.instance() or QApplication([])
|
||||
settings = QSettings(str(tmp_path / "server-panel.ini"), QSettings.Format.IniFormat)
|
||||
config = SimpleNamespace(
|
||||
api_base_url="",
|
||||
request_timeout=30,
|
||||
demo_mode=False,
|
||||
remembered_account="",
|
||||
)
|
||||
window = LoginWindow(object(), config=config, settings=settings)
|
||||
window.resize(860, 590)
|
||||
window.show()
|
||||
window.server_toggle.setChecked(True)
|
||||
window._toggle_server_panel(True)
|
||||
application.processEvents()
|
||||
|
||||
assert window.server_panel.isVisible()
|
||||
assert window.server_panel.height() >= window.server_panel.minimumSizeHint().height()
|
||||
assert window.server_url_label.geometry().bottom() < window.server_url_edit.geometry().top()
|
||||
assert window.server_url_edit.geometry().bottom() < window.timeout_label.geometry().top()
|
||||
assert window.timeout_spin.geometry().right() < window.save_server_button.geometry().left()
|
||||
assert window.timeout_label.geometry().bottom() < window.allow_self_signed_check.geometry().top()
|
||||
assert window.allow_self_signed_check.geometry().bottom() < window.server_hint.geometry().top()
|
||||
|
||||
window.allow_self_signed_check.setChecked(True)
|
||||
application.processEvents()
|
||||
assert window.ssl_warning.isVisible()
|
||||
assert window.allow_self_signed_check.geometry().bottom() < window.ssl_warning.geometry().top()
|
||||
assert window.ssl_warning.geometry().bottom() < window.server_hint.geometry().top()
|
||||
|
||||
window.close()
|
||||
application.processEvents()
|
||||
|
||||
|
||||
def test_server_settings_can_persist_self_signed_debug_mode(tmp_path: Any) -> None:
|
||||
application = QApplication.instance() or QApplication([])
|
||||
settings = QSettings(str(tmp_path / "self-signed.ini"), QSettings.Format.IniFormat)
|
||||
config = SimpleNamespace(
|
||||
api_base_url="https://internal.example.test",
|
||||
request_timeout=30,
|
||||
verify_ssl=True,
|
||||
demo_mode=False,
|
||||
remembered_account="",
|
||||
)
|
||||
window = LoginWindow(object(), config=config, settings=settings)
|
||||
emitted: list[dict[str, Any]] = []
|
||||
window.server_settings_changed.connect(emitted.append)
|
||||
window.allow_self_signed_check.setChecked(True)
|
||||
|
||||
window._save_server_settings()
|
||||
|
||||
assert emitted[-1]["verify_ssl"] is False
|
||||
assert settings.value("server/verify_ssl", type=bool) is False
|
||||
assert "证书校验已关闭" in window.error_banner.label.text()
|
||||
window.close()
|
||||
application.processEvents()
|
||||
|
||||
|
||||
def test_login_applies_self_signed_setting_before_authentication(
|
||||
monkeypatch: Any,
|
||||
tmp_path: Any,
|
||||
) -> None:
|
||||
application = QApplication.instance() or QApplication([])
|
||||
settings = QSettings(str(tmp_path / "self-signed-login.ini"), QSettings.Format.IniFormat)
|
||||
config = AppConfig(
|
||||
api_base_url="https://internal.example.test/adminapi",
|
||||
demo_mode=False,
|
||||
verify_ssl=True,
|
||||
)
|
||||
calls: list[str] = []
|
||||
|
||||
class Repository:
|
||||
def __init__(self, name: str) -> None:
|
||||
self.name = name
|
||||
|
||||
def login(self, **_payload: Any) -> object:
|
||||
calls.append(self.name)
|
||||
return object()
|
||||
|
||||
def get_current_user(self) -> object:
|
||||
return object()
|
||||
|
||||
old_repository = Repository("old")
|
||||
rebuilt_repository = Repository("rebuilt-without-verification")
|
||||
window = LoginWindow(old_repository, config=config, settings=settings)
|
||||
|
||||
def rebuild_on_config_change(updated: AppConfig) -> None:
|
||||
assert updated.verify_ssl is False
|
||||
window.repository = rebuilt_repository
|
||||
window.active_repository = rebuilt_repository
|
||||
|
||||
def run_immediately(function: Any, **callbacks: Any) -> object:
|
||||
try:
|
||||
callbacks["on_success"](function())
|
||||
except Exception as error: # pragma: no cover - assertion output is more useful
|
||||
callbacks["on_error"](error)
|
||||
finally:
|
||||
callbacks["on_finished"]()
|
||||
return object()
|
||||
|
||||
monkeypatch.setattr(login_module, "run_async", run_immediately)
|
||||
window.config_changed.connect(rebuild_on_config_change)
|
||||
window.account_edit.setText("admin")
|
||||
window.password_edit.setText("secret")
|
||||
window.allow_self_signed_check.setChecked(True)
|
||||
|
||||
window.submit()
|
||||
|
||||
assert calls == ["rebuilt-without-verification"]
|
||||
assert settings.value("server/verify_ssl", type=bool) is False
|
||||
window.close()
|
||||
application.processEvents()
|
||||
|
||||
|
||||
def test_certificate_error_explains_self_signed_server_setting() -> None:
|
||||
message = friendly_error(
|
||||
RuntimeError("[SSL: CERTIFICATE_VERIFY_FAILED] self-signed certificate")
|
||||
)
|
||||
assert "信任自签名证书" in message
|
||||
assert "服务器设置" in message
|
||||
|
||||
|
||||
def test_certificate_error_opens_server_settings(tmp_path: Any) -> None:
|
||||
application = QApplication.instance() or QApplication([])
|
||||
settings = QSettings(str(tmp_path / "certificate-error.ini"), QSettings.Format.IniFormat)
|
||||
config = SimpleNamespace(
|
||||
api_base_url="https://internal.example.test",
|
||||
request_timeout=30,
|
||||
verify_ssl=True,
|
||||
demo_mode=False,
|
||||
remembered_account="",
|
||||
)
|
||||
window = LoginWindow(object(), config=config, settings=settings)
|
||||
|
||||
window._on_login_error(
|
||||
RuntimeError("[SSL: CERTIFICATE_VERIFY_FAILED] self-signed certificate")
|
||||
)
|
||||
|
||||
assert window.server_toggle.isChecked()
|
||||
assert not window.server_panel.isHidden()
|
||||
assert "信任自签名证书" in window.error_banner.label.text()
|
||||
window.close()
|
||||
application.processEvents()
|
||||
|
||||
Reference in New Issue
Block a user