From de159bc12207d83dda3d97a857c7a0a622419f27 Mon Sep 17 00:00:00 2001 From: "prompt.ac/@jeffrey" Date: Thu, 17 Sep 2026 15:44:40 -0700 Subject: [PATCH] Fix duplicated Chrome consent and late inspection races --- slab/captutor/lib/modal-police.mjs | 13 +++++++++---- slab/captutor/test/modal-police.test.mjs | 2 ++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/slab/captutor/lib/modal-police.mjs b/slab/captutor/lib/modal-police.mjs index 0eb342913b..b88b177fc0 100644 --- a/slab/captutor/lib/modal-police.mjs +++ b/slab/captutor/lib/modal-police.mjs @@ -31,12 +31,16 @@ function walk(e,depth){ } return {texts,buttons,modal}; } -for(const w of chrome.windows())walk(w,0); +let windowIndex=0; +for(const w of chrome.windows()){const start=hits.length;walk(w,0);for(const h of hits.slice(start))h.windowIndex=windowIndex;windowIndex++;} // Chrome may expose the same sheet both below its window and as a window. -const uniqueHits=[];const seen=new Set(); +const uniqueHits=[];const seen=new Set(),physical=new Set(); for(const h of hits){let position=null;try{position=h.element.position();}catch{} - const key=JSON.stringify([h.kind,h.title,h.buttons,position]); - if(!seen.has(key)){seen.add(key);uniqueHits.push(h);} + // Chrome can report duplicate sheet positions during a native relayout. + const key=JSON.stringify([h.windowIndex,h.kind,h.title,h.buttons,h.kind==='remote-debugging'?null:position]); + const physicalKey=JSON.stringify([h.kind,h.title,h.buttons,position]); + if(!seen.has(key)&&!physical.has(physicalKey))uniqueHits.push(h); + seen.add(key);physical.add(physicalKey); } `; async function native(action,expected) { @@ -64,6 +68,7 @@ export function createModalPolice({ if(!['connecting','preparing','recording'].includes(phase))throw Error('Unknown modal-police phase'); let hits; try{hits=await scan();}catch(error){emit({type:'blocked',kind:'inspection-failed',at:new Date().toISOString()});throw error;} + if(!mayHandle())return {checkedAt:new Date().toISOString(),modals:hits.length,expired:true}; const seen=new Set();let blocked; for(const hit of hits){ const id=fingerprintModal(hit);seen.add(id); diff --git a/slab/captutor/test/modal-police.test.mjs b/slab/captutor/test/modal-police.test.mjs index 1f6298da8a..0b51418ab9 100644 --- a/slab/captutor/test/modal-police.test.mjs +++ b/slab/captutor/test/modal-police.test.mjs @@ -59,3 +59,5 @@ test('connection watcher rescans a moved consent dialog instead of abandoning it let checks=0;const result=await connectWithModalPolice(async()=>{await new Promise(r=>setTimeout(r,20));return 'connected';},{intervalMs:1,police:{check:async()=>{if(++checks===1)throw Error('Modal changed or action ambiguous');}}}); assert.equal(result,'connected');assert.ok(checks>1); }); + +test('a connection settled during native scan does not fail or click',async t=>{let pending=true;const f=setup(t,'automation-banner',{scan:async()=>{pending=false;return [hit('automation-banner')];}});assert.equal((await f.police.check('connecting',{mayHandle:()=>pending})).expired,true);assert.deepEqual(f.actions,[]);}); -- 2.51.2