@@ -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' ) ;
@@ -118,27 +119,46 @@ until.foundElementCountIs = function foundElementCountIs(locator, n) {
118119 } ) ;
119120} ;
120121
122+ /**
123+ * Error messages used by driver methods.
124+ */
125+ const errorMessages = {
126+ waitUntilXWindowHandlesTimeout :
127+ 'waitUntilXWindowHandles timed out polling window handles' ,
128+ } ;
129+
121130/**
122131 * This is MetaMask's custom E2E test driver, wrapping the Selenium WebDriver.
123132 * For Selenium WebDriver API documentation, see:
124133 * https://www.selenium.dev/selenium/docs/api/javascript/module/selenium-webdriver/index_exports_WebDriver.html
125134 */
126135class Driver {
127136 /**
128- * @param {!ThenableWebDriver } driver - A {@code WebDriver} instance
129- * @param {string } browser - The type of browser this driver is controlling
130- * @param {string } extensionUrl
131- * @param {number } timeout - Defaults to 10000 milliseconds (10 seconds)
137+ * @param {object } args - Constructor arguments.
138+ * @param {!ThenableWebDriver } args.driver - A {@code WebDriver} instance
139+ * @param {string } args.browser - The type of browser this driver is controlling
140+ * @param {string } args.extensionUrl
141+ * @param {number } args.timeout - Defaults to 10000 milliseconds (10 seconds)
142+ * @param {boolean } args.disableServerMochaToBackground - Determines whether the background mocha
143+ * server is used.
132144 */
133- constructor ( driver , browser , extensionUrl , timeout = 10 * 1000 ) {
145+ constructor ( {
146+ driver,
147+ browser,
148+ extensionUrl,
149+ timeout = 10 * 1000 ,
150+ disableServerMochaToBackground,
151+ } ) {
134152 this . driver = driver ;
135153 this . browser = browser ;
136154 this . extensionUrl = extensionUrl ;
137155 this . timeout = timeout ;
138156 this . exceptions = [ ] ;
139157 this . errors = [ ] ;
140158 this . eventProcessingStack = [ ] ;
141- this . windowHandles = new WindowHandles ( this . driver ) ;
159+ this . windowHandles = disableServerMochaToBackground
160+ ? null
161+ : new WindowHandles ( this . driver ) ;
142162
143163 // The following values are found in
144164 // https://github.com/SeleniumHQ/selenium/blob/trunk/javascript/node/selenium-webdriver/lib/input.js#L50-L110
@@ -1053,7 +1073,9 @@ class Driver {
10531073 */
10541074 async switchToWindow ( handle ) {
10551075 await this . driver . switchTo ( ) . window ( handle ) ;
1056- await this . windowHandles . getCurrentWindowProperties ( null , handle ) ;
1076+ if ( this . windowHandles ) {
1077+ await this . windowHandles . getCurrentWindowProperties ( null , handle ) ;
1078+ }
10571079 }
10581080
10591081 /**
@@ -1082,7 +1104,10 @@ class Driver {
10821104 * be resolved with an array of window handles.
10831105 */
10841106 async getAllWindowHandles ( ) {
1085- return await this . windowHandles . getAllWindowHandles ( ) ;
1107+ if ( this . windowHandles ) {
1108+ return await this . windowHandles . getAllWindowHandles ( ) ;
1109+ }
1110+ return await this . driver . getAllWindowHandles ( ) ;
10861111 }
10871112
10881113 /**
@@ -1153,7 +1178,7 @@ class Driver {
11531178 }
11541179
11551180 throw new Error (
1156- `waitUntilXWindowHandles timed out polling window handles . Expected: ${ x } , Actual: ${ windowHandles . length } ` ,
1181+ `${ errorMessages . waitUntilXWindowHandlesTimeout } . Expected: ${ x } , Actual: ${ windowHandles . length } ` ,
11571182 ) ;
11581183 }
11591184
@@ -1193,7 +1218,42 @@ class Driver {
11931218 * @throws {Error } throws an error if no window with the specified title is found
11941219 */
11951220 async switchToWindowWithTitle ( title ) {
1196- return await this . windowHandles . switchToWindowWithProperty ( 'title' , title ) ;
1221+ if ( this . windowHandles ) {
1222+ return await this . windowHandles . switchToWindowWithProperty (
1223+ 'title' ,
1224+ title ,
1225+ ) ;
1226+ }
1227+
1228+ let windowHandles = await this . driver . getAllWindowHandles ( ) ;
1229+ let timeElapsed = 0 ;
1230+
1231+ while ( timeElapsed <= this . timeout ) {
1232+ for ( const handle of windowHandles ) {
1233+ // Wait 25 x 200ms = 5 seconds for the title to match the target title
1234+ const handleTitle = await retry (
1235+ {
1236+ retries : 25 ,
1237+ delay : 200 ,
1238+ } ,
1239+ async ( ) => {
1240+ await this . driver . switchTo ( ) . window ( handle ) ;
1241+ return await this . driver . getTitle ( ) ;
1242+ } ,
1243+ ) ;
1244+
1245+ if ( handleTitle === title ) {
1246+ return handle ;
1247+ }
1248+ }
1249+ const delayTime = 1000 ;
1250+ await this . delay ( delayTime ) ;
1251+ timeElapsed += delayTime ;
1252+ // refresh the window handles
1253+ windowHandles = await this . driver . getAllWindowHandles ( ) ;
1254+ }
1255+
1256+ throw new Error ( `No window with title: ${ title } ` ) ;
11971257 }
11981258
11991259 /**
@@ -1217,6 +1277,11 @@ class Driver {
12171277 * @throws {Error } throws an error if no window with the specified URL is found
12181278 */
12191279 async switchToWindowWithUrl ( url ) {
1280+ if ( ! this . windowHandles ) {
1281+ throw new Error (
1282+ 'This is only supported when the Mocha background server is enabled' ,
1283+ ) ;
1284+ }
12201285 return await this . windowHandles . switchToWindowWithProperty (
12211286 'url' ,
12221287 new URL ( url ) . toString ( ) , // Make sure the URL has a trailing slash
@@ -1233,6 +1298,11 @@ class Driver {
12331298 * @throws {Error } throws an error if no window with the specified URL is found
12341299 */
12351300 async switchToWindowIfKnown ( title ) {
1301+ if ( ! this . windowHandles ) {
1302+ throw new Error (
1303+ 'This is only supported when the Mocha background server is enabled' ,
1304+ ) ;
1305+ }
12361306 return await this . windowHandles . switchToWindowIfKnown ( title ) ;
12371307 }
12381308
@@ -1334,46 +1404,6 @@ class Driver {
13341404 }
13351405 }
13361406
1337- /**
1338- * Switches to a window by its title without using the background socket.
1339- * To be used in specs that run against production builds.
1340- *
1341- * @param {string } title - The target window title to switch to
1342- * @returns {Promise<void> }
1343- * @throws {Error } Will throw an error if the target window is not found
1344- */
1345- async switchToWindowByTitleWithoutSocket ( title ) {
1346- const windowHandles = await this . driver . getAllWindowHandles ( ) ;
1347- let targetWindowFound = false ;
1348-
1349- // Iterate through each window handle
1350- for ( const handle of windowHandles ) {
1351- await this . driver . switchTo ( ) . window ( handle ) ;
1352- let currentTitle = await this . driver . getTitle ( ) ;
1353-
1354- // Wait 25 x 200ms = 5 seconds for the title to match the target title
1355- for ( let i = 0 ; i < 25 ; i ++ ) {
1356- if ( currentTitle === title ) {
1357- targetWindowFound = true ;
1358- console . log ( `Switched to ${ title } window` ) ;
1359- break ;
1360- }
1361- await this . driver . sleep ( 200 ) ;
1362- currentTitle = await this . driver . getTitle ( ) ;
1363- }
1364-
1365- // If the target window is found, break out of the outer loop
1366- if ( targetWindowFound ) {
1367- break ;
1368- }
1369- }
1370-
1371- // If target window is not found, throw an error
1372- if ( ! targetWindowFound ) {
1373- throw new Error ( `${ title } window not found` ) ;
1374- }
1375- }
1376-
13771407 // Error handling
13781408
13791409 async verboseReportOnFailure ( testTitle , error ) {
@@ -1625,4 +1655,4 @@ function sanitizeTestTitle(testTitle) {
16251655 . replace ( / ^ - + | - + $ / gu, '' ) ; // Trim leading/trailing dashes
16261656}
16271657
1628- module . exports = { Driver, PAGES } ;
1658+ module . exports = { Driver, PAGES , errorMessages } ;
0 commit comments