@@ -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
@@ -1060,7 +1080,9 @@ class Driver {
10601080 */
10611081 async switchToWindow ( handle ) {
10621082 await this . driver . switchTo ( ) . window ( handle ) ;
1063- await this . windowHandles . getCurrentWindowProperties ( null , handle ) ;
1083+ if ( this . windowHandles ) {
1084+ await this . windowHandles . getCurrentWindowProperties ( null , handle ) ;
1085+ }
10641086 }
10651087
10661088 /**
@@ -1089,7 +1111,10 @@ class Driver {
10891111 * be resolved with an array of window handles.
10901112 */
10911113 async getAllWindowHandles ( ) {
1092- return await this . windowHandles . getAllWindowHandles ( ) ;
1114+ if ( this . windowHandles ) {
1115+ return await this . windowHandles . getAllWindowHandles ( ) ;
1116+ }
1117+ return await this . driver . getAllWindowHandles ( ) ;
10931118 }
10941119
10951120 /**
@@ -1160,7 +1185,7 @@ class Driver {
11601185 }
11611186
11621187 throw new Error (
1163- `waitUntilXWindowHandles timed out polling window handles . Expected: ${ x } , Actual: ${ windowHandles . length } ` ,
1188+ `${ errorMessages . waitUntilXWindowHandlesTimeout } . Expected: ${ x } , Actual: ${ windowHandles . length } ` ,
11641189 ) ;
11651190 }
11661191
@@ -1200,7 +1225,42 @@ class Driver {
12001225 * @throws {Error } throws an error if no window with the specified title is found
12011226 */
12021227 async switchToWindowWithTitle ( title ) {
1203- return await this . windowHandles . switchToWindowWithProperty ( 'title' , title ) ;
1228+ if ( this . windowHandles ) {
1229+ return await this . windowHandles . switchToWindowWithProperty (
1230+ 'title' ,
1231+ title ,
1232+ ) ;
1233+ }
1234+
1235+ let windowHandles = await this . driver . getAllWindowHandles ( ) ;
1236+ let timeElapsed = 0 ;
1237+
1238+ while ( timeElapsed <= this . timeout ) {
1239+ for ( const handle of windowHandles ) {
1240+ // Wait 25 x 200ms = 5 seconds for the title to match the target title
1241+ const handleTitle = await retry (
1242+ {
1243+ retries : 25 ,
1244+ delay : 200 ,
1245+ } ,
1246+ async ( ) => {
1247+ await this . driver . switchTo ( ) . window ( handle ) ;
1248+ return await this . driver . getTitle ( ) ;
1249+ } ,
1250+ ) ;
1251+
1252+ if ( handleTitle === title ) {
1253+ return handle ;
1254+ }
1255+ }
1256+ const delayTime = 1000 ;
1257+ await this . delay ( delayTime ) ;
1258+ timeElapsed += delayTime ;
1259+ // refresh the window handles
1260+ windowHandles = await this . driver . getAllWindowHandles ( ) ;
1261+ }
1262+
1263+ throw new Error ( `No window with title: ${ title } ` ) ;
12041264 }
12051265
12061266 /**
@@ -1224,6 +1284,11 @@ class Driver {
12241284 * @throws {Error } throws an error if no window with the specified URL is found
12251285 */
12261286 async switchToWindowWithUrl ( url ) {
1287+ if ( ! this . windowHandles ) {
1288+ throw new Error (
1289+ 'This is only supported when the Mocha background server is enabled' ,
1290+ ) ;
1291+ }
12271292 return await this . windowHandles . switchToWindowWithProperty (
12281293 'url' ,
12291294 new URL ( url ) . toString ( ) , // Make sure the URL has a trailing slash
@@ -1240,6 +1305,11 @@ class Driver {
12401305 * @throws {Error } throws an error if no window with the specified URL is found
12411306 */
12421307 async switchToWindowIfKnown ( title ) {
1308+ if ( ! this . windowHandles ) {
1309+ throw new Error (
1310+ 'This is only supported when the Mocha background server is enabled' ,
1311+ ) ;
1312+ }
12431313 return await this . windowHandles . switchToWindowIfKnown ( title ) ;
12441314 }
12451315
@@ -1341,46 +1411,6 @@ class Driver {
13411411 }
13421412 }
13431413
1344- /**
1345- * Switches to a window by its title without using the background socket.
1346- * To be used in specs that run against production builds.
1347- *
1348- * @param {string } title - The target window title to switch to
1349- * @returns {Promise<void> }
1350- * @throws {Error } Will throw an error if the target window is not found
1351- */
1352- async switchToWindowByTitleWithoutSocket ( title ) {
1353- const windowHandles = await this . driver . getAllWindowHandles ( ) ;
1354- let targetWindowFound = false ;
1355-
1356- // Iterate through each window handle
1357- for ( const handle of windowHandles ) {
1358- await this . driver . switchTo ( ) . window ( handle ) ;
1359- let currentTitle = await this . driver . getTitle ( ) ;
1360-
1361- // Wait 25 x 200ms = 5 seconds for the title to match the target title
1362- for ( let i = 0 ; i < 25 ; i ++ ) {
1363- if ( currentTitle === title ) {
1364- targetWindowFound = true ;
1365- console . log ( `Switched to ${ title } window` ) ;
1366- break ;
1367- }
1368- await this . driver . sleep ( 200 ) ;
1369- currentTitle = await this . driver . getTitle ( ) ;
1370- }
1371-
1372- // If the target window is found, break out of the outer loop
1373- if ( targetWindowFound ) {
1374- break ;
1375- }
1376- }
1377-
1378- // If target window is not found, throw an error
1379- if ( ! targetWindowFound ) {
1380- throw new Error ( `${ title } window not found` ) ;
1381- }
1382- }
1383-
13841414 // Error handling
13851415
13861416 async verboseReportOnFailure ( testTitle , error ) {
@@ -1632,4 +1662,4 @@ function sanitizeTestTitle(testTitle) {
16321662 . replace ( / ^ - + | - + $ / gu, '' ) ; // Trim leading/trailing dashes
16331663}
16341664
1635- module . exports = { Driver, PAGES } ;
1665+ module . exports = { Driver, PAGES , errorMessages } ;
0 commit comments