Files
zyt/app/tests/test_diagnosis_notes_image_preview.py
2026-09-09 12:18:17 +08:00

150 lines
6.5 KiB
Python

from __future__ import annotations
import os
from pathlib import Path
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
import pytest
from PySide6.QtCore import QBuffer, QCoreApplication, QEvent, QIODevice, QPoint, Qt
from PySide6.QtGui import QColor, QDesktopServices, QFont, QImage, QPainter
from PySide6.QtTest import QTest
from PySide6.QtWidgets import QApplication
from test_diagnosis_drawer_visual import (
ActionRepository,
_open_dialog,
_select_tab,
)
from test_diagnosis_drawer_visual import (
application as application,
)
from test_diagnosis_drawer_visual import (
immediate_async as immediate_async,
)
from test_diagnosis_media_thumbnail_visual import (
_FakeManager,
_hold_remote_load,
_png_bytes,
)
from doctor_workstation.ui.diagnosis_drawer import _RemoteImageButton
from doctor_workstation.ui.diagnosis_media import ImagePreviewDialog
from doctor_workstation.ui.theme import _register_preferred_cjk_fonts
def _synthetic_image() -> bytes:
image = QImage(1600, 1200, QImage.Format.Format_ARGB32)
image.fill(QColor("#F4E3D8"))
painter = QPainter(image)
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
painter.setPen(Qt.PenStyle.NoPen)
painter.setBrush(QColor("#C37B85"))
painter.drawEllipse(440, 160, 720, 900)
painter.setPen(QColor("#67434A"))
painter.setFont(QFont("Arial", 36))
painter.drawText(image.rect(), Qt.AlignmentFlag.AlignCenter, "SYNTHETIC TEST IMAGE")
painter.end()
buffer = QBuffer()
assert buffer.open(QIODevice.OpenModeFlag.WriteOnly)
assert image.save(buffer, "PNG")
return bytes(buffer.data())
@pytest.mark.parametrize("mode", ["edit", "readonly"])
def test_real_note_thumbnail_click_keeps_drawer_and_previews_all_eight_images(
application: QApplication, monkeypatch: pytest.MonkeyPatch, mode: str,
) -> None:
"""Exercise the wired drawer click, not just the standalone lightbox class."""
monkeypatch.setattr(_RemoteImageButton, "load_url", _hold_remote_load)
external: list[str] = []
monkeypatch.setattr(QDesktopServices, "openUrl", lambda url: external.append(url.toString()) or True)
application.setFont(QFont(_register_preferred_cjk_fonts(), 10))
payload = _synthetic_image()
def offline_request(preview: ImagePreviewDialog, target: str) -> None:
preview._invalidate_request()
preview.apply_payload(payload, preview._generation)
monkeypatch.setattr(ImagePreviewDialog, "_request", offline_request)
dialog = _open_dialog(application, (1440, 900), mode=mode, repository=ActionRepository())
urls = [f"https://media.example.invalid/tongue-{index}.jpg" for index in range(8)]
if mode == "edit":
_select_tab(dialog, "notes")
dialog._fill_notes([{"id": 7001, "note_date": "2026-09-08", "content": "合成测试图片", "tongue_images": urls}])
QCoreApplication.sendPostedEvents(None, QEvent.Type.DeferredDelete)
timeline = dialog.drawer_notes_timeline if mode == "edit" else dialog._notes_timelines[0]
application.processEvents()
thumbs = timeline.findChildren(_RemoteImageButton, "DiagnosisTongueThumb")
assert len(thumbs) == 8
for thumb in thumbs:
assert thumb._apply_payload(payload, thumb._generation)
original_parent = dialog.parentWidget()
original_generation = dialog._generation
for index in (0, 7, 3):
QTest.mouseClick(thumbs[index], Qt.MouseButton.LeftButton, pos=QPoint(24, 32))
application.processEvents()
assert external == [], "Thumbnail click must not launch the system browser"
preview = dialog._image_preview
assert isinstance(preview, ImagePreviewDialog)
assert preview.isVisible() and preview.parentWidget() is dialog
assert dialog.isVisible() and dialog.parentWidget() is original_parent
assert dialog._generation == original_generation
assert preview.current_source == urls[index]
assert preview.sources == urls
assert not preview.canvas.pixmap().isNull()
fitted_width = preview.canvas.pixmap().width()
QTest.mouseClick(preview.zoom_button, Qt.MouseButton.LeftButton)
assert preview.canvas.pixmap().width() == 1600 > fitted_width
QTest.mouseClick(preview.next_button, Qt.MouseButton.LeftButton)
assert preview.current_source == urls[(index + 1) % 8]
QTest.mouseClick(preview.previous_button, Qt.MouseButton.LeftButton)
assert preview.current_source == urls[index]
if mode == "edit" and index == 7:
output = Path(__file__).resolve().parents[2] / "artifacts/patient-render-image-fix"
output.mkdir(parents=True, exist_ok=True)
assert dialog.grab().save(str(output / "notes-eight-thumbnails.png"))
QTest.mouseClick(preview.zoom_button, Qt.MouseButton.LeftButton)
application.processEvents()
assert preview.grab().save(str(output / "notes-image-preview.png"))
if index == 3:
QTest.keyClick(preview, Qt.Key.Key_Escape)
else:
QTest.mouseClick(preview.close_button, Qt.MouseButton.LeftButton)
application.processEvents()
assert dialog.isVisible() and timeline.isVisible()
assert dialog._image_preview is None
QCoreApplication.sendPostedEvents(None, QEvent.Type.DeferredDelete)
assert external == []
QTest.mouseClick(thumbs[4], Qt.MouseButton.LeftButton, pos=QPoint(24, 32))
preview = dialog._image_preview
QTest.mouseClick(preview.external_button, Qt.MouseButton.LeftButton)
assert external == [urls[4]]
dialog.reject()
application.processEvents()
assert dialog._image_preview is None
@pytest.mark.parametrize("close_with_escape", [False, True])
def test_preview_close_cancels_pending_response(
application: QApplication, monkeypatch: pytest.MonkeyPatch, close_with_escape: bool,
) -> None:
monkeypatch.setattr(ImagePreviewDialog, "_request", lambda self, target: None)
preview = ImagePreviewDialog(["https://media.example.invalid/pending.jpg"])
manager = _FakeManager(preview)
manager.queue(_png_bytes(80, 60))
preview._manager = manager
monkeypatch.undo()
preview.reload_current()
reply = manager.replies[-1]
generation = preview._generation
preview.show()
if close_with_escape:
QTest.keyClick(preview, Qt.Key.Key_Escape)
else:
QTest.mouseClick(preview.close_button, Qt.MouseButton.LeftButton)
assert reply.aborted
assert preview._generation > generation
reply.finished.emit()
assert preview._pixmap.isNull()
application.processEvents()