117 lines
4.3 KiB
Python
117 lines
4.3 KiB
Python
import json
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from tests.dashboard_bundle import dashboard
|
|
|
|
|
|
SESSION = Path(__file__).resolve().parents[1] / "frontend" / "update-triage-session.js"
|
|
|
|
|
|
def run_session(script):
|
|
source = f"const createSession = require({json.dumps(str(SESSION))});\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_update_triage_persists_account_bound_pass_and_resumes_by_identity():
|
|
result = run_session("""
|
|
const values = new Map();
|
|
let login = 'timmy';
|
|
let items = [1,2,3].map(id => ({notification_id:id,title:'Update '+id}));
|
|
const opened = [], progress = [];
|
|
const options = {
|
|
storage:{getItem:key=>values.get(key)||null,setItem:(key,value)=>values.set(key,value),removeItem:key=>values.delete(key)},
|
|
getLogin:()=>login, getItems:()=>items,
|
|
onOpen:item=>opened.push(item.notification_id), onProgress:value=>progress.push(value), onFinish:()=>opened.push('done'),
|
|
};
|
|
let session = createSession(options);
|
|
session.start();
|
|
session.keepUnreadAndNext();
|
|
const saved = JSON.parse(values.get('stackchain.update-triage.v1'));
|
|
session = createSession(options);
|
|
const resumable = session.resumable();
|
|
session.resume();
|
|
login = 'other';
|
|
const isolated = session.resumable();
|
|
process.stdout.write(JSON.stringify({opened, progress, saved, resumable, isolated}));
|
|
""")
|
|
|
|
assert result["opened"] == [1, 2, 2]
|
|
assert result["progress"] == [
|
|
{"index": 1, "total": 3},
|
|
{"index": 2, "total": 3},
|
|
{"index": 2, "total": 3},
|
|
]
|
|
assert result["saved"] == {
|
|
"version": 1,
|
|
"login": "timmy",
|
|
"identities": ["1", "2", "3"],
|
|
"current": "2",
|
|
"completed": ["1"],
|
|
}
|
|
assert result["resumable"] is True
|
|
assert result["isolated"] is False
|
|
|
|
|
|
def test_update_triage_reconciles_removed_items_and_does_not_admit_new_arrivals():
|
|
result = run_session("""
|
|
const values = new Map();
|
|
let items = [1,2,3].map(notification_id => ({notification_id}));
|
|
const opened = [], progress = [];
|
|
const session = createSession({
|
|
storage:{getItem:key=>values.get(key)||null,setItem:(key,value)=>values.set(key,value),removeItem:key=>values.delete(key)},
|
|
getLogin:()=> 'timmy', getItems:()=>items,
|
|
onOpen:item=>opened.push(item.notification_id), onProgress:value=>progress.push(value), onFinish:()=>opened.push('done'),
|
|
});
|
|
session.start();
|
|
items = [1,3,4].map(notification_id => ({notification_id}));
|
|
session.completeAndNext();
|
|
session.completeAndNext();
|
|
process.stdout.write(JSON.stringify({opened, progress, stored:values.get('stackchain.update-triage.v1') || null}));
|
|
""")
|
|
|
|
assert result == {
|
|
"opened": [1, 3, "done"],
|
|
"progress": [{"index": 1, "total": 3}, {"index": 3, "total": 3}],
|
|
"stored": None,
|
|
}
|
|
|
|
|
|
def test_update_triage_exposes_only_the_next_surviving_snapshot_item():
|
|
result = run_session("""
|
|
const values = new Map();
|
|
let items = [1,2,3].map(notification_id => ({notification_id}));
|
|
const session = createSession({
|
|
storage:{getItem:key=>values.get(key)||null,setItem:(key,value)=>values.set(key,value),removeItem:key=>values.delete(key)},
|
|
getLogin:()=> 'timmy', getItems:()=>items,
|
|
onOpen:()=>{}, onProgress:()=>{}, onFinish:()=>{},
|
|
});
|
|
session.start();
|
|
const first = session.next()?.notification_id;
|
|
items = [1,3,4].map(notification_id => ({notification_id}));
|
|
const afterRemoval = session.next()?.notification_id;
|
|
session.keepUnreadAndNext();
|
|
const afterAdvance = session.next();
|
|
process.stdout.write(JSON.stringify({first, afterRemoval, afterAdvance:afterAdvance || null}));
|
|
""")
|
|
|
|
assert result == {"first": 2, "afterRemoval": 3, "afterAdvance": None}
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_dashboard_wires_resumable_updates_triage_mobile_flow():
|
|
html = await dashboard()
|
|
|
|
assert '<script src="static/update-triage-session.js"></script>' in html
|
|
assert 'id="update-triage-progress"' in html
|
|
assert 'id="keep-update-unread" type="button" aria-label="Keep unread and open next update">Keep unread</button>' in html
|
|
assert "openUpdates: openUpdateTriage" in html
|
|
assert "updateTriage.acceptCompleted()" in html
|
|
assert "updateTriage.keepUnreadAndNext()" in html
|
|
assert "updateTriage.reconcile()" in html
|
|
assert ".update-triage-progress" in html
|