import time import pytest from PySide6.QtCore import QCoreApplication from PySide6.QtWidgets import QApplication from agr_assistent.core.memory import MemoryStore from agr_assistent.ui.chat_window import ChatWindow from tests.fake_llm import FakeLLMServer from tests.test_assistant_flow import _assistant def _pump(seconds: float = 0.1) -> None: deadline = time.monotonic() + seconds while time.monotonic() < deadline: QCoreApplication.processEvents() time.sleep(0.005) @pytest.fixture def window(qapp: QApplication, fake_llm: FakeLLMServer, tmp_path) -> ChatWindow: # type: ignore[no-untyped-def] memory = MemoryStore(tmp_path / "memory.sqlite3") chat = ChatWindow(_assistant(fake_llm, memory)) chat.resize(500, 300) chat.show() yield chat chat.hide() memory.close() def _scrollbar(window: ChatWindow): # type: ignore[no-untyped-def] return window._transcript.verticalScrollBar() def _stream_reply(window: ChatWindow, request: str, chunks: int) -> None: assistant = window._assistant assistant.request_added.emit(request, False) assistant.reply_started.emit() for index in range(chunks): assistant.reply_chunk.emit(f"Строка ответа номер {index}.\n\n") _pump(0.01) assistant.reply_finished.emit("") _pump(0.2) def test_journal_follows_new_content(window: ChatWindow) -> None: for request in range(3): _stream_reply(window, f"Вопрос {request}", chunks=15) scrollbar = _scrollbar(window) assert scrollbar.maximum() > 0 assert scrollbar.value() == scrollbar.maximum() def test_journal_keeps_position_when_user_scrolled_up(window: ChatWindow) -> None: _stream_reply(window, "Длинный вопрос", chunks=30) scrollbar = _scrollbar(window) scrollbar.setValue(10) _pump() assistant = window._assistant assistant.reply_started.emit() for index in range(10): assistant.reply_chunk.emit(f"Ещё строка {index}.\n\n") _pump(0.01) _pump(0.2) assert scrollbar.value() == 10 # Новый запрос пользователя снова прокручивает вниз assistant.request_added.emit("Новый вопрос", False) _pump(0.2) assert scrollbar.value() == scrollbar.maximum()