Reworked from the Codex re-gate (rebased onto fresh master so #4730's gateway-poll work is preserved, not reverted). Two CORE races + a test-window break: (1) Skeleton-clobber (sessions.js): renderSessionListFromCache() now bails while _sessionListSkeletonActive — _allSessions still holds the PREVIOUS profile until /api/sessions resolves, so a gateway-poll/SSE/timer/cache render mid-switch would repaint the wrong profile's rows over the skeleton. _applySessionListPayload clears the flag right before painting (fresh data in hand; superseded responses already discarded by the generation guard); the fetch-failure path and switch-failure catch clear it too so it can't strand. NO signature change (kept renderSessionListFromCache() and _applySessionListPayload(sessData,projData) so the ~10 static tests that anchor on those markers stay green). (2) Workspace wrong-profile tree (workspace.js + panels.js): an empty-session switch reuses the same session_id, so loadDir()'s id guard can't reject a stale pre-switch /api/list. Added _wsTreeGen generation token + bumpWorkspaceTreeGen(), bumped UNCONDITIONALLY at switch start (even panel-closed, since loadDir('.') still runs), captured in loadDir() and re-checked after both awaited /api/list points. (3) test_issue1116 proximity window 5000->6500 (applyBotName now ~char 5618, still fires). + regression tests: skeleton-flag bail/clear lifecycle, ws generation token, failure restore clears flag; updated #1785 stale-session guard test for the compound condition. Co-authored-by: rodboev <rodboev@users.noreply.github.com>
76 lines
3.4 KiB
Python
76 lines
3.4 KiB
Python
from pathlib import Path
|
|
|
|
|
|
BOOT_JS = Path("static/boot.js").read_text(encoding="utf-8")
|
|
WORKSPACE_JS = Path("static/workspace.js").read_text(encoding="utf-8")
|
|
|
|
|
|
def _function_block(src: str, name: str) -> str:
|
|
marker = f"function {name}("
|
|
start = src.find(marker)
|
|
assert start != -1, f"{name}() not found"
|
|
params_end = src.find("){", start)
|
|
assert params_end != -1, f"{name}() body not found"
|
|
brace = params_end + 1
|
|
depth = 0
|
|
for idx in range(brace, len(src)):
|
|
ch = src[idx]
|
|
if ch == "{":
|
|
depth += 1
|
|
elif ch == "}":
|
|
depth -= 1
|
|
if depth == 0:
|
|
return src[start : idx + 1]
|
|
raise AssertionError(f"{name}() body did not close")
|
|
|
|
|
|
def test_clear_preview_can_keep_preview_only_panel_open_for_directory_navigation():
|
|
"""#1785: leaving preview via a directory breadcrumb should switch to browse mode, not close."""
|
|
block = _function_block(BOOT_JS, "clearPreview")
|
|
assert "keepPanelOpen" in block, (
|
|
"clearPreview() needs an explicit keep-open option so breadcrumb/directory "
|
|
"navigation can leave preview-only mode without closing the workspace panel."
|
|
)
|
|
assert "_workspacePanelMode==='preview'&&!keepPanelOpen" in block.replace(" ", ""), (
|
|
"Preview-only close behavior should remain for the X button, but must be gated "
|
|
"off when directory navigation requests keepPanelOpen."
|
|
)
|
|
assert "openWorkspacePanel('browse')" in block or '_setWorkspacePanelMode("browse")' in block, (
|
|
"When keepPanelOpen is requested from preview-only mode, clearPreview() should "
|
|
"transition the workspace panel to browse mode so the root listing remains visible."
|
|
)
|
|
|
|
|
|
def test_load_dir_keeps_workspace_panel_open_when_clearing_preview():
|
|
"""#1785: loadDir('.') from the ~ breadcrumb should reveal the listing, not collapse the panel."""
|
|
block = _function_block(WORKSPACE_JS, "loadDir")
|
|
assert "clearPreview({keepPanelOpen:true})" in block.replace(" ", ""), (
|
|
"Directory navigation clears previews as part of showing the file tree; that clear "
|
|
"must keep the workspace panel open for breadcrumb navigation from preview mode."
|
|
)
|
|
|
|
|
|
def test_load_dir_ignores_stale_session_results():
|
|
block = _function_block(WORKSPACE_JS, "loadDir")
|
|
assert "const sessionId=S.session.session_id" in block
|
|
assert "encodeURIComponent(sessionId)" in block
|
|
# #4671 extended this guard with a workspace-tree generation check (an empty-session
|
|
# profile switch reuses the same session_id, so the id check alone isn't enough), so
|
|
# the rejection is now a compound condition. The session_id rejection must remain.
|
|
assert "S.session.session_id!==sessionId" in block, (
|
|
"loadDir must still reject results whose session_id no longer matches"
|
|
)
|
|
assert "treeGen!==_wsTreeGen" in block, (
|
|
"loadDir must also reject results from a superseded workspace-tree generation "
|
|
"(profile-switch stale-load race, #4671)"
|
|
)
|
|
|
|
|
|
def test_file_preview_breadcrumb_uses_directory_navigation_for_root():
|
|
block = _function_block(WORKSPACE_JS, "renderFileBreadcrumb")
|
|
assert "loadDir('.')" in block, "The preview root breadcrumb should navigate to the workspace root."
|
|
assert "clearPreview(); loadDir('.')" not in block, (
|
|
"The preview root breadcrumb should not do a close-style preview clear before "
|
|
"directory navigation; loadDir() owns the keep-open preview clear."
|
|
)
|