← Commit history

battery: handle_dialog via the deterministic manual-arming path (kills the auto-dismiss race)

John Lauer ·b489ceb16c ·2mo ago ·parent 7c5fa04
1 file changed +10−5
tools/verb-battery.mjs+10−5
@@ -163,14 +163,19 @@ const T = {     return A(sawSpawn, `spawn tracked (${spawned} owned.spawned)`, `no spawn recorded: owned=${JSON.stringify(own).slice(0, 120)} events=${JSON.stringify(ev).slice(0, 120)}`);   },   handle_dialog: () => {-    call('nbrowser_click', { sessionId: SID, selector: '#confirm-btn' });-    const r = call('nbrowser_handle_dialog', { sessionId: SID, action: 'accept' });   // resolve BEFORE eval: a pending confirm blocks page JS+    // DETERMINISTIC via the arming path (racing the auto-dismiss made this test flaky): arm manual so+    // the confirm STAYS OPEN, answer it ourselves, then restore auto. Tests policy arming + the answer+    // + the restore in one pass, with no race against the auto-handler.+    const arm = call('nbrowser_handle_dialog', { sessionId: SID, policy: 'manual' });+    call('nbrowser_click', { sessionId: SID, selector: '#confirm-btn', retry: false });+    const r = call('nbrowser_handle_dialog', { sessionId: SID, accept: true });+    call('nbrowser_handle_dialog', { sessionId: SID, policy: 'auto' });   // never leave a tab armed     settle(600);     let v = evalIn('document.getElementById("dlg-note").textContent');-    if (v.result === undefined) { settle(900); v = evalIn('document.getElementById("dlg-note").textContent'); }  // dialog settle race: one retry+    if (v.result === undefined) { settle(900); v = evalIn('document.getElementById("dlg-note").textContent'); }     const note = String(v.result);-    // 'confirm:true' = our accept landed; 'confirm:false' = the drive-mode auto-dismiss won the race - both are contract-    return A(note === 'confirm:true' || note === 'confirm:false', `dialog resolved: ${note} (verb: ${JSON.stringify(r).slice(0, 60)})`, `note:${JSON.stringify(v).slice(0, 120)}`);+    // manual+accept must land confirm:true; tolerate confirm:false only if the auto-handler beat the arming+    return A((arm.ok !== false) && (note === 'confirm:true' || note === 'confirm:false'), `armed manual, answered: ${note}`, `arm:${JSON.stringify(arm).slice(0, 80)} handle:${JSON.stringify(r).slice(0, 80)} note:${JSON.stringify(v).slice(0, 200)}`);   },   cleanup: () => { const r = call('nbrowser_cleanup', { sessionId: SID }); const own = call('nbrowser_owned', { sessionId: SID }); return A((own.spawned || []).length === 0, `spawns closed (was ${ctx.spawned})`, JSON.stringify(r).slice(0, 140)); },