HERMES-GIELIE/tests/test_issue1669_sidebar_scroll_jump_fix.py

88 lines
3.8 KiB
Python
Raw Normal View History

"""Regression test for #1669 follow-up — sidebar scroll jump fix.
The original PR #1669 added DOM virtualization to renderSessionListFromCache,
which:
1. Attached an unconditional scroll listener to the session list
2. The scroll listener triggers renderSessionListFromCache() on every rAF
3. The render rebuilds the list DOM via list.innerHTML='' / appendChild loop
4. After the rebuild, scrollTop was only restored when virtualWindow.virtualized
was true (i.e. total > 80 rows)
5. For lists ≤ 80 rows, the scrollTop reset to 0 on every scroll event,
producing a "scroll keeps jumping back" feel.
This test pins:
- The non-virtualized branch always restores scrollTop after a rebuild
- The scroll handler short-circuits when total <= threshold (prevents the
rebuild churn entirely on small lists)
"""
from pathlib import Path
SESSIONS_JS = Path(__file__).parent.parent / "static" / "sessions.js"
def _read_source():
return SESSIONS_JS.read_text()
def test_render_restores_scroll_top_for_non_virtualized_lists():
"""The bug: virtualWindow.virtualized=false skipped the scrollTop restore.
The fix: restore scrollTop whenever listScrollTopBeforeRender > 0,
regardless of virtualized flag. Otherwise small lists (≤80 rows) reset
to scrollTop=0 on every render.
"""
src = _read_source()
# The new branch must include listScrollTopBeforeRender>0 as the guard
# rather than virtualWindow.virtualized
assert "}else if(listScrollTopBeforeRender>0){" in src, (
"Expected the scrollTop-restore guard to use listScrollTopBeforeRender>0, "
"not virtualWindow.virtualized — without this fix, small lists drop "
"scrollTop to 0 on every scroll event."
)
def test_scroll_handler_short_circuits_below_virtualization_threshold():
"""The bug: the rAF re-render fired on every scroll event regardless of
whether virtualization was actually needed. For ≤80-row lists this caused
full DOM rebuild on every scroll tick.
The fix: _scheduleSessionVirtualizedRender skips the rebuild when
total <= SESSION_VIRTUAL_THRESHOLD_ROWS — there's no virtual window to
recompute on small lists, and the rebuild was wasteful (and bug-prone).
"""
src = _read_source()
# Locate the function body
start = src.find("function _scheduleSessionVirtualizedRender()")
end = src.find("function _ensureSessionVirtualScrollHandler", start)
body = src[start:end]
# The fix introduces an early-return when total <= SESSION_VIRTUAL_THRESHOLD_ROWS
assert "SESSION_VIRTUAL_THRESHOLD_ROWS" in body, (
"Expected _scheduleSessionVirtualizedRender to read the threshold; "
"without this guard, the rAF re-render fires on every scroll event "
"even when there's nothing to virtualize."
)
assert "total<=SESSION_VIRTUAL_THRESHOLD_ROWS" in body or "total <= SESSION_VIRTUAL_THRESHOLD_ROWS" in body, (
"Expected explicit total<=THRESHOLD comparison to short-circuit the re-render."
)
# The early return must be BEFORE the rAF schedule (else it's dead code)
early_return_idx = body.find("return")
raf_idx = body.find("requestAnimationFrame")
assert early_return_idx > 0 and early_return_idx < raf_idx, (
"The total<=THRESHOLD short-circuit must return BEFORE scheduling the rAF."
)
def test_virtualization_still_active_for_large_lists():
"""Regression: ensure the threshold + virtualWindow logic is still in place
for large lists. The fix must not break the original virtualization path.
"""
src = _read_source()
assert "SESSION_VIRTUAL_THRESHOLD_ROWS = 80" in src, (
"Threshold constant must remain at 80 rows."
)
# _sessionVirtualWindow function still defined
assert "function _sessionVirtualWindow" in src
# virtualWindow.virtualized branch still drives spacer rendering
assert "virtualWindow.virtualized" in src