Files
Endoleap/tests/headless/cdp-client.mjs

21 lines
1.5 KiB
JavaScript

/** Bounded protocol calls for isolated browser fixtures, never product code. */
export function createCdpCalls(socket,{timeoutMs=30000,onEvent=()=>{},setTimer=setTimeout,clearTimer=clearTimeout}={}){
let serial=0,failure;const pending=new Map();
const fail=error=>{failure??=error;for(const row of pending.values()){clearTimer(row.timer);row.reject(failure);}pending.clear();};
socket.addEventListener('close',()=>fail(Error('CDP connection closed')));
socket.addEventListener('error',()=>fail(Error('CDP connection failed')));
socket.addEventListener('message',event=>{
try{
const message=JSON.parse(event.data);
if(!message.id){onEvent(message);if(['Inspector.targetCrashed','Inspector.detached','Target.targetCrashed','Page.javascriptDialogOpening'].includes(message.method))fail(Error('CDP target unavailable: '+message.method+' '+JSON.stringify(message.params??{})));return;}
const row=pending.get(message.id);if(!row)return;pending.delete(message.id);clearTimer(row.timer);message.error?row.reject(Error(JSON.stringify(message.error))):row.resolve(message.result);
}catch(error){fail(error);}
});
return(method,params={})=>new Promise((resolve,reject)=>{
if(failure){reject(failure);return;}
const id=++serial,row={resolve,reject,timer:undefined};pending.set(id,row);
row.timer=setTimer(()=>fail(Error(`CDP ${method} timed out after ${timeoutMs}ms`)),timeoutMs);
try{socket.send(JSON.stringify({id,method,params}));}catch(error){fail(error);}
});
}