mirror of
https://github.com/nesquena/hermes-webui.git
synced 2026-05-23 10:50:14 +00:00
52 lines
2.2 KiB
Python
52 lines
2.2 KiB
Python
"""Regression tests for #1784: sidebar scroll remains independent while streaming."""
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
UI_JS = (ROOT / "static" / "ui.js").read_text(encoding="utf-8")
|
|
STYLE_CSS = (ROOT / "static" / "style.css").read_text(encoding="utf-8")
|
|
|
|
|
|
def _extract_fn(src: str, name: str) -> str:
|
|
marker = f"function {name}"
|
|
start = src.find(marker)
|
|
assert start >= 0, f"{name} not found"
|
|
brace = src.find("{", start)
|
|
assert brace >= 0, f"{name} body not found"
|
|
depth = 0
|
|
for i in range(brace, len(src)):
|
|
ch = src[i]
|
|
if ch == "{":
|
|
depth += 1
|
|
elif ch == "}":
|
|
depth -= 1
|
|
if depth == 0:
|
|
return src[start : i + 1]
|
|
raise AssertionError(f"{name} body did not close")
|
|
|
|
|
|
def test_sidebar_wheel_intent_is_recorded_passively():
|
|
"""A sidebar wheel gesture must not be swallowed or ignored during streaming."""
|
|
assert "_recordNonMessageScrollIntent" in UI_JS
|
|
assert "document.addEventListener('wheel',_recordNonMessageScrollIntent" in UI_JS
|
|
assert "{capture:true,passive:true}" in UI_JS
|
|
assert "!el.contains(target)" in UI_JS
|
|
assert "_lastNonMessageScrollIntentMs=performance.now()" in UI_JS
|
|
|
|
|
|
def test_scroll_if_pinned_skips_during_recent_non_message_scroll():
|
|
"""Token rendering must not force-scroll #messages while the sidebar is being scrolled."""
|
|
fn = _extract_fn(UI_JS, "scrollIfPinned")
|
|
assert "_recentNonMessageScrollIntent()" in fn
|
|
guard_index = fn.find("_recentNonMessageScrollIntent()")
|
|
settle_index = fn.find("_settleMessageScrollToBottom(false)")
|
|
assert guard_index >= 0 and settle_index >= 0 and guard_index < settle_index
|
|
|
|
settle = _extract_fn(UI_JS, "_settleMessageScrollToBottom")
|
|
assert "_setMessageScrollToBottom();" in settle
|
|
assert "_recentNonMessageScrollIntent()" in settle
|
|
|
|
|
|
def test_session_list_has_its_own_scroll_boundary():
|
|
"""The session list is its own scroll surface, not chained to the chat/body scroller."""
|
|
assert ".session-list{flex:1;overflow-y:auto;padding:0 8px 8px;min-height:0;overscroll-behavior-y:contain;touch-action:pan-y;overflow-anchor:none;}" in STYLE_CSS
|