selenium-webdriver 4.1.0 → 4.2.0
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 +506 -565
- package/LICENSE +1 -1
- package/NOTICE +1 -1
- package/README.md +4 -4
- package/chrome.js +13 -10
- package/chromium.js +48 -9
- package/edge.js +10 -8
- package/example/google_search.js +1 -1
- package/firefox.js +32 -17
- package/index.js +4 -50
- package/io/exec.js +2 -1
- package/io/index.js +23 -21
- package/io/zip.js +1 -3
- package/lib/by.js +6 -6
- package/lib/capabilities.js +0 -8
- package/lib/command.js +1 -11
- package/lib/error.js +1 -20
- package/lib/http.js +66 -161
- package/lib/input.js +71 -5
- package/lib/promise.js +12 -17
- package/lib/proxy.js +15 -5
- package/lib/session.js +1 -1
- package/lib/until.js +14 -16
- package/lib/webdriver.js +151 -143
- package/net/index.js +15 -8
- package/net/portprober.js +4 -3
- package/package.json +2 -2
- package/remote/index.js +12 -9
- package/safari.js +3 -3
- package/testing/index.js +18 -13
- package/opera.js +0 -406
package/lib/until.js
CHANGED
|
@@ -137,14 +137,13 @@ exports.alertIsPresent = function alertIsPresent() {
|
|
|
137
137
|
* @return {!Condition<boolean>} The new condition.
|
|
138
138
|
*/
|
|
139
139
|
exports.titleIs = function titleIs(title) {
|
|
140
|
-
return new Condition(
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
)
|
|
140
|
+
return new Condition('for title to be ' + JSON.stringify(title), function (
|
|
141
|
+
driver
|
|
142
|
+
) {
|
|
143
|
+
return driver.getTitle().then(function (t) {
|
|
144
|
+
return t === title
|
|
145
|
+
})
|
|
146
|
+
})
|
|
148
147
|
}
|
|
149
148
|
|
|
150
149
|
/**
|
|
@@ -189,14 +188,13 @@ exports.titleMatches = function titleMatches(regex) {
|
|
|
189
188
|
* @return {!Condition<boolean>} The new condition.
|
|
190
189
|
*/
|
|
191
190
|
exports.urlIs = function urlIs(url) {
|
|
192
|
-
return new Condition(
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
)
|
|
191
|
+
return new Condition('for URL to be ' + JSON.stringify(url), function (
|
|
192
|
+
driver
|
|
193
|
+
) {
|
|
194
|
+
return driver.getCurrentUrl().then(function (u) {
|
|
195
|
+
return u === url
|
|
196
|
+
})
|
|
197
|
+
})
|
|
200
198
|
}
|
|
201
199
|
|
|
202
200
|
/**
|
package/lib/webdriver.js
CHANGED
|
@@ -250,30 +250,30 @@ class IWebDriver {
|
|
|
250
250
|
* result.
|
|
251
251
|
* @template T
|
|
252
252
|
*/
|
|
253
|
-
execute(command) {
|
|
253
|
+
execute(command) {} // eslint-disable-line
|
|
254
254
|
|
|
255
255
|
/**
|
|
256
256
|
* Sets the {@linkplain input.FileDetector file detector} that should be
|
|
257
257
|
* used with this instance.
|
|
258
258
|
* @param {input.FileDetector} detector The detector to use or `null`.
|
|
259
259
|
*/
|
|
260
|
-
setFileDetector(detector) {
|
|
260
|
+
setFileDetector(detector) {} // eslint-disable-line
|
|
261
261
|
|
|
262
262
|
/**
|
|
263
263
|
* @return {!command.Executor} The command executor used by this instance.
|
|
264
264
|
*/
|
|
265
|
-
getExecutor() {
|
|
265
|
+
getExecutor() {}
|
|
266
266
|
|
|
267
267
|
/**
|
|
268
268
|
* @return {!Promise<!Session>} A promise for this client's session.
|
|
269
269
|
*/
|
|
270
|
-
getSession() {
|
|
270
|
+
getSession() {}
|
|
271
271
|
|
|
272
272
|
/**
|
|
273
273
|
* @return {!Promise<!Capabilities>} A promise that will resolve with
|
|
274
274
|
* the this instance's capabilities.
|
|
275
275
|
*/
|
|
276
|
-
getCapabilities() {
|
|
276
|
+
getCapabilities() {}
|
|
277
277
|
|
|
278
278
|
/**
|
|
279
279
|
* Terminates the browser session. After calling quit, this instance will be
|
|
@@ -283,7 +283,7 @@ class IWebDriver {
|
|
|
283
283
|
* @return {!Promise<void>} A promise that will be resolved when the
|
|
284
284
|
* command has completed.
|
|
285
285
|
*/
|
|
286
|
-
quit() {
|
|
286
|
+
quit() {}
|
|
287
287
|
|
|
288
288
|
/**
|
|
289
289
|
* Creates a new action sequence using this driver. The sequence will not be
|
|
@@ -296,7 +296,7 @@ class IWebDriver {
|
|
|
296
296
|
* for details).
|
|
297
297
|
* @return {!input.Actions} A new action sequence for this instance.
|
|
298
298
|
*/
|
|
299
|
-
actions(options) {
|
|
299
|
+
actions(options) {} // eslint-disable-line
|
|
300
300
|
|
|
301
301
|
/**
|
|
302
302
|
* Executes a snippet of JavaScript in the context of the currently selected
|
|
@@ -334,7 +334,7 @@ class IWebDriver {
|
|
|
334
334
|
* scripts return value.
|
|
335
335
|
* @template T
|
|
336
336
|
*/
|
|
337
|
-
executeScript(script, ...args) {
|
|
337
|
+
executeScript(script, ...args) {} // eslint-disable-line
|
|
338
338
|
|
|
339
339
|
/**
|
|
340
340
|
* Executes a snippet of asynchronous JavaScript in the context of the
|
|
@@ -411,7 +411,7 @@ class IWebDriver {
|
|
|
411
411
|
* value.
|
|
412
412
|
* @template T
|
|
413
413
|
*/
|
|
414
|
-
executeAsyncScript(script, ...args) {
|
|
414
|
+
executeAsyncScript(script, ...args) {} // eslint-disable-line
|
|
415
415
|
|
|
416
416
|
/**
|
|
417
417
|
* Waits for a condition to evaluate to a "truthy" value. The condition may be
|
|
@@ -462,7 +462,7 @@ class IWebDriver {
|
|
|
462
462
|
timeout = undefined, // eslint-disable-line
|
|
463
463
|
message = undefined, // eslint-disable-line
|
|
464
464
|
pollTimeout = undefined // eslint-disable-line
|
|
465
|
-
) {
|
|
465
|
+
) {}
|
|
466
466
|
|
|
467
467
|
/**
|
|
468
468
|
* Makes the driver sleep for the given amount of time.
|
|
@@ -471,7 +471,7 @@ class IWebDriver {
|
|
|
471
471
|
* @return {!Promise<void>} A promise that will be resolved when the sleep has
|
|
472
472
|
* finished.
|
|
473
473
|
*/
|
|
474
|
-
sleep(ms) {
|
|
474
|
+
sleep(ms) {} // eslint-disable-line
|
|
475
475
|
|
|
476
476
|
/**
|
|
477
477
|
* Retrieves the current window handle.
|
|
@@ -479,7 +479,7 @@ class IWebDriver {
|
|
|
479
479
|
* @return {!Promise<string>} A promise that will be resolved with the current
|
|
480
480
|
* window handle.
|
|
481
481
|
*/
|
|
482
|
-
getWindowHandle() {
|
|
482
|
+
getWindowHandle() {}
|
|
483
483
|
|
|
484
484
|
/**
|
|
485
485
|
* Retrieves a list of all available window handles.
|
|
@@ -487,7 +487,7 @@ class IWebDriver {
|
|
|
487
487
|
* @return {!Promise<!Array<string>>} A promise that will be resolved with an
|
|
488
488
|
* array of window handles.
|
|
489
489
|
*/
|
|
490
|
-
getAllWindowHandles() {
|
|
490
|
+
getAllWindowHandles() {}
|
|
491
491
|
|
|
492
492
|
/**
|
|
493
493
|
* Retrieves the current page's source. The returned source is a representation
|
|
@@ -497,7 +497,7 @@ class IWebDriver {
|
|
|
497
497
|
* @return {!Promise<string>} A promise that will be resolved with the current
|
|
498
498
|
* page source.
|
|
499
499
|
*/
|
|
500
|
-
getPageSource() {
|
|
500
|
+
getPageSource() {}
|
|
501
501
|
|
|
502
502
|
/**
|
|
503
503
|
* Closes the current window.
|
|
@@ -505,7 +505,7 @@ class IWebDriver {
|
|
|
505
505
|
* @return {!Promise<void>} A promise that will be resolved when this command
|
|
506
506
|
* has completed.
|
|
507
507
|
*/
|
|
508
|
-
close() {
|
|
508
|
+
close() {}
|
|
509
509
|
|
|
510
510
|
/**
|
|
511
511
|
* Navigates to the given URL.
|
|
@@ -514,7 +514,7 @@ class IWebDriver {
|
|
|
514
514
|
* @return {!Promise<void>} A promise that will be resolved when the document
|
|
515
515
|
* has finished loading.
|
|
516
516
|
*/
|
|
517
|
-
get(url) {
|
|
517
|
+
get(url) {} // eslint-disable-line
|
|
518
518
|
|
|
519
519
|
/**
|
|
520
520
|
* Retrieves the URL for the current page.
|
|
@@ -522,7 +522,7 @@ class IWebDriver {
|
|
|
522
522
|
* @return {!Promise<string>} A promise that will be resolved with the
|
|
523
523
|
* current URL.
|
|
524
524
|
*/
|
|
525
|
-
getCurrentUrl() {
|
|
525
|
+
getCurrentUrl() {}
|
|
526
526
|
|
|
527
527
|
/**
|
|
528
528
|
* Retrieves the current page title.
|
|
@@ -530,7 +530,7 @@ class IWebDriver {
|
|
|
530
530
|
* @return {!Promise<string>} A promise that will be resolved with the current
|
|
531
531
|
* page's title.
|
|
532
532
|
*/
|
|
533
|
-
getTitle() {
|
|
533
|
+
getTitle() {}
|
|
534
534
|
|
|
535
535
|
/**
|
|
536
536
|
* Locates an element on the page. If the element cannot be found, a
|
|
@@ -570,7 +570,7 @@ class IWebDriver {
|
|
|
570
570
|
* commands against the located element. If the element is not found, the
|
|
571
571
|
* element will be invalidated and all scheduled commands aborted.
|
|
572
572
|
*/
|
|
573
|
-
findElement(locator) {
|
|
573
|
+
findElement(locator) {} // eslint-disable-line
|
|
574
574
|
|
|
575
575
|
/**
|
|
576
576
|
* Search for multiple elements on the page. Refer to the documentation on
|
|
@@ -580,7 +580,7 @@ class IWebDriver {
|
|
|
580
580
|
* @return {!Promise<!Array<!WebElement>>} A promise that will resolve to an
|
|
581
581
|
* array of WebElements.
|
|
582
582
|
*/
|
|
583
|
-
findElements(locator) {
|
|
583
|
+
findElements(locator) {} // eslint-disable-line
|
|
584
584
|
|
|
585
585
|
/**
|
|
586
586
|
* Takes a screenshot of the current page. The driver makes a best effort to
|
|
@@ -594,23 +594,23 @@ class IWebDriver {
|
|
|
594
594
|
* @return {!Promise<string>} A promise that will be resolved to the
|
|
595
595
|
* screenshot as a base-64 encoded PNG.
|
|
596
596
|
*/
|
|
597
|
-
takeScreenshot() {
|
|
597
|
+
takeScreenshot() {}
|
|
598
598
|
|
|
599
599
|
/**
|
|
600
600
|
* @return {!Options} The options interface for this instance.
|
|
601
601
|
*/
|
|
602
|
-
manage() {
|
|
602
|
+
manage() {}
|
|
603
603
|
|
|
604
604
|
/**
|
|
605
605
|
* @return {!Navigation} The navigation interface for this instance.
|
|
606
606
|
*/
|
|
607
|
-
navigate() {
|
|
607
|
+
navigate() {}
|
|
608
608
|
|
|
609
609
|
/**
|
|
610
610
|
* @return {!TargetLocator} The target locator interface for this
|
|
611
611
|
* instance.
|
|
612
612
|
*/
|
|
613
|
-
switchTo() {
|
|
613
|
+
switchTo() {}
|
|
614
614
|
|
|
615
615
|
/**
|
|
616
616
|
*
|
|
@@ -629,7 +629,7 @@ class IWebDriver {
|
|
|
629
629
|
* shrinkToFit: (boolean|undefined)
|
|
630
630
|
* pageRanges: (<Array>|undefined)}} options.
|
|
631
631
|
*/
|
|
632
|
-
printPage(options) {
|
|
632
|
+
printPage(options) {} // eslint-disable-line
|
|
633
633
|
}
|
|
634
634
|
|
|
635
635
|
/**
|
|
@@ -669,7 +669,7 @@ class WebDriver {
|
|
|
669
669
|
// If session is a rejected promise, add a no-op rejection handler.
|
|
670
670
|
// This effectively hides setup errors until users attempt to interact
|
|
671
671
|
// with the session.
|
|
672
|
-
this.session_.catch(function () {
|
|
672
|
+
this.session_.catch(function () {})
|
|
673
673
|
|
|
674
674
|
/** @private {!command.Executor} */
|
|
675
675
|
this.executor_ = executor
|
|
@@ -765,12 +765,12 @@ class WebDriver {
|
|
|
765
765
|
this.session_ = Promise.reject(
|
|
766
766
|
new error.NoSuchSessionError(
|
|
767
767
|
'This driver instance does not have a valid session ID ' +
|
|
768
|
-
|
|
768
|
+
'(did you call WebDriver.quit()?) and may no longer be used.'
|
|
769
769
|
)
|
|
770
770
|
)
|
|
771
771
|
|
|
772
772
|
// Only want the session rejection to bubble if accessed.
|
|
773
|
-
this.session_.catch(function () {
|
|
773
|
+
this.session_.catch(function () {})
|
|
774
774
|
|
|
775
775
|
if (this.onQuit_) {
|
|
776
776
|
return this.onQuit_.call(void 0)
|
|
@@ -831,15 +831,18 @@ class WebDriver {
|
|
|
831
831
|
let timeoutMessage = resolveWaitMessage(message)
|
|
832
832
|
reject(
|
|
833
833
|
new error.TimeoutError(
|
|
834
|
-
`${timeoutMessage}Timed out waiting for promise to resolve after ${
|
|
834
|
+
`${timeoutMessage}Timed out waiting for promise to resolve after ${
|
|
835
|
+
Date.now() - start
|
|
835
836
|
}ms`
|
|
836
837
|
)
|
|
837
838
|
)
|
|
838
839
|
} catch (ex) {
|
|
839
840
|
reject(
|
|
840
841
|
new error.TimeoutError(
|
|
841
|
-
`${
|
|
842
|
-
|
|
842
|
+
`${
|
|
843
|
+
ex.message
|
|
844
|
+
}\nTimed out waiting for promise to resolve after ${
|
|
845
|
+
Date.now() - start
|
|
843
846
|
}ms`
|
|
844
847
|
)
|
|
845
848
|
)
|
|
@@ -869,7 +872,7 @@ class WebDriver {
|
|
|
869
872
|
if (typeof fn !== 'function') {
|
|
870
873
|
throw TypeError(
|
|
871
874
|
'Wait condition must be a promise-like object, function, or a ' +
|
|
872
|
-
|
|
875
|
+
'Condition object'
|
|
873
876
|
)
|
|
874
877
|
}
|
|
875
878
|
|
|
@@ -921,7 +924,7 @@ class WebDriver {
|
|
|
921
924
|
if (!(value instanceof WebElement)) {
|
|
922
925
|
throw TypeError(
|
|
923
926
|
'WebElementCondition did not resolve to a WebElement: ' +
|
|
924
|
-
|
|
927
|
+
Object.prototype.toString.call(value)
|
|
925
928
|
)
|
|
926
929
|
}
|
|
927
930
|
return value
|
|
@@ -1194,14 +1197,25 @@ class WebDriver {
|
|
|
1194
1197
|
* @return {!Promise<resolved>} A new CDP instance.
|
|
1195
1198
|
*/
|
|
1196
1199
|
async createCDPConnection(target) {
|
|
1200
|
+
let debuggerUrl = null
|
|
1201
|
+
|
|
1197
1202
|
const caps = await this.getCapabilities()
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1203
|
+
|
|
1204
|
+
if (process.env.SELENIUM_REMOTE_URL) {
|
|
1205
|
+
const host = new URL(process.env.SELENIUM_REMOTE_URL).host
|
|
1206
|
+
const sessionId = await this.getSession().then((session) =>
|
|
1207
|
+
session.getId()
|
|
1208
|
+
)
|
|
1209
|
+
debuggerUrl = `ws://${host}/session/${sessionId}/se/cdp`
|
|
1210
|
+
} else {
|
|
1211
|
+
const seCdp = caps['map_'].get('se:cdp')
|
|
1212
|
+
const vendorInfo =
|
|
1213
|
+
caps['map_'].get(this.VENDOR_COMMAND_PREFIX + ':chromeOptions') ||
|
|
1214
|
+
caps['map_'].get(this.VENDOR_CAPABILITY_PREFIX + ':edgeOptions') ||
|
|
1215
|
+
caps['map_'].get('moz:debuggerAddress') ||
|
|
1216
|
+
new Map()
|
|
1217
|
+
debuggerUrl = seCdp || vendorInfo['debuggerAddress'] || vendorInfo
|
|
1218
|
+
}
|
|
1205
1219
|
this._wsUrl = await this.getWsUrl(debuggerUrl, target, caps)
|
|
1206
1220
|
return new Promise((resolve, reject) => {
|
|
1207
1221
|
try {
|
|
@@ -1393,7 +1407,7 @@ class WebDriver {
|
|
|
1393
1407
|
|
|
1394
1408
|
callback(event)
|
|
1395
1409
|
}
|
|
1396
|
-
|
|
1410
|
+
|
|
1397
1411
|
if (params.method === 'Log.entryAdded') {
|
|
1398
1412
|
const logEventParams = params['params']
|
|
1399
1413
|
const logEntry = logEventParams['entry']
|
|
@@ -1405,7 +1419,6 @@ class WebDriver {
|
|
|
1405
1419
|
|
|
1406
1420
|
callback(event)
|
|
1407
1421
|
}
|
|
1408
|
-
|
|
1409
1422
|
})
|
|
1410
1423
|
await connection.execute('Runtime.enable', {}, null)
|
|
1411
1424
|
}
|
|
@@ -1783,7 +1796,7 @@ class Options {
|
|
|
1783
1796
|
} else if (typeof value !== 'undefined') {
|
|
1784
1797
|
throw TypeError(
|
|
1785
1798
|
'invalid timeouts configuration:' +
|
|
1786
|
-
|
|
1799
|
+
` expected "${key}" to be a number, got ${typeof value}`
|
|
1787
1800
|
)
|
|
1788
1801
|
}
|
|
1789
1802
|
}
|
|
@@ -1844,7 +1857,7 @@ function legacyTimeout(driver, type, ms) {
|
|
|
1844
1857
|
*
|
|
1845
1858
|
* @record
|
|
1846
1859
|
*/
|
|
1847
|
-
Options.Cookie = function () {
|
|
1860
|
+
Options.Cookie = function () {}
|
|
1848
1861
|
|
|
1849
1862
|
/**
|
|
1850
1863
|
* The name of the cookie.
|
|
@@ -1943,29 +1956,10 @@ class Window {
|
|
|
1943
1956
|
* @return {!Promise<{x: number, y: number, width: number, height: number}>}
|
|
1944
1957
|
* A promise that will resolve to the window rect of the current window.
|
|
1945
1958
|
*/
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
)
|
|
1951
|
-
} catch (ex) {
|
|
1952
|
-
if (ex instanceof error.UnknownCommandError) {
|
|
1953
|
-
let { width, height } = await this.driver_.execute(
|
|
1954
|
-
new command.Command(command.Name.GET_WINDOW_SIZE).setParameter(
|
|
1955
|
-
'windowHandle',
|
|
1956
|
-
'current'
|
|
1957
|
-
)
|
|
1958
|
-
)
|
|
1959
|
-
let { x, y } = await this.driver_.execute(
|
|
1960
|
-
new command.Command(command.Name.GET_WINDOW_POSITION).setParameter(
|
|
1961
|
-
'windowHandle',
|
|
1962
|
-
'current'
|
|
1963
|
-
)
|
|
1964
|
-
)
|
|
1965
|
-
return { x, y, width, height }
|
|
1966
|
-
}
|
|
1967
|
-
throw ex
|
|
1968
|
-
}
|
|
1959
|
+
getRect() {
|
|
1960
|
+
return this.driver_.execute(
|
|
1961
|
+
new command.Command(command.Name.GET_WINDOW_RECT)
|
|
1962
|
+
)
|
|
1969
1963
|
}
|
|
1970
1964
|
|
|
1971
1965
|
/**
|
|
@@ -1982,39 +1976,15 @@ class Window {
|
|
|
1982
1976
|
* A promise that will resolve to the current window's updated window
|
|
1983
1977
|
* rect.
|
|
1984
1978
|
*/
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
)
|
|
1995
|
-
} catch (ex) {
|
|
1996
|
-
if (ex instanceof error.UnknownCommandError) {
|
|
1997
|
-
if (typeof x === 'number' && typeof y === 'number') {
|
|
1998
|
-
await this.driver_.execute(
|
|
1999
|
-
new command.Command(command.Name.SET_WINDOW_POSITION)
|
|
2000
|
-
.setParameter('windowHandle', 'current')
|
|
2001
|
-
.setParameter('x', x)
|
|
2002
|
-
.setParameter('y', y)
|
|
2003
|
-
)
|
|
2004
|
-
}
|
|
2005
|
-
|
|
2006
|
-
if (typeof width === 'number' && typeof height === 'number') {
|
|
2007
|
-
await this.driver_.execute(
|
|
2008
|
-
new command.Command(command.Name.SET_WINDOW_SIZE)
|
|
2009
|
-
.setParameter('windowHandle', 'current')
|
|
2010
|
-
.setParameter('width', width)
|
|
2011
|
-
.setParameter('height', height)
|
|
2012
|
-
)
|
|
2013
|
-
}
|
|
2014
|
-
return this.getRect()
|
|
2015
|
-
}
|
|
2016
|
-
throw ex
|
|
2017
|
-
}
|
|
1979
|
+
setRect({ x, y, width, height }) {
|
|
1980
|
+
return this.driver_.execute(
|
|
1981
|
+
new command.Command(command.Name.SET_WINDOW_RECT).setParameters({
|
|
1982
|
+
x,
|
|
1983
|
+
y,
|
|
1984
|
+
width,
|
|
1985
|
+
height,
|
|
1986
|
+
})
|
|
1987
|
+
)
|
|
2018
1988
|
}
|
|
2019
1989
|
|
|
2020
1990
|
/**
|
|
@@ -2192,13 +2162,23 @@ class TargetLocator {
|
|
|
2192
2162
|
* If the specified frame can not be found, the returned promise will be
|
|
2193
2163
|
* rejected with a {@linkplain error.NoSuchFrameError}.
|
|
2194
2164
|
*
|
|
2195
|
-
* @param {(number|WebElement|null)} id The frame locator.
|
|
2165
|
+
* @param {(number|string|WebElement|null)} id The frame locator.
|
|
2196
2166
|
* @return {!Promise<void>} A promise that will be resolved
|
|
2197
2167
|
* when the driver has changed focus to the specified frame.
|
|
2198
2168
|
*/
|
|
2199
2169
|
frame(id) {
|
|
2170
|
+
let frameReference = id
|
|
2171
|
+
if (typeof id === 'string') {
|
|
2172
|
+
frameReference = this.driver_
|
|
2173
|
+
.findElement({ id })
|
|
2174
|
+
.catch((_) => this.driver_.findElement({ name: id }))
|
|
2175
|
+
}
|
|
2176
|
+
|
|
2200
2177
|
return this.driver_.execute(
|
|
2201
|
-
new command.Command(command.Name.SWITCH_TO_FRAME).setParameter(
|
|
2178
|
+
new command.Command(command.Name.SWITCH_TO_FRAME).setParameter(
|
|
2179
|
+
'id',
|
|
2180
|
+
frameReference
|
|
2181
|
+
)
|
|
2202
2182
|
)
|
|
2203
2183
|
}
|
|
2204
2184
|
|
|
@@ -2550,18 +2530,18 @@ class WebElement {
|
|
|
2550
2530
|
*/
|
|
2551
2531
|
async sendKeys(...args) {
|
|
2552
2532
|
let keys = []
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2533
|
+
;(await Promise.all(args)).forEach((key) => {
|
|
2534
|
+
let type = typeof key
|
|
2535
|
+
if (type === 'number') {
|
|
2536
|
+
key = String(key)
|
|
2537
|
+
} else if (type !== 'string') {
|
|
2538
|
+
throw TypeError('each key must be a number or string; got ' + type)
|
|
2539
|
+
}
|
|
2560
2540
|
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2541
|
+
// The W3C protocol requires keys to be specified as an array where
|
|
2542
|
+
// each element is a single key.
|
|
2543
|
+
keys.push(...key)
|
|
2544
|
+
})
|
|
2565
2545
|
|
|
2566
2546
|
if (!this.driver_.fileDetector_) {
|
|
2567
2547
|
return this.execute_(
|
|
@@ -2571,10 +2551,18 @@ class WebElement {
|
|
|
2571
2551
|
)
|
|
2572
2552
|
}
|
|
2573
2553
|
|
|
2574
|
-
|
|
2575
|
-
this.driver_
|
|
2576
|
-
|
|
2577
|
-
|
|
2554
|
+
try {
|
|
2555
|
+
keys = await this.driver_.fileDetector_.handleFile(
|
|
2556
|
+
this.driver_,
|
|
2557
|
+
keys.join('')
|
|
2558
|
+
)
|
|
2559
|
+
} catch (ex) {
|
|
2560
|
+
console.log(
|
|
2561
|
+
'Error trying parse string as a file with file detector; sending keys instead' +
|
|
2562
|
+
ex
|
|
2563
|
+
)
|
|
2564
|
+
}
|
|
2565
|
+
|
|
2578
2566
|
return this.execute_(
|
|
2579
2567
|
new command.Command(command.Name.SEND_KEYS_TO_ELEMENT)
|
|
2580
2568
|
.setParameter('text', keys)
|
|
@@ -2651,6 +2639,36 @@ class WebElement {
|
|
|
2651
2639
|
)
|
|
2652
2640
|
}
|
|
2653
2641
|
|
|
2642
|
+
/**
|
|
2643
|
+
* Get the value of the given attribute of the element.
|
|
2644
|
+
* <p>
|
|
2645
|
+
* This method, unlike {@link #getAttribute(String)}, returns the value of the attribute with the
|
|
2646
|
+
* given name but not the property with the same name.
|
|
2647
|
+
* <p>
|
|
2648
|
+
* The following are deemed to be "boolean" attributes, and will return either "true" or null:
|
|
2649
|
+
* <p>
|
|
2650
|
+
* async, autofocus, autoplay, checked, compact, complete, controls, declare, defaultchecked,
|
|
2651
|
+
* defaultselected, defer, disabled, draggable, ended, formnovalidate, hidden, indeterminate,
|
|
2652
|
+
* iscontenteditable, ismap, itemscope, loop, multiple, muted, nohref, noresize, noshade,
|
|
2653
|
+
* novalidate, nowrap, open, paused, pubdate, readonly, required, reversed, scoped, seamless,
|
|
2654
|
+
* seeking, selected, truespeed, willvalidate
|
|
2655
|
+
* <p>
|
|
2656
|
+
* See <a href="https://w3c.github.io/webdriver/#get-element-attribute">W3C WebDriver specification</a>
|
|
2657
|
+
* for more details.
|
|
2658
|
+
*
|
|
2659
|
+
* @param attributeName The name of the attribute.
|
|
2660
|
+
* @return The attribute's value or null if the value is not set.
|
|
2661
|
+
*/
|
|
2662
|
+
|
|
2663
|
+
getDomAttribute(attributeName) {
|
|
2664
|
+
return this.execute_(
|
|
2665
|
+
new command.Command(command.Name.GET_DOM_ATTRIBUTE).setParameter(
|
|
2666
|
+
'name',
|
|
2667
|
+
attributeName
|
|
2668
|
+
)
|
|
2669
|
+
)
|
|
2670
|
+
}
|
|
2671
|
+
|
|
2654
2672
|
/**
|
|
2655
2673
|
* Get the given property of the referenced web element
|
|
2656
2674
|
* @param {string} propertyName The name of the attribute to query.
|
|
@@ -2713,22 +2731,8 @@ class WebElement {
|
|
|
2713
2731
|
* @return {!Promise<{width: number, height: number, x: number, y: number}>}
|
|
2714
2732
|
* A promise that will resolve with the element's rect.
|
|
2715
2733
|
*/
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
return await this.execute_(
|
|
2719
|
-
new command.Command(command.Name.GET_ELEMENT_RECT)
|
|
2720
|
-
)
|
|
2721
|
-
} catch (err) {
|
|
2722
|
-
if (err instanceof error.UnknownCommandError) {
|
|
2723
|
-
const { width, height } = await this.execute_(
|
|
2724
|
-
new command.Command(command.Name.GET_ELEMENT_SIZE)
|
|
2725
|
-
)
|
|
2726
|
-
const { x, y } = await this.execute_(
|
|
2727
|
-
new command.Command(command.Name.GET_ELEMENT_LOCATION)
|
|
2728
|
-
)
|
|
2729
|
-
return { x, y, width, height }
|
|
2730
|
-
}
|
|
2731
|
-
}
|
|
2734
|
+
getRect() {
|
|
2735
|
+
return this.execute_(new command.Command(command.Name.GET_ELEMENT_RECT))
|
|
2732
2736
|
}
|
|
2733
2737
|
|
|
2734
2738
|
/**
|
|
@@ -2761,13 +2765,17 @@ class WebElement {
|
|
|
2761
2765
|
* when the form has been submitted.
|
|
2762
2766
|
*/
|
|
2763
2767
|
submit() {
|
|
2764
|
-
const
|
|
2765
|
-
|
|
2766
|
-
"
|
|
2767
|
-
"
|
|
2768
|
-
|
|
2769
|
-
form
|
|
2770
|
-
|
|
2768
|
+
const script = "var form = arguments[0];\n" +
|
|
2769
|
+
"while (form.nodeName != \"FORM\" && form.parentNode) {\n" +
|
|
2770
|
+
" form = form.parentNode;\n" +
|
|
2771
|
+
"}\n" +
|
|
2772
|
+
"if (!form) { throw Error('Unable to find containing form element'); }\n" +
|
|
2773
|
+
"if (!form.ownerDocument) { throw Error('Unable to find owning document'); }\n" +
|
|
2774
|
+
"var e = form.ownerDocument.createEvent('Event');\n" +
|
|
2775
|
+
"e.initEvent('submit', true, true);\n" +
|
|
2776
|
+
"if (form.dispatchEvent(e)) { HTMLFormElement.prototype.submit.call(form) }\n";
|
|
2777
|
+
|
|
2778
|
+
this.driver_.executeScript(script, this);
|
|
2771
2779
|
}
|
|
2772
2780
|
|
|
2773
2781
|
/**
|
|
@@ -2861,7 +2869,6 @@ class WebElementPromise extends WebElement {
|
|
|
2861
2869
|
* retrieve elements that live in the DOM below the ShadowRoot.
|
|
2862
2870
|
*/
|
|
2863
2871
|
class ShadowRoot {
|
|
2864
|
-
|
|
2865
2872
|
constructor(driver, id) {
|
|
2866
2873
|
this.driver_ = driver
|
|
2867
2874
|
this.id_ = id
|
|
@@ -2891,7 +2898,8 @@ class ShadowRoot {
|
|
|
2891
2898
|
return (
|
|
2892
2899
|
obj &&
|
|
2893
2900
|
typeof obj === 'object' &&
|
|
2894
|
-
typeof obj[SHADOWROOT_ID_KEY] === 'string'
|
|
2901
|
+
typeof obj[SHADOWROOT_ID_KEY] === 'string'
|
|
2902
|
+
)
|
|
2895
2903
|
}
|
|
2896
2904
|
|
|
2897
2905
|
/**
|
|
@@ -3005,7 +3013,7 @@ class ShadowRootPromise extends ShadowRoot {
|
|
|
3005
3013
|
/**
|
|
3006
3014
|
* @param {!WebDriver} driver The parent WebDriver instance for this
|
|
3007
3015
|
* element.
|
|
3008
|
-
* @param {!Promise<!ShadowRoot>}
|
|
3016
|
+
* @param {!Promise<!ShadowRoot>} shadow A promise
|
|
3009
3017
|
* that will resolve to the promised element.
|
|
3010
3018
|
*/
|
|
3011
3019
|
constructor(driver, shadow) {
|