import { ChromiumBrowserContext , Page } from 'playwright' ; import debugFactory from 'debug' ; const debug = debugFactory ( 'element:network:recorder' ) ; interface RequestEvent { requestId : string ; } interface Event extends RequestEvent { request : { url : string ; } ; type : string ; frameId : string ; redirectResponse : any ; } export class Manager { private lifecycleCompleteCallback : ( ( value : unknown ) => void ) | null ; private networkIdlePromise : Promise < any > | null ; public timeout = 10e3 ; constructor ( private page , private requestIdToRequest = new Map < string , any > ( ) ) { } public async getIdlePromise ( ) { console . log ( 'get idle promise' ) ; this . createIdlePromise ( ) ; return this . networkIdlePromise ; } public get pendingRequestCount ( ) : number { return this . requestIdToRequest . size ; } private updateIdlePromise ( ) { if ( this . pendingRequestCount <= 2 && this . lifecycleCompleteCallback ) { this . lifecycleCompleteCallback . apply ( this ) ; this . networkIdlePromise = null ; this . lifecycleCompleteCallback = null ; console . log ( `Idle promise callback fired` ) ; } } private createTimeoutPromise ( ) { return new Promise ( ( fulfill ) => setTimeout ( fulfill , this . timeout ) ) ; } private createIdlePromise ( ) { if ( this . lifecycleCompleteCallback ) return ; if ( this . networkIdlePromise ) return ; const lifecycleCompletePromise = new Promise ( ( fulfill ) => { this . lifecycleCompleteCallback = fulfill ; } ) ; this . networkIdlePromise = Promise . race ( [ lifecycleCompletePromise , this . createTimeoutPromise ( ) ] ) ; this . updateIdlePromise ( ) ; } public async attachEvents ( ) { try { const browserContext = ( await this . page . context ( ) ) as ChromiumBrowserContext ; const client = await browserContext . newCDPSession ( this . page ) ; if ( client ) { await client . send ( 'Network.enable' ) ; client . on ( 'Network.requestWillBeSent' , this . onRequestWillBeSent . bind ( this ) ) ; client . on ( 'Network.requestIntercepted' , this . onRequestIntercepted . bind ( this ) ) ; client . on ( 'Network.responseReceived' , this . onResponseReceived . bind ( this ) ) ; client . on ( 'Network.loadingFinished' , this . onLoadingFinished . bind ( this ) ) ; client . on ( 'Network.loadingFailed' , this . onLoadingFailed . bind ( this ) ) ; } } catch ( err ) { debug ( err ) ; } } private onRequestWillBeSent ( event ) { this . handleRequestStart ( event . requestId , event . request . url , event . type , event . request , event . frameId ) ; } private handleRequestStart ( requestId , _url , _resourceType , _requestPayload , _frameId ) { if ( requestId ) this . requestIdToRequest . set ( requestId , null ) ; } private onRequestIntercepted ( ) { console . log ( 'RequestIntercepted' ) ; this . updateIdlePromise ( ) ; } private onResponseReceived ( ) { this . updateIdlePromise ( ) ; } private onLoadingFinished ( event ) { this . requestIdToRequest . delete ( event . requestId ) ; this . updateIdlePromise ( ) ; } private onLoadingFailed ( event ) { const request = this . requestIdToRequest . get ( event . requestId ) ; if ( ! request ) return ; this . requestIdToRequest . delete ( event . requestId ) ; this . updateIdlePromise ( ) ; } }