@@ -12,6 +12,7 @@ const {
1212const cssToXPath = require ( 'css-to-xpath' ) ;
1313const { sprintf } = require ( 'sprintf-js' ) ;
1414const lodash = require ( 'lodash' ) ;
15+ const { retry } = require ( '../../../development/lib/retry' ) ;
1516const { quoteXPathText } = require ( '../../helpers/quoteXPathText' ) ;
1617const { isManifestV3 } = require ( '../../../shared/modules/mv3.utils' ) ;
1718const { WindowHandles } = require ( '../background-socket/window-handles' ) ;
@@ -24,6 +25,14 @@ const PAGES = {
2425 POPUP : 'popup' ,
2526} ;
2627
28+ /**
29+ * Error messages used by driver methods.
30+ */
31+ const errorMessages = {
32+ waitUntilXWindowHandlesTimeout :
33+ 'waitUntilXWindowHandles timed out polling window handles' ,
34+ } ;
35+
2736/**
2837 * Temporary workaround to patch selenium's element handle API with methods
2938 * that match the playwright API for Elements
@@ -128,17 +137,24 @@ class Driver {
128137 * @param {!ThenableWebDriver } driver - A {@code WebDriver} instance
129138 * @param {string } browser - The type of browser this driver is controlling
130139 * @param {string } extensionUrl
140+ * @param {boolean } e2eBuild - Whether the driver is being used with an E2E build or not.
131141 * @param {number } timeout - Defaults to 10000 milliseconds (10 seconds)
132142 */
133- constructor ( driver , browser , extensionUrl , timeout = 10 * 1000 ) {
143+ constructor (
144+ driver ,
145+ browser ,
146+ extensionUrl ,
147+ e2eBuild = true ,
148+ timeout = 10 * 1000 ,
149+ ) {
134150 this . driver = driver ;
135151 this . browser = browser ;
136152 this . extensionUrl = extensionUrl ;
137153 this . timeout = timeout ;
138154 this . exceptions = [ ] ;
139155 this . errors = [ ] ;
140156 this . eventProcessingStack = [ ] ;
141- this . windowHandles = new WindowHandles ( this . driver ) ;
157+ this . windowHandles = e2eBuild ? new WindowHandles ( this . driver ) : null ;
142158
143159 // The following values are found in
144160 // https://github.com/SeleniumHQ/selenium/blob/trunk/javascript/node/selenium-webdriver/lib/input.js#L50-L110
@@ -1053,7 +1069,9 @@ class Driver {
10531069 */
10541070 async switchToWindow ( handle ) {
10551071 await this . driver . switchTo ( ) . window ( handle ) ;
1056- await this . windowHandles . getCurrentWindowProperties ( null , handle ) ;
1072+ if ( this . windowHandles ) {
1073+ await this . windowHandles . getCurrentWindowProperties ( null , handle ) ;
1074+ }
10571075 }
10581076
10591077 /**
@@ -1082,7 +1100,10 @@ class Driver {
10821100 * be resolved with an array of window handles.
10831101 */
10841102 async getAllWindowHandles ( ) {
1085- return await this . windowHandles . getAllWindowHandles ( ) ;
1103+ if ( this . windowHandles ) {
1104+ return await this . windowHandles . getAllWindowHandles ( ) ;
1105+ }
1106+ return await this . driver . getAllWindowHandles ( ) ;
10861107 }
10871108
10881109 /**
@@ -1153,7 +1174,7 @@ class Driver {
11531174 }
11541175
11551176 throw new Error (
1156- `waitUntilXWindowHandles timed out polling window handles . Expected: ${ x } , Actual: ${ windowHandles . length } ` ,
1177+ `${ errorMessages . waitUntilXWindowHandlesTimeout } . Expected: ${ x } , Actual: ${ windowHandles . length } ` ,
11571178 ) ;
11581179 }
11591180
@@ -1193,7 +1214,41 @@ class Driver {
11931214 * @throws {Error } throws an error if no window with the specified title is found
11941215 */
11951216 async switchToWindowWithTitle ( title ) {
1196- return await this . windowHandles . switchToWindowWithProperty ( 'title' , title ) ;
1217+ if ( this . windowHandles ) {
1218+ return await this . windowHandles . switchToWindowWithProperty (
1219+ 'title' ,
1220+ title ,
1221+ ) ;
1222+ }
1223+
1224+ let windowHandles = await this . driver . getAllWindowHandles ( ) ;
1225+ let timeElapsed = 0 ;
1226+
1227+ while ( timeElapsed <= this . timeout ) {
1228+ for ( const handle of windowHandles ) {
1229+ const handleTitle = await retry (
1230+ {
1231+ retries : 8 ,
1232+ delay : 2500 ,
1233+ } ,
1234+ async ( ) => {
1235+ await this . driver . switchTo ( ) . window ( handle ) ;
1236+ return await this . driver . getTitle ( ) ;
1237+ } ,
1238+ ) ;
1239+
1240+ if ( handleTitle === title ) {
1241+ return handle ;
1242+ }
1243+ }
1244+ const delayTime = 1000 ;
1245+ await this . delay ( delayTime ) ;
1246+ timeElapsed += delayTime ;
1247+ // refresh the window handles
1248+ windowHandles = await this . driver . getAllWindowHandles ( ) ;
1249+ }
1250+
1251+ throw new Error ( `No window with title: ${ title } ` ) ;
11971252 }
11981253
11991254 /**
@@ -1217,6 +1272,9 @@ class Driver {
12171272 * @throws {Error } throws an error if no window with the specified URL is found
12181273 */
12191274 async switchToWindowWithUrl ( url ) {
1275+ if ( ! this . windowHandles ) {
1276+ throw new Error ( 'This is only supported for E2E test builds' ) ;
1277+ }
12201278 return await this . windowHandles . switchToWindowWithProperty (
12211279 'url' ,
12221280 new URL ( url ) . toString ( ) , // Make sure the URL has a trailing slash
@@ -1233,6 +1291,9 @@ class Driver {
12331291 * @throws {Error } throws an error if no window with the specified URL is found
12341292 */
12351293 async switchToWindowIfKnown ( title ) {
1294+ if ( ! this . windowHandles ) {
1295+ throw new Error ( 'This is only supported for E2E test builds' ) ;
1296+ }
12361297 return await this . windowHandles . switchToWindowIfKnown ( title ) ;
12371298 }
12381299
@@ -1625,4 +1686,4 @@ function sanitizeTestTitle(testTitle) {
16251686 . replace ( / ^ - + | - + $ / gu, '' ) ; // Trim leading/trailing dashes
16261687}
16271688
1628- module . exports = { Driver, PAGES } ;
1689+ module . exports = { Driver, PAGES , errorMessages } ;
0 commit comments