stackchain-dashboard/tests/test_today_handoff.py
timmy 468676d2f4
All checks were successful
CI / lint (pull_request) Successful in 2m56s
CI / build-release (pull_request) Successful in 6s
CI / browser-journey (pull_request) Successful in 1m50s
CI / release-candidate (pull_request) Has been skipped
feat: review wrap-up commitments in Today (Closes #992)
2026-08-16 23:15:00 +00:00

85 lines
4.0 KiB
Python

import json
import subprocess
from pathlib import Path
HANDOFF = Path(__file__).parents[1] / "frontend" / "today-handoff.js"
def run_node(script: str):
result = subprocess.run(["node", "-e", script], capture_output=True, text=True)
assert result.returncode == 0, result.stderr
return json.loads(result.stdout)
def test_due_wrap_up_commitments_are_reviewed_in_order_and_added_durably():
script = f"""
const createHandoff=require({json.dumps(str(HANDOFF))});
const values=new Map();
const storage={{getItem:k=>values.get(k)||null,setItem:(k,v)=>values.set(k,v),removeItem:k=>values.delete(k)}};
const items=[
{{kind:'issue',repository:'r',number:2,title:'Second'}},
{{kind:'issue',repository:'r',number:1,title:'First'}},
];
const identity=item=>'issue:'+item.repository+':'+item.number+':';
const today=[]; const operations=[];
const controller=createHandoff({{
storage,getLogin:()=> 'timmy',identity,
todayWork:{{contains:item=>today.includes(identity(item)),add:item=>{{if(today.length>=1)return 'full';today.push(identity(item));return 'added';}}}},
todaySync:{{enqueue:(action,id)=>{{operations.push([action,id]);return true;}},flush:async()=>true}},
}});
controller.capture(['issue:r:1:','issue:r:2:','issue:r:1:']);
const review=controller.review(items);
controller.choose('issue:r:2:',false);
const first=await controller.commit(items);
controller.choose('issue:r:2:',true);
const blocked=await controller.commit(items);
process.stdout.write(JSON.stringify({{review,first,blocked,today,operations,pending:controller.pending()}}));
"""
result = run_node(f"(async()=>{{{script}}})().catch(error=>{{console.error(error);process.exit(1);}})")
assert [row["identity"] for row in result["review"]] == ["issue:r:1:", "issue:r:2:"]
assert all(row["selected"] for row in result["review"])
assert result["first"] == {"scheduled": 1, "blocked": 0, "remaining": 1}
assert result["blocked"] == {"scheduled": 0, "blocked": 1, "remaining": 1}
assert result["today"] == ["issue:r:1:"]
assert result["operations"] == [["add", "issue:r:1:"]]
assert result["pending"] == ["issue:r:2:"]
def test_handoff_pending_state_is_account_scoped_and_capture_is_idempotent():
script = f"""
const createHandoff=require({json.dumps(str(HANDOFF))});
const values=new Map();let login='timmy';
const storage={{getItem:k=>values.get(k)||null,setItem:(k,v)=>values.set(k,v),removeItem:k=>values.delete(k)}};
const options={{storage,getLogin:()=>login,identity:item=>item.id,todayWork:{{contains:()=>false,add:()=> 'added'}},todaySync:{{enqueue:()=>true,flush:async()=>true}}}};
const controller=createHandoff(options);
controller.capture(['one','two']);controller.capture(['two','one']);
const timmy=controller.pending();login='alexander';const isolated=controller.pending();
login='timmy';const resumed=createHandoff(options).pending();
process.stdout.write(JSON.stringify({{timmy,isolated,resumed}}));
"""
assert run_node(f"(async()=>{{{script}}})()") == {
"timmy": ["one", "two"], "isolated": [], "resumed": ["one", "two"],
}
def test_dashboard_packages_accessible_mobile_commitment_review_and_account_sync():
from src import main
html = main.FRONTEND_BUILD.dashboard_html
dashboard = (HANDOFF.parents[0] / "dashboard.js").read_text()
css = (HANDOFF.parents[0] / "dashboard.css").read_text()
service_worker = (HANDOFF.parents[0] / "service-worker.js").read_text()
assert 'id="today-handoff-dialog"' in html
assert 'aria-labelledby="today-handoff-title"' in html
assert 'id="today-handoff-items"' in html
assert 'id="confirm-today-handoff"' in html
assert '<script src="static/today-handoff.js"></script>' in (HANDOFF.parents[0] / "index.html").read_text()
assert "createTodayHandoff({" in dashboard
assert "laterSync.enqueue(action, itemId, wakeAt, handoff)" in dashboard
assert "todayHandoff.capture(handoffs)" in dashboard
assert ".today-handoff-actions button { min-height:44px;" in css
assert "BASE + 'static/today-handoff.js'" in service_worker
assert "static/today-handoff.js" in main.FRONTEND_BUILD.page_sources