Files
javis/tests/test_slave_chat_ui.py
T
2026-10-10 13:20:35 +02:00

121 lines
3.6 KiB
Python

"""Slave GUI chat: newest-first transcript and fullscreen chat mode (offscreen Qt)."""
from __future__ import annotations
import os
import sys
from pathlib import Path
import pytest
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
SLAVE_SRC = Path(__file__).resolve().parents[1] / "javis-slave" / "src"
if str(SLAVE_SRC) not in sys.path:
sys.path.insert(0, str(SLAVE_SRC))
QtWidgets = pytest.importorskip("PySide6.QtWidgets")
QtTest = pytest.importorskip("PySide6.QtTest")
from javis_slave import main_window # noqa: E402
@pytest.fixture(scope="module")
def qapp():
return QtWidgets.QApplication.instance() or QtWidgets.QApplication([])
@pytest.fixture
def screen(qapp):
scr = main_window.MainScreen()
scr.resize(900, 700)
scr.show()
yield scr
scr.close()
def _texts(scr) -> list[str]:
"""Bubble texts from the top of the transcript to the bottom."""
layout = scr.transcript_layout
out = []
for i in range(layout.count()):
row = layout.itemAt(i).widget()
if row is not None:
out.append(row.findChild(QtWidgets.QLabel).text())
return out
def test_newest_message_is_on_top(screen):
screen.set_turn("frage 1", "antwort 1")
screen.set_turn("frage 2", "antwort 2")
screen.show_error("kaputt")
assert _texts(screen) == [
"⚠ kaputt", "antwort 2", "frage 2", "antwort 1", "frage 1"]
def test_prune_drops_oldest_at_the_bottom(screen):
for i in range(30):
screen.set_turn(f"u{i}", f"a{i}")
texts = _texts(screen)
assert len(texts) == 40
assert texts[0] == "a29"
assert "u0" not in texts and "u29" in texts
def test_scrolls_to_top_on_new_message(screen):
for i in range(12):
screen.set_turn(f"u{i}", "x " * 200)
QtTest.QTest.qWait(150) # lets the layout settle (and the first auto-scroll fire)
vbar = screen.transcript_scroll.verticalScrollBar()
assert vbar.maximum() > 0
vbar.setValue(vbar.maximum())
screen.set_turn("neu", "neu")
QtTest.QTest.qWait(150) # the scroll is deferred by a 50 ms timer
assert vbar.value() == vbar.minimum()
def test_fullscreen_button_goes_fullscreen_and_keeps_orb_and_chat_visible(qapp):
win = main_window.SlaveWindow()
win.show_main()
win.show()
scr = win.main_screen
scr.set_turn("frage", "antwort")
try:
assert not win.isFullScreen()
assert scr.expand_btn.toolTip() == "Vollbild"
scr.expand_btn.click()
QtTest.QTest.qWait(50)
assert win.isFullScreen()
assert scr.orb.isVisible() and scr.transcript_scroll.isVisible()
assert scr.expand_btn.toolTip() == "Vollbild beenden"
scr.expand_btn.click()
QtTest.QTest.qWait(50)
assert not win.isFullScreen()
assert scr.orb.isVisible() and scr.transcript_scroll.isVisible()
assert scr.expand_btn.toolTip() == "Vollbild"
finally:
win.close()
def test_esc_and_f11_keep_button_in_sync(qapp):
win = main_window.SlaveWindow()
win.show_main()
win.show()
try:
win._toggle_fullscreen() # F11
QtTest.QTest.qWait(50)
assert win.isFullScreen() and win.main_screen.expand_btn.toolTip() == "Vollbild beenden"
win._leave_fullscreen() # Esc
QtTest.QTest.qWait(50)
assert not win.isFullScreen() and win.main_screen.expand_btn.toolTip() == "Vollbild"
finally:
win.close()
def test_expand_icons_render(qapp):
for kind in ("expand", "collapse"):
img = main_window._icon(kind, "#cccccc", 26).pixmap(26, 26).toImage()
assert any(img.pixelColor(x, y).alpha() > 0
for x in range(img.width()) for y in range(img.height()))