Журнал перерисовывается целиком, и очистка документа сбрасывала прокрутку в начало: следующая перерисовка принимала это за прокрутку пользователем и оставляла журнал наверху. - Режим «следовать за низом» меняется только прокруткой пользователя - Позиция восстанавливается по rangeChanged, когда раскладка документа действительно обновилась - Новый запрос всегда прокручивает вниз - Тесты автопрокрутки и сохранения позиции при прокрутке вверх Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
73 lines
2.3 KiB
Python
73 lines
2.3 KiB
Python
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()
|