selenium-webdriver 4.0.0-alpha.8 → 4.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGES.md +14 -1
- package/LICENSE +202 -0
- package/NOTICE +2 -0
- package/README.md +0 -0
- package/chrome.js +0 -0
- package/chromium.js +7 -202
- package/devtools/CDPConnection.js +0 -0
- package/edge.js +1 -1
- package/example/chrome_android.js +45 -0
- package/{lib/atoms/make-atoms-module.js → example/chrome_mobile_emulation.js} +26 -15
- package/example/firefox_channels.js +84 -0
- package/example/google_search.js +50 -0
- package/example/google_search_test.js +70 -0
- package/example/headless.js +63 -0
- package/example/logging.js +64 -0
- package/firefox.js +10 -9
- package/http/index.js +0 -0
- package/http/util.js +3 -3
- package/ie.js +0 -0
- package/index.js +2 -2
- package/io/exec.js +0 -0
- package/io/index.js +4 -4
- package/io/zip.js +0 -0
- package/lib/actions.js +16 -15
- package/lib/atoms/find-elements.js +4 -3
- package/lib/atoms/get-attribute.js +0 -0
- package/lib/atoms/is-displayed.js +0 -0
- package/lib/atoms/mutation-listener.js +38 -0
- package/lib/by.js +1 -1
- package/lib/capabilities.js +2 -2
- package/lib/command.js +2 -0
- package/lib/error.js +0 -0
- package/lib/http.js +17 -1
- package/lib/input.js +0 -0
- package/lib/logging.js +0 -0
- package/lib/promise.js +1 -1
- package/lib/proxy.js +0 -0
- package/lib/session.js +0 -0
- package/lib/symbols.js +0 -0
- package/lib/until.js +17 -15
- package/lib/webdriver.js +322 -50
- package/net/index.js +0 -0
- package/net/portprober.js +8 -8
- package/opera.js +0 -0
- package/package.json +8 -8
- package/proxy.js +0 -0
- package/remote/index.js +0 -0
- package/safari.js +0 -0
- package/testing/index.js +509 -0
- package/.eslintrc.js +0 -27
- package/.prettierrc +0 -4
- package/devtools/generator/protocol-dts-generator.js +0 -429
- package/lib/README +0 -5
package/lib/webdriver.js
CHANGED
|
@@ -29,6 +29,11 @@ const input = require('./input')
|
|
|
29
29
|
const logging = require('./logging')
|
|
30
30
|
const promise = require('./promise')
|
|
31
31
|
const Symbols = require('./symbols')
|
|
32
|
+
const cdpTargets = ['page', 'browser']
|
|
33
|
+
const cdp = require('../devtools/CDPConnection')
|
|
34
|
+
const WebSocket = require('ws')
|
|
35
|
+
const http = require('../http/index')
|
|
36
|
+
const fs = require('fs')
|
|
32
37
|
const { Capabilities } = require('./capabilities')
|
|
33
38
|
|
|
34
39
|
// Capability names that are defined in the W3C spec.
|
|
@@ -239,30 +244,30 @@ class IWebDriver {
|
|
|
239
244
|
* result.
|
|
240
245
|
* @template T
|
|
241
246
|
*/
|
|
242
|
-
execute(command) {} // eslint-disable-line
|
|
247
|
+
execute(command) { } // eslint-disable-line
|
|
243
248
|
|
|
244
249
|
/**
|
|
245
250
|
* Sets the {@linkplain input.FileDetector file detector} that should be
|
|
246
251
|
* used with this instance.
|
|
247
252
|
* @param {input.FileDetector} detector The detector to use or `null`.
|
|
248
253
|
*/
|
|
249
|
-
setFileDetector(detector) {} // eslint-disable-line
|
|
254
|
+
setFileDetector(detector) { } // eslint-disable-line
|
|
250
255
|
|
|
251
256
|
/**
|
|
252
257
|
* @return {!command.Executor} The command executor used by this instance.
|
|
253
258
|
*/
|
|
254
|
-
getExecutor() {}
|
|
259
|
+
getExecutor() { }
|
|
255
260
|
|
|
256
261
|
/**
|
|
257
262
|
* @return {!Promise<!Session>} A promise for this client's session.
|
|
258
263
|
*/
|
|
259
|
-
getSession() {}
|
|
264
|
+
getSession() { }
|
|
260
265
|
|
|
261
266
|
/**
|
|
262
267
|
* @return {!Promise<!Capabilities>} A promise that will resolve with
|
|
263
268
|
* the this instance's capabilities.
|
|
264
269
|
*/
|
|
265
|
-
getCapabilities() {}
|
|
270
|
+
getCapabilities() { }
|
|
266
271
|
|
|
267
272
|
/**
|
|
268
273
|
* Terminates the browser session. After calling quit, this instance will be
|
|
@@ -272,7 +277,7 @@ class IWebDriver {
|
|
|
272
277
|
* @return {!Promise<void>} A promise that will be resolved when the
|
|
273
278
|
* command has completed.
|
|
274
279
|
*/
|
|
275
|
-
quit() {}
|
|
280
|
+
quit() { }
|
|
276
281
|
|
|
277
282
|
/**
|
|
278
283
|
* Creates a new action sequence using this driver. The sequence will not be
|
|
@@ -285,7 +290,7 @@ class IWebDriver {
|
|
|
285
290
|
* for details).
|
|
286
291
|
* @return {!input.Actions} A new action sequence for this instance.
|
|
287
292
|
*/
|
|
288
|
-
actions(options) {} // eslint-disable-line
|
|
293
|
+
actions(options) { } // eslint-disable-line
|
|
289
294
|
|
|
290
295
|
/**
|
|
291
296
|
* Executes a snippet of JavaScript in the context of the currently selected
|
|
@@ -323,7 +328,7 @@ class IWebDriver {
|
|
|
323
328
|
* scripts return value.
|
|
324
329
|
* @template T
|
|
325
330
|
*/
|
|
326
|
-
executeScript(script, ...args) {} // eslint-disable-line
|
|
331
|
+
executeScript(script, ...args) { } // eslint-disable-line
|
|
327
332
|
|
|
328
333
|
/**
|
|
329
334
|
* Executes a snippet of asynchronous JavaScript in the context of the
|
|
@@ -400,7 +405,7 @@ class IWebDriver {
|
|
|
400
405
|
* value.
|
|
401
406
|
* @template T
|
|
402
407
|
*/
|
|
403
|
-
executeAsyncScript(script, ...args) {} // eslint-disable-line
|
|
408
|
+
executeAsyncScript(script, ...args) { } // eslint-disable-line
|
|
404
409
|
|
|
405
410
|
/**
|
|
406
411
|
* Waits for a condition to evaluate to a "truthy" value. The condition may be
|
|
@@ -451,7 +456,7 @@ class IWebDriver {
|
|
|
451
456
|
timeout = undefined, // eslint-disable-line
|
|
452
457
|
message = undefined, // eslint-disable-line
|
|
453
458
|
pollTimeout = undefined // eslint-disable-line
|
|
454
|
-
) {}
|
|
459
|
+
) { }
|
|
455
460
|
|
|
456
461
|
/**
|
|
457
462
|
* Makes the driver sleep for the given amount of time.
|
|
@@ -460,7 +465,7 @@ class IWebDriver {
|
|
|
460
465
|
* @return {!Promise<void>} A promise that will be resolved when the sleep has
|
|
461
466
|
* finished.
|
|
462
467
|
*/
|
|
463
|
-
sleep(ms) {} // eslint-disable-line
|
|
468
|
+
sleep(ms) { } // eslint-disable-line
|
|
464
469
|
|
|
465
470
|
/**
|
|
466
471
|
* Retrieves the current window handle.
|
|
@@ -468,7 +473,7 @@ class IWebDriver {
|
|
|
468
473
|
* @return {!Promise<string>} A promise that will be resolved with the current
|
|
469
474
|
* window handle.
|
|
470
475
|
*/
|
|
471
|
-
getWindowHandle() {}
|
|
476
|
+
getWindowHandle() { }
|
|
472
477
|
|
|
473
478
|
/**
|
|
474
479
|
* Retrieves a list of all available window handles.
|
|
@@ -476,7 +481,7 @@ class IWebDriver {
|
|
|
476
481
|
* @return {!Promise<!Array<string>>} A promise that will be resolved with an
|
|
477
482
|
* array of window handles.
|
|
478
483
|
*/
|
|
479
|
-
getAllWindowHandles() {}
|
|
484
|
+
getAllWindowHandles() { }
|
|
480
485
|
|
|
481
486
|
/**
|
|
482
487
|
* Retrieves the current page's source. The returned source is a representation
|
|
@@ -486,7 +491,7 @@ class IWebDriver {
|
|
|
486
491
|
* @return {!Promise<string>} A promise that will be resolved with the current
|
|
487
492
|
* page source.
|
|
488
493
|
*/
|
|
489
|
-
getPageSource() {}
|
|
494
|
+
getPageSource() { }
|
|
490
495
|
|
|
491
496
|
/**
|
|
492
497
|
* Closes the current window.
|
|
@@ -494,7 +499,7 @@ class IWebDriver {
|
|
|
494
499
|
* @return {!Promise<void>} A promise that will be resolved when this command
|
|
495
500
|
* has completed.
|
|
496
501
|
*/
|
|
497
|
-
close() {}
|
|
502
|
+
close() { }
|
|
498
503
|
|
|
499
504
|
/**
|
|
500
505
|
* Navigates to the given URL.
|
|
@@ -503,7 +508,7 @@ class IWebDriver {
|
|
|
503
508
|
* @return {!Promise<void>} A promise that will be resolved when the document
|
|
504
509
|
* has finished loading.
|
|
505
510
|
*/
|
|
506
|
-
get(url) {} // eslint-disable-line
|
|
511
|
+
get(url) { } // eslint-disable-line
|
|
507
512
|
|
|
508
513
|
/**
|
|
509
514
|
* Retrieves the URL for the current page.
|
|
@@ -511,7 +516,7 @@ class IWebDriver {
|
|
|
511
516
|
* @return {!Promise<string>} A promise that will be resolved with the
|
|
512
517
|
* current URL.
|
|
513
518
|
*/
|
|
514
|
-
getCurrentUrl() {}
|
|
519
|
+
getCurrentUrl() { }
|
|
515
520
|
|
|
516
521
|
/**
|
|
517
522
|
* Retrieves the current page title.
|
|
@@ -519,7 +524,7 @@ class IWebDriver {
|
|
|
519
524
|
* @return {!Promise<string>} A promise that will be resolved with the current
|
|
520
525
|
* page's title.
|
|
521
526
|
*/
|
|
522
|
-
getTitle() {}
|
|
527
|
+
getTitle() { }
|
|
523
528
|
|
|
524
529
|
/**
|
|
525
530
|
* Locates an element on the page. If the element cannot be found, a
|
|
@@ -559,7 +564,7 @@ class IWebDriver {
|
|
|
559
564
|
* commands against the located element. If the element is not found, the
|
|
560
565
|
* element will be invalidated and all scheduled commands aborted.
|
|
561
566
|
*/
|
|
562
|
-
findElement(locator) {} // eslint-disable-line
|
|
567
|
+
findElement(locator) { } // eslint-disable-line
|
|
563
568
|
|
|
564
569
|
/**
|
|
565
570
|
* Search for multiple elements on the page. Refer to the documentation on
|
|
@@ -569,7 +574,7 @@ class IWebDriver {
|
|
|
569
574
|
* @return {!Promise<!Array<!WebElement>>} A promise that will resolve to an
|
|
570
575
|
* array of WebElements.
|
|
571
576
|
*/
|
|
572
|
-
findElements(locator) {} // eslint-disable-line
|
|
577
|
+
findElements(locator) { } // eslint-disable-line
|
|
573
578
|
|
|
574
579
|
/**
|
|
575
580
|
* Takes a screenshot of the current page. The driver makes a best effort to
|
|
@@ -583,23 +588,23 @@ class IWebDriver {
|
|
|
583
588
|
* @return {!Promise<string>} A promise that will be resolved to the
|
|
584
589
|
* screenshot as a base-64 encoded PNG.
|
|
585
590
|
*/
|
|
586
|
-
takeScreenshot() {}
|
|
591
|
+
takeScreenshot() { }
|
|
587
592
|
|
|
588
593
|
/**
|
|
589
594
|
* @return {!Options} The options interface for this instance.
|
|
590
595
|
*/
|
|
591
|
-
manage() {}
|
|
596
|
+
manage() { }
|
|
592
597
|
|
|
593
598
|
/**
|
|
594
599
|
* @return {!Navigation} The navigation interface for this instance.
|
|
595
600
|
*/
|
|
596
|
-
navigate() {}
|
|
601
|
+
navigate() { }
|
|
597
602
|
|
|
598
603
|
/**
|
|
599
604
|
* @return {!TargetLocator} The target locator interface for this
|
|
600
605
|
* instance.
|
|
601
606
|
*/
|
|
602
|
-
switchTo() {}
|
|
607
|
+
switchTo() { }
|
|
603
608
|
|
|
604
609
|
/**
|
|
605
610
|
*
|
|
@@ -618,7 +623,7 @@ class IWebDriver {
|
|
|
618
623
|
* shrinkToFit: (boolean|undefined)
|
|
619
624
|
* pageRanges: (<Array>|undefined)}} options.
|
|
620
625
|
*/
|
|
621
|
-
printPage(options) {} // eslint-disable-line
|
|
626
|
+
printPage(options) { } // eslint-disable-line
|
|
622
627
|
}
|
|
623
628
|
|
|
624
629
|
/**
|
|
@@ -658,7 +663,7 @@ class WebDriver {
|
|
|
658
663
|
// If session is a rejected promise, add a no-op rejection handler.
|
|
659
664
|
// This effectively hides setup errors until users attempt to interact
|
|
660
665
|
// with the session.
|
|
661
|
-
this.session_.catch(function () {})
|
|
666
|
+
this.session_.catch(function () { })
|
|
662
667
|
|
|
663
668
|
/** @private {!command.Executor} */
|
|
664
669
|
this.executor_ = executor
|
|
@@ -754,12 +759,12 @@ class WebDriver {
|
|
|
754
759
|
this.session_ = Promise.reject(
|
|
755
760
|
new error.NoSuchSessionError(
|
|
756
761
|
'This driver instance does not have a valid session ID ' +
|
|
757
|
-
|
|
762
|
+
'(did you call WebDriver.quit()?) and may no longer be used.'
|
|
758
763
|
)
|
|
759
764
|
)
|
|
760
765
|
|
|
761
766
|
// Only want the session rejection to bubble if accessed.
|
|
762
|
-
this.session_.catch(function () {})
|
|
767
|
+
this.session_.catch(function () { })
|
|
763
768
|
|
|
764
769
|
if (this.onQuit_) {
|
|
765
770
|
return this.onQuit_.call(void 0)
|
|
@@ -820,18 +825,15 @@ class WebDriver {
|
|
|
820
825
|
let timeoutMessage = resolveWaitMessage(message)
|
|
821
826
|
reject(
|
|
822
827
|
new error.TimeoutError(
|
|
823
|
-
`${timeoutMessage}Timed out waiting for promise to resolve after ${
|
|
824
|
-
Date.now() - start
|
|
828
|
+
`${timeoutMessage}Timed out waiting for promise to resolve after ${Date.now() - start
|
|
825
829
|
}ms`
|
|
826
830
|
)
|
|
827
831
|
)
|
|
828
832
|
} catch (ex) {
|
|
829
833
|
reject(
|
|
830
834
|
new error.TimeoutError(
|
|
831
|
-
`${
|
|
832
|
-
|
|
833
|
-
}\nTimed out waiting for promise to resolve after ${
|
|
834
|
-
Date.now() - start
|
|
835
|
+
`${ex.message
|
|
836
|
+
}\nTimed out waiting for promise to resolve after ${Date.now() - start
|
|
835
837
|
}ms`
|
|
836
838
|
)
|
|
837
839
|
)
|
|
@@ -861,7 +863,7 @@ class WebDriver {
|
|
|
861
863
|
if (typeof fn !== 'function') {
|
|
862
864
|
throw TypeError(
|
|
863
865
|
'Wait condition must be a promise-like object, function, or a ' +
|
|
864
|
-
|
|
866
|
+
'Condition object'
|
|
865
867
|
)
|
|
866
868
|
}
|
|
867
869
|
|
|
@@ -913,7 +915,7 @@ class WebDriver {
|
|
|
913
915
|
if (!(value instanceof WebElement)) {
|
|
914
916
|
throw TypeError(
|
|
915
917
|
'WebElementCondition did not resolve to a WebElement: ' +
|
|
916
|
-
|
|
918
|
+
Object.prototype.toString.call(value)
|
|
917
919
|
)
|
|
918
920
|
}
|
|
919
921
|
return value
|
|
@@ -925,7 +927,7 @@ class WebDriver {
|
|
|
925
927
|
|
|
926
928
|
/** @override */
|
|
927
929
|
sleep(ms) {
|
|
928
|
-
return new Promise((resolve) => setTimeout(
|
|
930
|
+
return new Promise((resolve) => setTimeout(resolve, ms))
|
|
929
931
|
}
|
|
930
932
|
|
|
931
933
|
/** @override */
|
|
@@ -1150,6 +1152,257 @@ class WebDriver {
|
|
|
1150
1152
|
new command.Command(command.Name.PRINT_PAGE).setParameters(resultObj)
|
|
1151
1153
|
)
|
|
1152
1154
|
}
|
|
1155
|
+
|
|
1156
|
+
/**
|
|
1157
|
+
* Creates a new WebSocket connection.
|
|
1158
|
+
* @return {!Promise<resolved>} A new CDP instance.
|
|
1159
|
+
*/
|
|
1160
|
+
async createCDPConnection(target) {
|
|
1161
|
+
const caps = await this.getCapabilities()
|
|
1162
|
+
const seOptions = caps['map_'].get('se:options') || new Map()
|
|
1163
|
+
const vendorInfo =
|
|
1164
|
+
caps['map_'].get(this.VENDOR_COMMAND_PREFIX + ':chromeOptions') ||
|
|
1165
|
+
caps['map_'].get('moz:debuggerAddress') ||
|
|
1166
|
+
new Map()
|
|
1167
|
+
const debuggerUrl = seOptions['cdp'] || vendorInfo['debuggerAddress'] || vendorInfo
|
|
1168
|
+
this._wsUrl = await this.getWsUrl(debuggerUrl, target)
|
|
1169
|
+
|
|
1170
|
+
return new Promise((resolve, reject) => {
|
|
1171
|
+
try {
|
|
1172
|
+
this._wsConnection = new WebSocket(this._wsUrl)
|
|
1173
|
+
} catch (err) {
|
|
1174
|
+
reject(err)
|
|
1175
|
+
return
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
this._wsConnection.on('open', () => {
|
|
1179
|
+
this._cdpConnection = new cdp.CdpConnection(this._wsConnection)
|
|
1180
|
+
resolve(this._cdpConnection)
|
|
1181
|
+
})
|
|
1182
|
+
|
|
1183
|
+
this._wsConnection.on('error', (error) => {
|
|
1184
|
+
reject(error)
|
|
1185
|
+
})
|
|
1186
|
+
})
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
/**
|
|
1190
|
+
* Retrieves 'webSocketDebuggerUrl' by sending a http request using debugger address
|
|
1191
|
+
* @param {string} debuggerAddress
|
|
1192
|
+
* @param {string} target
|
|
1193
|
+
* @return {string} Returns parsed webSocketDebuggerUrl obtained from the http request
|
|
1194
|
+
*/
|
|
1195
|
+
async getWsUrl(debuggerAddress, target) {
|
|
1196
|
+
if (target && cdpTargets.indexOf(target.toLowerCase()) === -1) {
|
|
1197
|
+
throw new error.InvalidArgumentError('invalid target value')
|
|
1198
|
+
}
|
|
1199
|
+
let path = '/json/version'
|
|
1200
|
+
|
|
1201
|
+
let request = new http.Request('GET', path)
|
|
1202
|
+
let client = new http.HttpClient('http://' + debuggerAddress)
|
|
1203
|
+
let response = await client.send(request)
|
|
1204
|
+
let url = JSON.parse(response.body)['webSocketDebuggerUrl']
|
|
1205
|
+
|
|
1206
|
+
return url
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
/**
|
|
1210
|
+
* Sets a listener for Fetch.authRequired event from CDP
|
|
1211
|
+
* If event is triggered, it enter username and password
|
|
1212
|
+
* and allows the test to move forward
|
|
1213
|
+
* @param {string} username
|
|
1214
|
+
* @param {string} password
|
|
1215
|
+
* @param connection CDP Connection
|
|
1216
|
+
*/
|
|
1217
|
+
async register(username, password, connection) {
|
|
1218
|
+
await connection.execute(
|
|
1219
|
+
'Network.setCacheDisabled',
|
|
1220
|
+
this.getRandomNumber(1, 10),
|
|
1221
|
+
{
|
|
1222
|
+
cacheDisabled: true,
|
|
1223
|
+
},
|
|
1224
|
+
null
|
|
1225
|
+
)
|
|
1226
|
+
|
|
1227
|
+
this._wsConnection.on('message', (message) => {
|
|
1228
|
+
const params = JSON.parse(message)
|
|
1229
|
+
|
|
1230
|
+
if (params.method === 'Fetch.authRequired') {
|
|
1231
|
+
const requestParams = params['params']
|
|
1232
|
+
connection.execute(
|
|
1233
|
+
'Fetch.continueWithAuth',
|
|
1234
|
+
this.getRandomNumber(1, 10),
|
|
1235
|
+
{
|
|
1236
|
+
requestId: requestParams['requestId'],
|
|
1237
|
+
authChallengeResponse: {
|
|
1238
|
+
response: 'ProvideCredentials',
|
|
1239
|
+
username: username,
|
|
1240
|
+
password: password,
|
|
1241
|
+
},
|
|
1242
|
+
}
|
|
1243
|
+
)
|
|
1244
|
+
} else if (params.method === 'Fetch.requestPaused') {
|
|
1245
|
+
const requestPausedParams = params['params']
|
|
1246
|
+
connection.execute(
|
|
1247
|
+
'Fetch.continueRequest',
|
|
1248
|
+
this.getRandomNumber(1, 10),
|
|
1249
|
+
{
|
|
1250
|
+
requestId: requestPausedParams['requestId'],
|
|
1251
|
+
}
|
|
1252
|
+
)
|
|
1253
|
+
}
|
|
1254
|
+
})
|
|
1255
|
+
|
|
1256
|
+
await connection.execute(
|
|
1257
|
+
'Fetch.enable',
|
|
1258
|
+
1,
|
|
1259
|
+
{
|
|
1260
|
+
handleAuthRequests: true,
|
|
1261
|
+
},
|
|
1262
|
+
null
|
|
1263
|
+
)
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
/**
|
|
1267
|
+
*
|
|
1268
|
+
* @param connection
|
|
1269
|
+
* @param callback
|
|
1270
|
+
* @returns {Promise<void>}
|
|
1271
|
+
*/
|
|
1272
|
+
async onLogEvent(connection, callback) {
|
|
1273
|
+
await connection.execute(
|
|
1274
|
+
'Runtime.enable',
|
|
1275
|
+
this.getRandomNumber(1, 10),
|
|
1276
|
+
{},
|
|
1277
|
+
null
|
|
1278
|
+
)
|
|
1279
|
+
|
|
1280
|
+
this._wsConnection.on('message', (message) => {
|
|
1281
|
+
const params = JSON.parse(message)
|
|
1282
|
+
|
|
1283
|
+
if (params.method === 'Runtime.consoleAPICalled') {
|
|
1284
|
+
const consoleEventParams = params['params']
|
|
1285
|
+
let event = {
|
|
1286
|
+
type: consoleEventParams['type'],
|
|
1287
|
+
timestamp: new Date(consoleEventParams['timestamp']),
|
|
1288
|
+
args: consoleEventParams['args'],
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
callback(event)
|
|
1292
|
+
}
|
|
1293
|
+
})
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
/**
|
|
1297
|
+
*
|
|
1298
|
+
* @param connection
|
|
1299
|
+
* @param callback
|
|
1300
|
+
* @returns {Promise<void>}
|
|
1301
|
+
*/
|
|
1302
|
+
async onLogException(connection, callback) {
|
|
1303
|
+
await connection.execute(
|
|
1304
|
+
'Runtime.enable',
|
|
1305
|
+
this.getRandomNumber(1, 10),
|
|
1306
|
+
{},
|
|
1307
|
+
null
|
|
1308
|
+
)
|
|
1309
|
+
|
|
1310
|
+
this._wsConnection.on('message', (message) => {
|
|
1311
|
+
const params = JSON.parse(message)
|
|
1312
|
+
|
|
1313
|
+
if (params.method === 'Runtime.exceptionThrown') {
|
|
1314
|
+
const exceptionEventParams = params['params']
|
|
1315
|
+
let event = {
|
|
1316
|
+
exceptionDetails: exceptionEventParams['exceptionDetails'],
|
|
1317
|
+
timestamp: new Date(exceptionEventParams['timestamp']),
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
callback(event)
|
|
1321
|
+
}
|
|
1322
|
+
})
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
/**
|
|
1326
|
+
* @param connection
|
|
1327
|
+
* @param callback
|
|
1328
|
+
* @returns {Promise<void>}
|
|
1329
|
+
*/
|
|
1330
|
+
async logMutationEvents(connection, callback) {
|
|
1331
|
+
await connection.execute(
|
|
1332
|
+
'Runtime.enable',
|
|
1333
|
+
this.getRandomNumber(1, 10),
|
|
1334
|
+
{},
|
|
1335
|
+
null
|
|
1336
|
+
)
|
|
1337
|
+
await connection.execute(
|
|
1338
|
+
'Page.enable',
|
|
1339
|
+
this.getRandomNumber(1, 10),
|
|
1340
|
+
{},
|
|
1341
|
+
null
|
|
1342
|
+
)
|
|
1343
|
+
|
|
1344
|
+
await connection.execute(
|
|
1345
|
+
'Runtime.addBinding',
|
|
1346
|
+
this.getRandomNumber(1, 10),
|
|
1347
|
+
{
|
|
1348
|
+
name: '__webdriver_attribute',
|
|
1349
|
+
},
|
|
1350
|
+
null
|
|
1351
|
+
)
|
|
1352
|
+
|
|
1353
|
+
let mutationListener = ''
|
|
1354
|
+
try {
|
|
1355
|
+
// Depending on what is running the code it could appear in 2 different places which is why we try
|
|
1356
|
+
// here and then the other location
|
|
1357
|
+
mutationListener = fs
|
|
1358
|
+
.readFileSync(
|
|
1359
|
+
'./javascript/node/selenium-webdriver/lib/atoms/mutation-listener.js',
|
|
1360
|
+
'utf-8'
|
|
1361
|
+
)
|
|
1362
|
+
.toString()
|
|
1363
|
+
} catch {
|
|
1364
|
+
mutationListener = fs
|
|
1365
|
+
.readFileSync('./atoms/mutation-listener.js', 'utf-8')
|
|
1366
|
+
.toString()
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
this.executeScript(mutationListener)
|
|
1370
|
+
|
|
1371
|
+
await connection.execute(
|
|
1372
|
+
'Page.addScriptToEvaluateOnNewDocument',
|
|
1373
|
+
this.getRandomNumber(1, 10),
|
|
1374
|
+
{
|
|
1375
|
+
source: mutationListener,
|
|
1376
|
+
},
|
|
1377
|
+
null
|
|
1378
|
+
)
|
|
1379
|
+
|
|
1380
|
+
this._wsConnection.on('message', async (message) => {
|
|
1381
|
+
const params = JSON.parse(message)
|
|
1382
|
+
if (params.method === 'Runtime.bindingCalled') {
|
|
1383
|
+
let payload = JSON.parse(params['params']['payload'])
|
|
1384
|
+
let elements = await this.findElements({
|
|
1385
|
+
css: '*[data-__webdriver_id=' + payload['target'],
|
|
1386
|
+
})
|
|
1387
|
+
|
|
1388
|
+
if (elements.length === 0) {
|
|
1389
|
+
return
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
let event = {
|
|
1393
|
+
element: elements[0],
|
|
1394
|
+
attribute_name: payload['name'],
|
|
1395
|
+
current_value: payload['value'],
|
|
1396
|
+
old_value: payload['oldValue'],
|
|
1397
|
+
}
|
|
1398
|
+
callback(event)
|
|
1399
|
+
}
|
|
1400
|
+
})
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
getRandomNumber(min, max) {
|
|
1404
|
+
return Math.floor(Math.random() * (max - min + 1) + min)
|
|
1405
|
+
}
|
|
1153
1406
|
}
|
|
1154
1407
|
|
|
1155
1408
|
/**
|
|
@@ -1431,7 +1684,7 @@ class Options {
|
|
|
1431
1684
|
} else if (typeof value !== 'undefined') {
|
|
1432
1685
|
throw TypeError(
|
|
1433
1686
|
'invalid timeouts configuration:' +
|
|
1434
|
-
|
|
1687
|
+
` expected "${key}" to be a number, got ${typeof value}`
|
|
1435
1688
|
)
|
|
1436
1689
|
}
|
|
1437
1690
|
}
|
|
@@ -1492,7 +1745,7 @@ function legacyTimeout(driver, type, ms) {
|
|
|
1492
1745
|
*
|
|
1493
1746
|
* @record
|
|
1494
1747
|
*/
|
|
1495
|
-
Options.Cookie = function () {}
|
|
1748
|
+
Options.Cookie = function () { }
|
|
1496
1749
|
|
|
1497
1750
|
/**
|
|
1498
1751
|
* The name of the cookie.
|
|
@@ -2197,18 +2450,18 @@ class WebElement {
|
|
|
2197
2450
|
*/
|
|
2198
2451
|
async sendKeys(...args) {
|
|
2199
2452
|
let keys = []
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2453
|
+
; (await Promise.all(args)).forEach((key) => {
|
|
2454
|
+
let type = typeof key
|
|
2455
|
+
if (type === 'number') {
|
|
2456
|
+
key = String(key)
|
|
2457
|
+
} else if (type !== 'string') {
|
|
2458
|
+
throw TypeError('each key must be a number of string; got ' + type)
|
|
2459
|
+
}
|
|
2207
2460
|
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2461
|
+
// The W3C protocol requires keys to be specified as an array where
|
|
2462
|
+
// each element is a single key.
|
|
2463
|
+
keys.push(...key.split(''))
|
|
2464
|
+
})
|
|
2212
2465
|
|
|
2213
2466
|
if (!this.driver_.fileDetector_) {
|
|
2214
2467
|
return this.execute_(
|
|
@@ -2324,6 +2577,25 @@ class WebElement {
|
|
|
2324
2577
|
return this.execute_(new command.Command(command.Name.GET_ELEMENT_TEXT))
|
|
2325
2578
|
}
|
|
2326
2579
|
|
|
2580
|
+
/**
|
|
2581
|
+
* Get the computed WAI-ARIA role of element.
|
|
2582
|
+
*
|
|
2583
|
+
* @return {!Promise<string>} A promise that will be
|
|
2584
|
+
* resolved with the element's computed role.
|
|
2585
|
+
*/
|
|
2586
|
+
getAriaRole() {
|
|
2587
|
+
return this.execute_(new command.Command(command.Name.GET_COMPUTED_ROLE))
|
|
2588
|
+
}
|
|
2589
|
+
|
|
2590
|
+
/**
|
|
2591
|
+
* Get the computed WAI-ARIA label of element.
|
|
2592
|
+
*
|
|
2593
|
+
* @return {!Promise<string>} A promise that will be
|
|
2594
|
+
* resolved with the element's computed label.
|
|
2595
|
+
*/
|
|
2596
|
+
getAccessibleName() {
|
|
2597
|
+
return this.execute_(new command.Command(command.Name.GET_COMPUTED_LABEL))
|
|
2598
|
+
}
|
|
2327
2599
|
/**
|
|
2328
2600
|
* Returns an object describing an element's location, in pixels relative to
|
|
2329
2601
|
* the document element, and the element's size in pixels.
|
package/net/index.js
CHANGED
|
File without changes
|
package/net/portprober.js
CHANGED
|
@@ -52,21 +52,21 @@ function isFree(port, opt_host) {
|
|
|
52
52
|
|
|
53
53
|
function findFreePort(opt_host) {
|
|
54
54
|
return new Promise((resolve, reject) => {
|
|
55
|
-
const server = net.createServer()
|
|
56
|
-
server.on('listening', function() {
|
|
57
|
-
resolve(server.address().port)
|
|
58
|
-
server.close()
|
|
59
|
-
})
|
|
55
|
+
const server = net.createServer()
|
|
56
|
+
server.on('listening', function () {
|
|
57
|
+
resolve(server.address().port)
|
|
58
|
+
server.close()
|
|
59
|
+
})
|
|
60
60
|
server.on('error', (e) => {
|
|
61
61
|
if (e.code === 'EADDRINUSE' || e.code === 'EACCES') {
|
|
62
62
|
resolve('Unable to find a free port')
|
|
63
63
|
} else {
|
|
64
64
|
reject(e)
|
|
65
65
|
}
|
|
66
|
-
})
|
|
66
|
+
})
|
|
67
67
|
// By providing 0 we let the operative system find an arbitrary port
|
|
68
|
-
server.listen(0, opt_host)
|
|
69
|
-
})
|
|
68
|
+
server.listen(0, opt_host)
|
|
69
|
+
})
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
// PUBLIC API
|
package/opera.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "selenium-webdriver",
|
|
3
|
-
"version": "4.0.0-
|
|
3
|
+
"version": "4.0.0-beta.1",
|
|
4
4
|
"description": "The official WebDriver JavaScript bindings from the Selenium project",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"keywords": [
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"webdriver",
|
|
11
11
|
"webdriverjs"
|
|
12
12
|
],
|
|
13
|
-
"homepage": "https://github.com/SeleniumHQ/selenium",
|
|
13
|
+
"homepage": "https://github.com/SeleniumHQ/selenium/tree/trunk/javascript/node/selenium-webdriver#readme",
|
|
14
14
|
"bugs": {
|
|
15
15
|
"url": "https://github.com/SeleniumHQ/selenium/issues"
|
|
16
16
|
},
|
|
@@ -25,25 +25,25 @@
|
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"jszip": "^3.5.0",
|
|
27
27
|
"rimraf": "^2.7.1",
|
|
28
|
-
"tmp": "^0.1
|
|
28
|
+
"tmp": "^0.2.1",
|
|
29
29
|
"ws": "^7.3.1"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"eslint": "^7.
|
|
33
|
-
"eslint-config-prettier": "^
|
|
32
|
+
"eslint": "^7.15.0",
|
|
33
|
+
"eslint-config-prettier": "^7.0.0",
|
|
34
34
|
"eslint-plugin-no-only-tests": "^2.4.0",
|
|
35
35
|
"eslint-plugin-node": "^11.1.0",
|
|
36
|
-
"eslint-plugin-prettier": "^3.
|
|
36
|
+
"eslint-plugin-prettier": "^3.2.0",
|
|
37
37
|
"express": "^4.17.1",
|
|
38
38
|
"jasmine": "^3.6.1",
|
|
39
39
|
"mocha": "^8.1.0",
|
|
40
40
|
"multer": "^1.4.2",
|
|
41
|
-
"prettier": "^2.
|
|
41
|
+
"prettier": "^2.2.1",
|
|
42
42
|
"serve-index": "^1.9.1",
|
|
43
43
|
"sinon": "^7.5.0"
|
|
44
44
|
},
|
|
45
45
|
"scripts": {
|
|
46
|
-
"lint": "eslint --ignore-pattern node_modules --ignore-pattern generator --ext js \"**/*.js\"",
|
|
46
|
+
"lint": "eslint --ignore-pattern node_modules --ignore-pattern generator --ext js lib/http.js \"**/*.js\"",
|
|
47
47
|
"test": "npm run lint && mocha -t 600000 --recursive test",
|
|
48
48
|
"test-jasmine": "jasmine JASMINE_CONFIG_PATH=jasmine.json"
|
|
49
49
|
},
|
package/proxy.js
CHANGED
|
File without changes
|
package/remote/index.js
CHANGED
|
File without changes
|