import json import subprocess from pathlib import Path MODULE = Path(__file__).parents[1] / "frontend" / "issue-filing-review.js" def run_node(script: str) -> dict: completed = subprocess.run( ["node", "-e", script], capture_output=True, text=True, check=True ) return json.loads(completed.stdout) def test_review_requires_one_confirmation_and_preserves_the_reviewed_payload(): script = f""" const createReview = require({json.dumps(str(MODULE))}); function target() {{ const listeners = {{}}; return {{ disabled:false, hidden:true, textContent:'', children:[], addEventListener:(name, fn)=>listeners[name]=fn, dispatch:(name, event={{}})=>listeners[name]?.({{preventDefault(){{}}, ...event}}), focus(){{this.focused=true;}}, replaceChildren(...items){{this.children=items;}}, setAttribute(){{}}, appendChild(item){{this.children.push(item);}}, }}; }} const sheet=target(), confirm=target(), back=target(), trigger=target(), evidence=target(); const documentRef={{ createElement:tag=>({{tag, textContent:'', children:[], appendChild(item){{this.children.push(item);}}}}), addEventListener:()=>{{}}, }}; const admitted=[]; const review=createReview({{ sheet, confirmButton:confirm, backButton:back, evidenceList:evidence, repository:target(), intent:target(), title:target(), body:target(), metadata:target(), document:documentRef, onConfirm:async payload=>{{ admitted.push(payload); return {{ok:true}}; }}, }}); const payload={{ draft:{{repository:'stackchain/dashboard',title:'Ship it',body:'Full note',labels:['P1'], milestone:{{title:'Sprint'}},dueDate:'2026-08-20',attachments:[ {{filename:'first.png',note:'Before'}},{{filename:'second.png',note:'After'}} ]}}, intent:'create-and-start', }}; review.open(payload, trigger); payload.draft.title='Mutated outside'; confirm.dispatch('click'); confirm.dispatch('click'); setImmediate(()=>process.stdout.write(JSON.stringify({{ admissions:admitted.length, reviewedTitle:admitted[0].draft.title, evidence:evidence.children.map(item=>item.textContent), hidden:sheet.hidden, triggerFocused:trigger.focused || false, }}))); """ result = run_node(script) assert result == { "admissions": 1, "reviewedTitle": "Ship it", "evidence": ["1. first.png — Before", "2. second.png — After"], "hidden": True, "triggerFocused": True, } def test_escape_returns_to_the_unchanged_issue_form(): script = f""" const createReview = require({json.dumps(str(MODULE))}); function target() {{ const listeners={{}}; return {{hidden:true,disabled:false,textContent:'',children:[], addEventListener:(name,fn)=>listeners[name]=fn, replaceChildren(...items){{this.children=items;}}, focus(){{this.focused=true;}}, dispatch:(name,event)=>listeners[name]?.(event)}}; }} const listeners={{}}, documentRef={{ createElement:()=>({{textContent:''}}), addEventListener:(name,fn)=>listeners[name]=fn, dispatch:(name,event)=>listeners[name]?.(event), }}; const sheet=target(), trigger=target(); const review=createReview({{ sheet,confirmButton:target(),backButton:target(),evidenceList:target(), repository:target(),intent:target(),title:target(),body:target(),metadata:target(), document:documentRef,onConfirm:async()=>{{}}, }}); const payload={{draft:{{repository:'o/r',title:'Original',body:'Note'}},intent:'create-and-assign'}}; review.open(payload,trigger); documentRef.dispatch('keydown',{{key:'Escape',preventDefault(){{this.prevented=true;}}}}); process.stdout.write(JSON.stringify({{hidden:sheet.hidden,focused:trigger.focused||false,title:payload.draft.title}})); """ assert run_node(script) == {"hidden": True, "focused": True, "title": "Original"} def test_create_actions_review_the_complete_payload_before_durable_admission(): root = Path(__file__).parents[1] html = (root / "frontend" / "index.html").read_text() dashboard = (root / "frontend" / "dashboard.js").read_text() css = (root / "frontend" / "dashboard.css").read_text() bundle = (root / "src" / "frontend_bundle.py").read_text() assert 'id="issue-filing-review" role="dialog" aria-modal="true"' in html assert 'id="issue-filing-review-repository"' in html assert 'id="issue-filing-review-intent"' in html assert 'id="issue-filing-review-title"' in html assert 'id="issue-filing-review-body"' in html assert 'id="issue-filing-review-evidence"' in html assert 'id="back-to-issue-edit"' in html assert 'id="confirm-issue-filing"' in html assert '' in html submit_handler = dashboard.split( "qs('#create-issue-form').addEventListener('submit'", 1 )[1].split("qs('#close-issue-sheet').addEventListener", 1)[0] assert "filingReview.open" in submit_handler assert "issueOutbox.enqueueDurably" not in submit_handler assert "async function admitReviewedIssue" in dashboard assert "issueOutbox.enqueueDurably" in dashboard.split( "async function admitReviewedIssue", 1 )[1].split("qs('#create-issue-form').addEventListener", 1)[0] assert ".issue-filing-review" in css assert "max-height:100dvh" in css assert "overflow-x:hidden" in css assert "env(safe-area-inset-bottom)" in css assert '"static/issue-filing-review.js"' in bundle def test_duplicate_acknowledgement_preserves_the_selected_filing_intent(): dashboard = (Path(__file__).parents[1] / "frontend" / "dashboard.js").read_text() assert "let pendingIssueFilingIntent = 'create-and-assign';" in dashboard assert "if (event.submitter) pendingIssueFilingIntent" in dashboard assert "const intent = pendingIssueFilingIntent;" in dashboard assert "pendingIssueFilingIntent = 'create-and-assign';" in dashboard.split( "async function admitReviewedIssue", 1 )[1].split("qs('#create-issue-form').addEventListener", 1)[0]