@@ -610,6 +610,7 @@ final class LinuxBrowserSession: @unchecked Sendable {
610610 let diagnostics = QADiagnosticStore ( )
611611 private let diagnosticsLock = NSLock ( )
612612 private var requestContexts : [ String : ( method: String ? , url: String ? , headers: [ String : String ] ) ] = [ : ]
613+ private let networkIdleTracker = NetworkIdleTracker ( )
613614 private let recordingLock = NSLock ( )
614615 private var recordingPausedUntil = Date . distantPast
615616 private let navigationLock = NSLock ( )
@@ -827,6 +828,8 @@ final class LinuxBrowserSession: @unchecked Sendable {
827828 let expectedURL = parameters [ " url " ] ? . stringValue
828829 let expectedText = parameters [ " text " ] ? . stringValue
829830 let requireSettled = parameters [ " settled " ] ? . boolValue ?? false
831+ let requireNetworkIdle = parameters [ " networkIdle " ] ? . boolValue ?? false
832+ let networkWaitStartedAt = networkIdleTracker. beginWait ( )
830833 let deadline = Date ( ) . addingTimeInterval ( timeoutMs / 1_000 )
831834 var state : JSONValue = . object( [ : ] )
832835 repeat {
@@ -846,7 +849,10 @@ final class LinuxBrowserSession: @unchecked Sendable {
846849 let ready = object [ " readyState " ] ? . stringValue == " complete "
847850 let animations = object [ " runningAnimations " ] ? . numberValue ?? 0
848851 let quiet = object [ " mutationQuietMs " ] ? . numberValue ?? 0
849- if urlMatches && textMatches && ( !requireSettled || ( ready && animations == 0 && quiet >= 300 ) ) { return state }
852+ let settled = !requireSettled || ( ready && animations == 0 && quiet >= 300 )
853+ let networkIdle = !requireNetworkIdle
854+ || networkIdleTracker. snapshot ( since: networkWaitStartedAt) . isIdle
855+ if urlMatches && textMatches && settled && networkIdle { return state }
850856 Thread . sleep ( forTimeInterval: 0.05 )
851857 } while Date ( ) < deadline
852858 throw CDPError . timedOut
@@ -1190,6 +1196,10 @@ final class LinuxBrowserSession: @unchecked Sendable {
11901196 case " Network.requestWillBeSent " :
11911197 guard let requestID = parameters [ " requestId " ] as? String ,
11921198 let request = parameters [ " request " ] as? [ String : Any ] else { return }
1199+ networkIdleTracker. requestDidStart (
1200+ identifier: requestID,
1201+ resourceType: parameters [ " type " ] as? String
1202+ )
11931203 diagnosticsLock. lock ( )
11941204 requestContexts [ requestID] = (
11951205 request [ " method " ] as? String ,
@@ -1207,12 +1217,14 @@ final class LinuxBrowserSession: @unchecked Sendable {
12071217 responseHeaders: stringHeaders ( response [ " headers " ] as? [ String : Any ] ) , source: " chromium-cdp " )
12081218 case " Network.loadingFailed " :
12091219 let requestID = parameters [ " requestId " ] as? String ?? " "
1220+ networkIdleTracker. requestDidFinish ( identifier: requestID)
12101221 diagnosticsLock. lock ( ) ; let request = requestContexts. removeValue ( forKey: requestID) ; diagnosticsLock. unlock ( )
12111222 diagnostics. append ( kind: " request-failed " , message: parameters [ " errorText " ] as? String ,
12121223 url: request? . url, method: request? . method, requestID: requestID,
12131224 requestHeaders: request? . headers, source: " chromium-cdp " )
12141225 case " Network.loadingFinished " :
12151226 if let requestID = parameters [ " requestId " ] as? String {
1227+ networkIdleTracker. requestDidFinish ( identifier: requestID)
12161228 diagnosticsLock. lock ( ) ; requestContexts. removeValue ( forKey: requestID) ; diagnosticsLock. unlock ( )
12171229 }
12181230 default : break
0 commit comments