79 lines
3.0 KiB
Python
79 lines
3.0 KiB
Python
import json
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from tests.dashboard_bundle import dashboard
|
|
|
|
|
|
MODULE = Path(__file__).parents[1] / "frontend" / "offline-issue-blocker.js"
|
|
|
|
|
|
def run_node(script: str):
|
|
completed = subprocess.run(["node", "-e", script], check=True, capture_output=True, text=True)
|
|
return json.loads(completed.stdout)
|
|
|
|
|
|
def test_offline_blocker_reports_queued_only_after_durable_admission():
|
|
script = f"""
|
|
const createOfflineIssueBlocker=require({json.dumps(str(MODULE))});
|
|
const events=[];
|
|
const queue=createOfflineIssueBlocker({{
|
|
createOperationId:()=> 'blocker-op',
|
|
enqueueDurably:async message=>{{events.push(['admit',message]);return{{item:message,durability:'background'}};}},
|
|
onQueued:(item,blocker,present,admission)=>events.push(['queued',item.number,blocker.number,present,admission.durability]),
|
|
}});
|
|
(async()=>{{
|
|
const result=await queue(
|
|
{{repository:'stackchain/dashboard',number:17}},
|
|
{{repository:'stackchain/api',number:9,title:'Restore API'}},
|
|
false
|
|
);
|
|
process.stdout.write(JSON.stringify({{events,result}}));
|
|
}})();
|
|
"""
|
|
output = run_node(script)
|
|
|
|
assert output["events"] == [
|
|
["admit", {
|
|
"kind": "issue-blocker", "repository": "stackchain/dashboard", "number": 17,
|
|
"blockerRepository": "stackchain/api", "blockerNumber": 9,
|
|
"present": False, "operationId": "blocker-op",
|
|
}],
|
|
["queued", 17, 9, False, "background"],
|
|
]
|
|
assert output["result"]["admission"]["durability"] == "background"
|
|
|
|
|
|
def test_offline_blocker_does_not_report_queued_when_durable_admission_fails():
|
|
script = f"""
|
|
const createOfflineIssueBlocker=require({json.dumps(str(MODULE))});
|
|
let queued=false;
|
|
const queue=createOfflineIssueBlocker({{
|
|
enqueueDurably:async()=>{{throw new Error('IndexedDB unavailable');}},
|
|
onQueued:()=>queued=true,
|
|
}});
|
|
queue({{repository:'o/r',number:1}},{{repository:'o/b',number:2}},true)
|
|
.then(()=>process.stdout.write(JSON.stringify({{queued}})))
|
|
.catch(error=>process.stdout.write(JSON.stringify({{queued,error:error.message}})));
|
|
"""
|
|
output = run_node(script)
|
|
|
|
assert output == {"queued": False, "error": "IndexedDB unavailable"}
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_saved_issue_exposes_offline_blocker_queue_in_mobile_sheet():
|
|
html = await dashboard()
|
|
dashboard_js = (MODULE.parent / "dashboard.js").read_text()
|
|
service_worker = (MODULE.parent / "service-worker.js").read_text()
|
|
|
|
assert '<script src="static/offline-issue-blocker.js"></script>' in html
|
|
assert "BASE + 'static/offline-issue-blocker.js'" in service_worker
|
|
assert "const queueOfflineIssueBlocker = createOfflineIssueBlocker({" in dashboard_js
|
|
assert "qs('#manage-issue-blockers').hidden = !assignedIssue;" in dashboard_js
|
|
assert "await queueOfflineIssueBlocker(item, blocker, !remove);" in dashboard_js
|
|
assert "Blocker removal queued. Today remains blocked until Stackchain confirms delivery." in dashboard_js
|
|
assert "const candidates = selectedIssueOffline ? workSession.items()" in dashboard_js
|