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_review_lists_selected_blockers_in_filing_order(): script = f""" const createReview=require({json.dumps(str(MODULE))}); function target(){{const listeners={{}};return{{hidden:true,disabled:false,textContent:'',children:[],addEventListener:(n,f)=>listeners[n]=f,replaceChildren(...items){{this.children=items;}},focus(){{}}}};}} const blockerList=target(); const review=createReview({{sheet:target(),confirmButton:target(),backButton:target(),evidenceList:target(),blockerList, repository:target(),intent:target(),title:target(),body:target(),metadata:target(), document:{{createElement:()=>target(),addEventListener:()=>{{}}}},onConfirm:async()=>{{}}}}); review.open({{draft:{{repository:'o/r',title:'Blocked',blockers:[ {{repository:'o/api',number:7,title:'API ready'}},{{repository:'o/web',number:8,title:'Web ready'}} ]}},intent:'create-and-assign'}},target()); process.stdout.write(JSON.stringify(blockerList.children.map(item=>item.textContent))); """ assert run_node(script) == ["o/api #7 — API ready", "o/web #8 — Web ready"] def test_review_names_the_selected_initial_owner(): script = f""" const createReview=require({json.dumps(str(MODULE))}); function target(){{return{{hidden:true,disabled:false,textContent:'',addEventListener:()=>{{}},replaceChildren:()=>{{}},focus:()=>{{}}}};}} const metadata=target(); const review=createReview({{sheet:target(),confirmButton:target(),backButton:target(),evidenceList:target(), repository:target(),intent:target(),title:target(),body:target(),metadata, document:{{createElement:()=>target(),addEventListener:()=>{{}}}},onConfirm:async()=>{{}}}}); review.open({{draft:{{repository:'o/r',title:'Delegate',assignee:'alex',assigneeName:'Alex'}},intent:'create-and-assign'}},target()); process.stdout.write(JSON.stringify({{metadata:metadata.textContent}})); """ assert run_node(script)["metadata"].endswith("Owner: Alex (@alex)") def test_review_names_the_repository_issue_type(): script = f""" const createReview=require({json.dumps(str(MODULE))}); function target(){{return{{hidden:true,disabled:false,textContent:'',addEventListener:()=>{{}},replaceChildren:()=>{{}},focus:()=>{{}}}};}} const issueType=target(); const review=createReview({{sheet:target(),confirmButton:target(),backButton:target(),evidenceList:target(), repository:target(),intent:target(),title:target(),body:target(),metadata:target(),issueType, document:{{createElement:()=>target(),addEventListener:()=>{{}}}},onConfirm:async()=>{{}}}}); review.open({{draft:{{repository:'o/r',title:'Crash',templateName:'Bug report'}},intent:'create-and-assign'}},target()); process.stdout.write(JSON.stringify({{issueType:issueType.textContent}})); """ assert run_node(script)["issueType"] == "Bug report" def test_create_and_start_review_shows_estimate_and_projected_capacity(): script = f""" const createReview=require({json.dumps(str(MODULE))}); function target(){{return{{hidden:true,disabled:false,textContent:'',addEventListener:()=>{{}},replaceChildren:()=>{{}},focus:()=>{{}}}};}} const metadata=target(); const review=createReview({{sheet:target(),confirmButton:target(),backButton:target(),evidenceList:target(), repository:target(),intent:target(),title:target(),body:target(),metadata, document:{{createElement:()=>target(),addEventListener:()=>{{}}}},onConfirm:async()=>{{}}}}); review.open({{draft:{{repository:'o/r',title:'Sized work',estimateMinutes:45, todayCapacity:{{remainingMinutes:60,projectedMinutes:15}}}},intent:'create-and-start'}},target()); process.stdout.write(JSON.stringify({{metadata:metadata.textContent}})); """ metadata = run_node(script)["metadata"] assert "Estimate: 45 min" in metadata assert "Today after start: 15 min free" in metadata 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_review_renders_exact_evidence_bytes_and_selects_the_preview(): script = f""" const createReview = require({json.dumps(str(MODULE))}); function target(tag='div') {{ const listeners={{}}, attributes={{}}; return {{tag,hidden:true,disabled:false,textContent:'',children:[],src:'',alt:'', addEventListener:(name,fn)=>listeners[name]=fn, dispatch:(name,event={{}})=>listeners[name]?.({{preventDefault(){{}},currentTarget:this,...event}}), replaceChildren(...items){{this.children=items;}}, appendChild(item){{this.children.push(item);}}, setAttribute(name,value){{attributes[name]=String(value);}}, getAttribute:name=>attributes[name], focus(){{this.focused=true;}}}}; }} const documentRef={{createElement:tag=>target(tag),addEventListener:()=>{{}}}}; const evidence=target(), preview=target(), image=target('img'); const position=target(), filename=target(), note=target(), empty=target(); const created=[]; const review=createReview({{ sheet:target(),confirmButton:target(),backButton:target(),evidenceList:evidence, evidencePreview:preview,evidenceImage:image,evidencePosition:position, evidenceFilename:filename,evidenceNote:note,evidenceEmpty:empty, repository:target(),intent:target(),title:target(),body:target(),metadata:target(), document:documentRef,createObjectURL:blob=>{{const url='blob:review-'+blob.size;created.push(url);return url;}}, revokeObjectURL:()=>{{}},onConfirm:async()=>{{}}, }}); review.open({{draft:{{repository:'o/r',title:'Privacy check',attachments:[ {{filename:'redacted.png',contentType:'image/png',blob:new Blob(['flattened-redaction']),note:'Secrets hidden'}}, {{filename:'legacy.webp',contentType:'image/webp',data:'bGVnYWN5',note:'Expected result'}} ]}},intent:'create-and-assign'}},target()); const firstButton=evidence.children[0].children[0]; const secondButton=evidence.children[1].children[0]; secondButton.dispatch('click'); process.stdout.write(JSON.stringify({{ created,thumbnailSources:[firstButton.children[0].src,secondButton.children[0].src], labels:[firstButton.getAttribute('aria-label'),secondButton.getAttribute('aria-label')], selected:[firstButton.getAttribute('aria-pressed'),secondButton.getAttribute('aria-pressed')], preview:{{hidden:preview.hidden,src:image.src,alt:image.alt,position:position.textContent, filename:filename.textContent,note:note.textContent}},emptyHidden:empty.hidden, }})); """ result = run_node(script) assert result == { "created": ["blob:review-19"], "thumbnailSources": [ "blob:review-19", "data:image/webp;base64,bGVnYWN5", ], "labels": [ "Preview evidence 1 of 2: redacted.png", "Preview evidence 2 of 2: legacy.webp", ], "selected": ["false", "true"], "preview": { "hidden": False, "src": "data:image/webp;base64,bGVnYWN5", "alt": "Evidence 2 of 2: legacy.webp", "position": "Evidence 2 of 2", "filename": "legacy.webp", "note": "Expected result", }, "emptyHidden": True, } def test_failed_filing_keeps_preview_and_success_releases_blob_url_once(): script = f""" const createReview = require({json.dumps(str(MODULE))}); function target() {{ const listeners={{}}; return {{hidden:true,disabled:false,textContent:'',children:[],src:'',alt:'', addEventListener:(name,fn)=>listeners[name]=fn, dispatch:(name,event={{}})=>listeners[name]?.({{preventDefault(){{}},...event}}), replaceChildren(...items){{this.children=items;}},appendChild(item){{this.children.push(item);}}, setAttribute(){{}},focus(){{this.focused=true;}}}}; }} const documentRef={{createElement:()=>target(),addEventListener:()=>{{}}}}; const sheet=target(), confirm=target(), trigger=target(), image=target(), preview=target(); const revoked=[]; let attempts=0; const review=createReview({{ sheet,confirmButton:confirm,backButton:target(),evidenceList:target(),evidencePreview:preview, evidenceImage:image,evidencePosition:target(),evidenceFilename:target(),evidenceNote:target(),evidenceEmpty:target(), repository:target(),intent:target(),title:target(),body:target(),metadata:target(),status:target(), document:documentRef,createObjectURL:blob=>'blob:attempt-'+blob.size, revokeObjectURL:url=>revoked.push(url), onConfirm:async()=>{{attempts+=1;if(attempts===1)throw new Error('Network unavailable');}}, }}); review.open({{draft:{{repository:'o/r',title:'Verify',attachment:{{filename:'one.png',blob:new Blob(['one'])}}}},intent:'create-and-assign'}},trigger); confirm.dispatch('click'); setImmediate(()=>{{ const afterFailure={{hidden:sheet.hidden,previewHidden:preview.hidden,src:image.src,disabled:confirm.disabled,revoked:[...revoked]}}; confirm.dispatch('click'); setImmediate(()=>process.stdout.write(JSON.stringify({{ attempts,afterFailure,afterSuccess:{{hidden:sheet.hidden,triggerFocused:trigger.focused||false,revoked}} }}))); }}); """ assert run_node(script) == { "attempts": 2, "afterFailure": { "hidden": False, "previewHidden": False, "src": "blob:attempt-3", "disabled": False, "revoked": [], }, "afterSuccess": { "hidden": True, "triggerFocused": True, "revoked": ["blob:attempt-3"], }, } 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="issue-filing-review-evidence-empty"' in html assert 'id="issue-filing-review-evidence-preview"' in html assert 'id="issue-filing-review-evidence-image"' in html assert 'id="issue-filing-review-evidence-position"' in html assert 'id="issue-filing-review-evidence-filename"' in html assert 'id="issue-filing-review-evidence-note"' 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 "evidencePreview: qs('#issue-filing-review-evidence-preview')" in dashboard assert "evidenceImage: qs('#issue-filing-review-evidence-image')" in dashboard assert "createObjectURL: blob => URL.createObjectURL(blob)" in dashboard assert "revokeObjectURL: url => URL.revokeObjectURL(url)" 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 ".issue-filing-evidence-preview" in css assert ".issue-filing-evidence-selector" in css assert "min-height:44px" in css.split(".issue-filing-evidence-selector", 1)[1] 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]