feat: open updates at newest activity (Closes #759)
This commit is contained in:
1 parent
82982e5741
commit
707ee4c1bc
7 files changed
+151
No files matched your search
@@ -847,6 +847,7 @@ def test_install_precaches_complete_subpath_scoped_app_shell():
|
||||
"/dashboard/static/mobile-work-entry.js",
|
||||
"/dashboard/static/mobile-queue-launcher.js",
|
||||
"/dashboard/static/update-triage-session.js",
|
||||
"/dashboard/static/update-read-position.js",
|
||||
"/dashboard/static/update-triage-launcher.js",
|
||||
"/dashboard/static/agenda-session-launcher.js",
|
||||
"/dashboard/static/mobile-launch.js",
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
import json
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from tests.dashboard_bundle import dashboard
|
||||
|
||||
|
||||
POSITIONER = Path(__file__).resolve().parents[1] / "frontend" / "update-read-position.js"
|
||||
|
||||
|
||||
def run_positioner(script: str) -> dict:
|
||||
source = f"const createPositioner = require({json.dumps(str(POSITIONER))});\n" + script
|
||||
result = subprocess.run(["node", "-e", source], capture_output=True, text=True)
|
||||
assert result.returncode == 0, result.stderr
|
||||
return json.loads(result.stdout)
|
||||
|
||||
|
||||
def test_new_update_scrolls_to_newest_activity_once_without_reusing_previous_offset():
|
||||
result = run_positioner("""
|
||||
const listeners = {};
|
||||
const panel = {scrollTop:480, addEventListener:(name, fn)=>listeners[name]=fn};
|
||||
const jump = {hidden:true, focus(){}};
|
||||
const first = {calls:0, scrollIntoView(){this.calls += 1}, classList:{add(){}}};
|
||||
const second = {calls:0, scrollIntoView(){this.calls += 1}, classList:{add(){}}};
|
||||
const positioner = createPositioner({panel, jump});
|
||||
positioner.open('101');
|
||||
positioner.ready('101', first);
|
||||
positioner.ready('101', first);
|
||||
panel.scrollTop = 920;
|
||||
positioner.open('102');
|
||||
positioner.ready('102', second);
|
||||
process.stdout.write(JSON.stringify({first:first.calls, second:second.calls, jumpHidden:jump.hidden}));
|
||||
""")
|
||||
|
||||
assert result == {"first": 1, "second": 1, "jumpHidden": True}
|
||||
|
||||
|
||||
def test_user_scroll_during_loading_preserves_position_until_explicit_jump():
|
||||
result = run_positioner("""
|
||||
const listeners = {};
|
||||
const panel = {scrollTop:120, addEventListener:(name, fn)=>listeners[name]=fn};
|
||||
const jump = {hidden:true, focus(){}};
|
||||
const target = {calls:0, scrollIntoView(){this.calls += 1}, classList:{add(){}}};
|
||||
const positioner = createPositioner({panel, jump});
|
||||
positioner.open('201');
|
||||
panel.scrollTop = 260;
|
||||
listeners.scroll();
|
||||
positioner.ready('201', target);
|
||||
const before = {calls:target.calls, hidden:jump.hidden, top:panel.scrollTop};
|
||||
positioner.jump();
|
||||
process.stdout.write(JSON.stringify({before, after:{calls:target.calls, hidden:jump.hidden}}));
|
||||
""")
|
||||
|
||||
assert result == {
|
||||
"before": {"calls": 0, "hidden": False, "top": 260},
|
||||
"after": {"calls": 1, "hidden": True},
|
||||
}
|
||||
|
||||
|
||||
def test_stale_or_prefetched_conversation_cannot_move_the_visible_update():
|
||||
result = run_positioner("""
|
||||
const panel = {scrollTop:0, addEventListener(){}};
|
||||
const jump = {hidden:true};
|
||||
const stale = {calls:0, scrollIntoView(){this.calls += 1}, classList:{add(){}}};
|
||||
const current = {calls:0, scrollIntoView(){this.calls += 1}, classList:{add(){}}};
|
||||
const positioner = createPositioner({panel, jump});
|
||||
positioner.open('302');
|
||||
positioner.ready('301', stale);
|
||||
positioner.ready('302', current);
|
||||
process.stdout.write(JSON.stringify({stale:stale.calls, current:current.calls}));
|
||||
""")
|
||||
|
||||
assert result == {"stale": 0, "current": 1}
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_dashboard_mounts_mobile_new_activity_positioning_flow():
|
||||
html = await dashboard()
|
||||
|
||||
assert '<script src="static/update-read-position.js"></script>' in html
|
||||
assert 'id="jump-update-new-activity"' in html
|
||||
assert "updateReadPosition.open(String(item.notification_id))" in html
|
||||
assert "updateReadPosition.ready(String(selectedUpdate?.notification_id || ''), newest)" in html
|
||||
assert ".update-new-activity" in html
|
||||
assert "BASE + 'static/update-read-position.js'" in (POSITIONER.parent / "service-worker.js").read_text()
|
||||
Reference in new issue
Block a user