Files
hermes-webui/tests/test_issue2341_pending_user_reattach.py
nesquena-hermes 3603027b74 test: update loadSession source-assertion tests for #3326 conditional renderMessages arg
#3326 changed loadSession's INFLIGHT + idle render calls from bare
renderMessages() to renderMessages(sameSessionForceReload?{preserveScroll:true}:undefined),
and added reload-width-hint handling inside _ensureMessagesLoaded. Updated 5
source-pinning tests to match the new (behaviorally-equivalent) call form:
- test_regressions / test_issue2341: match 'renderMessages(' call form
- test_parallel_session_switch: match call form + widen 600->850 block window
- test_issue1690: assert the CONDITIONAL preserveScroll (cross-session still bottom-pins)
- test_issue3162: widen _ensureMessagesLoaded slice 2000->2600
2026-06-02 19:11:15 +00:00

71 lines
3.3 KiB
Python

from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
SESSIONS_JS = (ROOT / "static" / "sessions.js").read_text(encoding="utf-8")
UI_JS = (ROOT / "static" / "ui.js").read_text(encoding="utf-8")
def _load_session_inflight_branch() -> str:
start = SESSIONS_JS.find("if(INFLIGHT[sid]){")
assert start != -1, "loadSession INFLIGHT branch not found"
end = SESSIONS_JS.find("}else{", start)
assert end != -1, "loadSession INFLIGHT branch end not found"
return SESSIONS_JS[start:end]
def test_load_session_inflight_reattach_merges_pending_user_message_before_render():
"""#2341: Reattaching to an active stream must show the initiating user turn.
A reload or session switch can hydrate a running turn from INFLIGHT while the
backend still carries the user prompt only as pending_user_message. Without
merging that pending row before renderMessages(), the user sees assistant
thinking/tool activity without the prompt that started it.
"""
block = _load_session_inflight_branch()
merge_pos = block.find("_mergePendingSessionMessage")
# #3326 added an optional {preserveScroll} arg to the INFLIGHT-branch render
# call; match the call form rather than the bare `renderMessages();`.
render_pos = block.find("renderMessages(")
assert merge_pos != -1, (
"loadSession's INFLIGHT reattach branch must merge pending_user_message "
"into S.messages before rendering the running turn"
)
assert render_pos != -1, "INFLIGHT branch render call not found"
assert merge_pos < render_pos, (
"The pending user row must be present before renderMessages() rebuilds "
"the active transcript"
)
assert "restoreLiveTurnHtmlForSession(sid)" in block, (
"Session restore may keep a live DOM snapshot instead of always "
"recreating a fresh Thinking row after renderMessages()"
)
assert "INFLIGHT[sid].messages=S.messages;" in block, (
"After merging the pending user row, the INFLIGHT cache should be updated "
"so later session switches keep the same visible turn"
)
assert "messages.findIndex(m=>m&&m.role==='assistant'&&m._live)" in SESSIONS_JS
assert "messages.splice(liveAssistantIdx,0,pendingMsg)" in SESSIONS_JS
def test_pending_user_message_dedup_checks_current_message_array():
"""#2341: Pending merge must not duplicate an already-visible user row."""
assert "function getPendingSessionMessage(session, messagesOverride=null)" in UI_JS
helper_start = UI_JS.find("function getPendingSessionMessage(session, messagesOverride=null)")
assert helper_start != -1, "getPendingSessionMessage helper not found"
helper_end = UI_JS.find("async function checkInflightOnBoot", helper_start)
assert helper_end != -1, "getPendingSessionMessage helper end not found"
helper = UI_JS[helper_start:helper_end]
assert "messagesOverride" in helper
assert "Array.isArray(messagesOverride)?messagesOverride" in helper.replace(" ", ""), (
"Pending-message dedup must inspect the current S.messages/INFLIGHT "
"array, not only session.messages from the metadata response"
)
assert "lastText===text" in helper, (
"Pending-message merge must suppress duplicates when the last user row "
"already matches pending_user_message"
)