@@ -44,6 +44,27 @@ const makeOpenAndWaitCommand = (config: BrowserConfig, session: WebdriverIO.Brow
4444
4545 waitNetworkIdle &&= isChrome || isCDP ;
4646
47+ const originalPageLoadTimeout = config . pageLoadTimeout ;
48+ const shouldUpdateTimeout = timeout && timeout !== originalPageLoadTimeout ;
49+
50+ const setPageLoadTimeout = async ( value : number | null ) : Promise < void > => {
51+ if ( ! value ) {
52+ return ;
53+ }
54+ try {
55+ await session . setTimeout ( { pageLoad : value } ) ;
56+ } catch {
57+ /* */
58+ }
59+ } ;
60+
61+ const restorePageLoadTimeout = ( ) : void => {
62+ if ( shouldUpdateTimeout && originalPageLoadTimeout ) {
63+ // No await because session might be stuck on url() command
64+ setPageLoadTimeout ( originalPageLoadTimeout ) . catch ( ( ) => { } ) ;
65+ }
66+ } ;
67+
4768 if ( ! uri || uri === emptyPageUrl ) {
4869 return new Promise ( resolve => {
4970 session . url ( uri ) . then ( ( ) => resolve ( ) ) ;
@@ -64,7 +85,23 @@ const makeOpenAndWaitCommand = (config: BrowserConfig, session: WebdriverIO.Brow
6485 let predicateResolved = ! predicate ;
6586 let networkResolved = ! waitNetworkIdle ;
6687
67- return new Promise < void > ( ( resolve , reject ) => {
88+ if ( shouldUpdateTimeout ) {
89+ await setPageLoadTimeout ( timeout ) ;
90+ }
91+
92+ // Create hard timeout promise to guarantee timeout is respected
93+ // This is needed because WebDriver pageLoad timeout only affects the browser's
94+ // page load event, not the HTTP connection/response time
95+ let hardTimeoutId : NodeJS . Timeout | undefined ;
96+ const hardTimeoutPromise = timeout
97+ ? new Promise < never > ( ( _ , reject ) => {
98+ hardTimeoutId = setTimeout ( ( ) => {
99+ reject ( new Error ( `openAndWait timed out after ${ timeout } ms` ) ) ;
100+ } , timeout ) ;
101+ } )
102+ : null ;
103+
104+ const loadPromise = new Promise < void > ( ( resolve , reject ) => {
68105 const handleError = ( err : Error ) : void => {
69106 reject ( new Error ( `url: ${ err . message } ` ) ) ;
70107 } ;
@@ -76,7 +113,7 @@ const makeOpenAndWaitCommand = (config: BrowserConfig, session: WebdriverIO.Brow
76113 } ;
77114
78115 const goToPage = async ( ) : Promise < void > => {
79- await session . url ( uri ) ;
116+ await session . url ( uri , { timeout } ) ;
80117 } ;
81118
82119 pageLoader . on ( "pageLoadError" , handleError ) ;
@@ -109,7 +146,21 @@ const makeOpenAndWaitCommand = (config: BrowserConfig, session: WebdriverIO.Brow
109146 } ) ;
110147
111148 pageLoader . load ( goToPage ) . then ( checkLoaded ) ;
112- } ) . finally ( ( ) => pageLoader . unsubscribe ( ) ) ;
149+ } ) ;
150+
151+ const racePromises : Promise < void > [ ] = [ loadPromise ] ;
152+ if ( hardTimeoutPromise ) {
153+ racePromises . push ( hardTimeoutPromise ) ;
154+ }
155+
156+ return Promise . race ( racePromises ) . finally ( ( ) => {
157+ if ( hardTimeoutId ) {
158+ clearTimeout ( hardTimeoutId ) ;
159+ }
160+ // No await, because session might be stuck on url() command
161+ pageLoader . unsubscribe ( ) ;
162+ restorePageLoadTimeout ( ) ;
163+ } ) ;
113164 } ;
114165
115166export type OpenAndWaitCommand = ReturnType < typeof makeOpenAndWaitCommand > ;
0 commit comments