selenium-webdriver 4.0.0-alpha.4 → 4.0.0-alpha.8
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/.eslintrc.js +27 -0
- package/.prettierrc +4 -0
- package/CHANGES.md +22 -1
- package/README.md +4 -4
- package/chrome.js +72 -590
- package/chromium.js +1024 -0
- package/devtools/CDPConnection.js +37 -0
- package/devtools/generator/protocol-dts-generator.js +429 -0
- package/edge.js +124 -86
- package/firefox.js +201 -202
- package/http/index.js +131 -115
- package/http/util.js +56 -64
- package/ie.js +180 -104
- package/index.js +246 -199
- package/io/exec.js +34 -39
- package/io/index.js +141 -151
- package/io/zip.js +75 -65
- package/lib/README +5 -0
- package/lib/actions.js +138 -121
- package/lib/atoms/find-elements.js +123 -0
- package/lib/atoms/get-attribute.js +79 -60
- package/lib/atoms/is-displayed.js +72 -73
- package/{example/chrome_mobile_emulation.js → lib/atoms/make-atoms-module.js} +16 -23
- package/lib/by.js +192 -65
- package/lib/capabilities.js +82 -78
- package/lib/command.js +18 -20
- package/lib/error.js +134 -168
- package/lib/http.js +324 -230
- package/lib/input.js +325 -302
- package/lib/logging.js +127 -138
- package/lib/promise.js +60 -66
- package/lib/proxy.js +31 -41
- package/lib/session.js +12 -15
- package/lib/symbols.js +3 -4
- package/lib/until.js +162 -162
- package/lib/webdriver.js +733 -522
- package/net/index.js +30 -36
- package/net/portprober.js +31 -144
- package/opera.js +406 -0
- package/package.json +18 -11
- package/proxy.js +2 -2
- package/remote/index.js +190 -187
- package/safari.js +40 -49
- package/LICENSE +0 -202
- package/NOTICE +0 -2
- package/example/chrome_android.js +0 -42
- package/example/firefox_channels.js +0 -77
- package/example/google_search.js +0 -50
- package/example/google_search_test.js +0 -72
- package/example/headless.js +0 -55
- package/example/logging.js +0 -68
- package/testing/index.js +0 -498
package/lib/webdriver.js
CHANGED
|
@@ -19,32 +19,31 @@
|
|
|
19
19
|
* @fileoverview The heart of the WebDriver JavaScript API.
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
'use strict'
|
|
23
|
-
|
|
24
|
-
const by = require('./by')
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
const {
|
|
33
|
-
|
|
22
|
+
'use strict'
|
|
23
|
+
|
|
24
|
+
const by = require('./by')
|
|
25
|
+
const { RelativeBy } = require('./by')
|
|
26
|
+
const command = require('./command')
|
|
27
|
+
const error = require('./error')
|
|
28
|
+
const input = require('./input')
|
|
29
|
+
const logging = require('./logging')
|
|
30
|
+
const promise = require('./promise')
|
|
31
|
+
const Symbols = require('./symbols')
|
|
32
|
+
const { Capabilities } = require('./capabilities')
|
|
34
33
|
|
|
35
34
|
// Capability names that are defined in the W3C spec.
|
|
36
35
|
const W3C_CAPABILITY_NAMES = new Set([
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
36
|
+
'acceptInsecureCerts',
|
|
37
|
+
'browserName',
|
|
38
|
+
'browserVersion',
|
|
39
|
+
'platformName',
|
|
40
|
+
'pageLoadStrategy',
|
|
41
|
+
'proxy',
|
|
42
|
+
'setWindowRect',
|
|
43
|
+
'timeouts',
|
|
44
|
+
'strictFileInteractability',
|
|
45
|
+
'unhandledPromptBehavior',
|
|
46
|
+
])
|
|
48
47
|
|
|
49
48
|
/**
|
|
50
49
|
* Defines a condition for use with WebDriver's {@linkplain WebDriver#wait wait
|
|
@@ -61,19 +60,18 @@ class Condition {
|
|
|
61
60
|
*/
|
|
62
61
|
constructor(message, fn) {
|
|
63
62
|
/** @private {string} */
|
|
64
|
-
this.description_ = 'Waiting ' + message
|
|
63
|
+
this.description_ = 'Waiting ' + message
|
|
65
64
|
|
|
66
65
|
/** @type {function(!WebDriver): OUT} */
|
|
67
|
-
this.fn = fn
|
|
66
|
+
this.fn = fn
|
|
68
67
|
}
|
|
69
68
|
|
|
70
69
|
/** @return {string} A description of this condition. */
|
|
71
70
|
description() {
|
|
72
|
-
return this.description_
|
|
71
|
+
return this.description_
|
|
73
72
|
}
|
|
74
73
|
}
|
|
75
74
|
|
|
76
|
-
|
|
77
75
|
/**
|
|
78
76
|
* Defines a condition that will result in a {@link WebElement}.
|
|
79
77
|
*
|
|
@@ -88,18 +86,16 @@ class WebElementCondition extends Condition {
|
|
|
88
86
|
* loop.
|
|
89
87
|
*/
|
|
90
88
|
constructor(message, fn) {
|
|
91
|
-
super(message, fn)
|
|
89
|
+
super(message, fn)
|
|
92
90
|
}
|
|
93
91
|
}
|
|
94
92
|
|
|
95
|
-
|
|
96
93
|
//////////////////////////////////////////////////////////////////////////////
|
|
97
94
|
//
|
|
98
95
|
// WebDriver
|
|
99
96
|
//
|
|
100
97
|
//////////////////////////////////////////////////////////////////////////////
|
|
101
98
|
|
|
102
|
-
|
|
103
99
|
/**
|
|
104
100
|
* Translates a command to its wire-protocol representation before passing it
|
|
105
101
|
* to the given `executor` for execution.
|
|
@@ -108,14 +104,12 @@ class WebElementCondition extends Condition {
|
|
|
108
104
|
* @return {!Promise} A promise that will resolve with the command response.
|
|
109
105
|
*/
|
|
110
106
|
function executeCommand(executor, command) {
|
|
111
|
-
return toWireValue(command.getParameters()).
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
});
|
|
107
|
+
return toWireValue(command.getParameters()).then(function (parameters) {
|
|
108
|
+
command.setParameters(parameters)
|
|
109
|
+
return executor.execute(command)
|
|
110
|
+
})
|
|
116
111
|
}
|
|
117
112
|
|
|
118
|
-
|
|
119
113
|
/**
|
|
120
114
|
* Converts an object to its JSON representation in the WebDriver wire protocol.
|
|
121
115
|
* When converting values of type object, the following steps will be taken:
|
|
@@ -135,64 +129,62 @@ function executeCommand(executor, command) {
|
|
|
135
129
|
* representation.
|
|
136
130
|
*/
|
|
137
131
|
async function toWireValue(obj) {
|
|
138
|
-
let value = await Promise.resolve(obj)
|
|
132
|
+
let value = await Promise.resolve(obj)
|
|
139
133
|
if (value === void 0 || value === null) {
|
|
140
|
-
return value
|
|
134
|
+
return value
|
|
141
135
|
}
|
|
142
136
|
|
|
143
|
-
if (
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
137
|
+
if (
|
|
138
|
+
typeof value === 'boolean' ||
|
|
139
|
+
typeof value === 'number' ||
|
|
140
|
+
typeof value === 'string'
|
|
141
|
+
) {
|
|
142
|
+
return value
|
|
147
143
|
}
|
|
148
144
|
|
|
149
145
|
if (Array.isArray(value)) {
|
|
150
|
-
return convertKeys(value)
|
|
146
|
+
return convertKeys(value)
|
|
151
147
|
}
|
|
152
148
|
|
|
153
149
|
if (typeof value === 'function') {
|
|
154
|
-
return '' + value
|
|
150
|
+
return '' + value
|
|
155
151
|
}
|
|
156
152
|
|
|
157
153
|
if (typeof value[Symbols.serialize] === 'function') {
|
|
158
|
-
return toWireValue(value[Symbols.serialize]())
|
|
154
|
+
return toWireValue(value[Symbols.serialize]())
|
|
159
155
|
} else if (typeof value.toJSON === 'function') {
|
|
160
|
-
return toWireValue(value.toJSON())
|
|
156
|
+
return toWireValue(value.toJSON())
|
|
161
157
|
}
|
|
162
|
-
return convertKeys(value)
|
|
158
|
+
return convertKeys(value)
|
|
163
159
|
}
|
|
164
160
|
|
|
165
|
-
|
|
166
161
|
async function convertKeys(obj) {
|
|
167
|
-
const isArray = Array.isArray(obj)
|
|
168
|
-
const numKeys = isArray ? obj.length : Object.keys(obj).length
|
|
169
|
-
const ret = isArray ? new Array(numKeys) : {}
|
|
162
|
+
const isArray = Array.isArray(obj)
|
|
163
|
+
const numKeys = isArray ? obj.length : Object.keys(obj).length
|
|
164
|
+
const ret = isArray ? new Array(numKeys) : {}
|
|
170
165
|
if (!numKeys) {
|
|
171
|
-
return ret
|
|
166
|
+
return ret
|
|
172
167
|
}
|
|
173
168
|
|
|
174
|
-
let numResolved = 0;
|
|
175
|
-
|
|
176
169
|
async function forEachKey(obj, fn) {
|
|
177
170
|
if (Array.isArray(obj)) {
|
|
178
171
|
for (let i = 0, n = obj.length; i < n; i++) {
|
|
179
|
-
await fn(obj[i], i)
|
|
172
|
+
await fn(obj[i], i)
|
|
180
173
|
}
|
|
181
174
|
} else {
|
|
182
175
|
for (let key in obj) {
|
|
183
|
-
await fn(obj[key], key)
|
|
176
|
+
await fn(obj[key], key)
|
|
184
177
|
}
|
|
185
178
|
}
|
|
186
179
|
}
|
|
187
180
|
|
|
188
|
-
await forEachKey(obj, async function(value, key) {
|
|
189
|
-
ret[key] = await toWireValue(value)
|
|
190
|
-
})
|
|
181
|
+
await forEachKey(obj, async function (value, key) {
|
|
182
|
+
ret[key] = await toWireValue(value)
|
|
183
|
+
})
|
|
191
184
|
|
|
192
|
-
return ret
|
|
185
|
+
return ret
|
|
193
186
|
}
|
|
194
187
|
|
|
195
|
-
|
|
196
188
|
/**
|
|
197
189
|
* Converts a value from its JSON representation according to the WebDriver wire
|
|
198
190
|
* protocol. Any JSON object that defines a WebElement ID will be decoded to a
|
|
@@ -205,22 +197,32 @@ async function convertKeys(obj) {
|
|
|
205
197
|
*/
|
|
206
198
|
function fromWireValue(driver, value) {
|
|
207
199
|
if (Array.isArray(value)) {
|
|
208
|
-
value = value.map(v => fromWireValue(driver, v))
|
|
200
|
+
value = value.map((v) => fromWireValue(driver, v))
|
|
209
201
|
} else if (WebElement.isId(value)) {
|
|
210
|
-
let id = WebElement.extractId(value)
|
|
211
|
-
value = new WebElement(driver, id)
|
|
202
|
+
let id = WebElement.extractId(value)
|
|
203
|
+
value = new WebElement(driver, id)
|
|
212
204
|
} else if (value && typeof value === 'object') {
|
|
213
|
-
let result = {}
|
|
205
|
+
let result = {}
|
|
214
206
|
for (let key in value) {
|
|
215
|
-
if (
|
|
216
|
-
result[key] = fromWireValue(driver, value[key])
|
|
207
|
+
if (Object.prototype.hasOwnProperty.call(value, key)) {
|
|
208
|
+
result[key] = fromWireValue(driver, value[key])
|
|
217
209
|
}
|
|
218
210
|
}
|
|
219
|
-
value = result
|
|
211
|
+
value = result
|
|
220
212
|
}
|
|
221
|
-
return value
|
|
213
|
+
return value
|
|
222
214
|
}
|
|
223
215
|
|
|
216
|
+
/**
|
|
217
|
+
* Resolves a wait message from either a function or a string.
|
|
218
|
+
* @param {(string|Function)=} message An optional message to use if the wait times out.
|
|
219
|
+
* @return {string} The resolved message
|
|
220
|
+
*/
|
|
221
|
+
function resolveWaitMessage(message) {
|
|
222
|
+
return message
|
|
223
|
+
? `${typeof message === 'function' ? message() : message}\n`
|
|
224
|
+
: ''
|
|
225
|
+
}
|
|
224
226
|
|
|
225
227
|
/**
|
|
226
228
|
* Structural interface for a WebDriver client.
|
|
@@ -228,7 +230,6 @@ function fromWireValue(driver, value) {
|
|
|
228
230
|
* @record
|
|
229
231
|
*/
|
|
230
232
|
class IWebDriver {
|
|
231
|
-
|
|
232
233
|
/**
|
|
233
234
|
* Executes the provided {@link command.Command} using this driver's
|
|
234
235
|
* {@link command.Executor}.
|
|
@@ -238,14 +239,14 @@ class IWebDriver {
|
|
|
238
239
|
* result.
|
|
239
240
|
* @template T
|
|
240
241
|
*/
|
|
241
|
-
execute(command) {}
|
|
242
|
+
execute(command) {} // eslint-disable-line
|
|
242
243
|
|
|
243
244
|
/**
|
|
244
245
|
* Sets the {@linkplain input.FileDetector file detector} that should be
|
|
245
246
|
* used with this instance.
|
|
246
247
|
* @param {input.FileDetector} detector The detector to use or `null`.
|
|
247
248
|
*/
|
|
248
|
-
setFileDetector(detector) {}
|
|
249
|
+
setFileDetector(detector) {} // eslint-disable-line
|
|
249
250
|
|
|
250
251
|
/**
|
|
251
252
|
* @return {!command.Executor} The command executor used by this instance.
|
|
@@ -284,7 +285,7 @@ class IWebDriver {
|
|
|
284
285
|
* for details).
|
|
285
286
|
* @return {!input.Actions} A new action sequence for this instance.
|
|
286
287
|
*/
|
|
287
|
-
actions(options) {}
|
|
288
|
+
actions(options) {} // eslint-disable-line
|
|
288
289
|
|
|
289
290
|
/**
|
|
290
291
|
* Executes a snippet of JavaScript in the context of the currently selected
|
|
@@ -322,7 +323,7 @@ class IWebDriver {
|
|
|
322
323
|
* scripts return value.
|
|
323
324
|
* @template T
|
|
324
325
|
*/
|
|
325
|
-
executeScript(script, ...args) {}
|
|
326
|
+
executeScript(script, ...args) {} // eslint-disable-line
|
|
326
327
|
|
|
327
328
|
/**
|
|
328
329
|
* Executes a snippet of asynchronous JavaScript in the context of the
|
|
@@ -399,7 +400,7 @@ class IWebDriver {
|
|
|
399
400
|
* value.
|
|
400
401
|
* @template T
|
|
401
402
|
*/
|
|
402
|
-
executeAsyncScript(script, ...args) {}
|
|
403
|
+
executeAsyncScript(script, ...args) {} // eslint-disable-line
|
|
403
404
|
|
|
404
405
|
/**
|
|
405
406
|
* Waits for a condition to evaluate to a "truthy" value. The condition may be
|
|
@@ -434,7 +435,7 @@ class IWebDriver {
|
|
|
434
435
|
* evaluate as a condition.
|
|
435
436
|
* @param {number=} timeout The duration in milliseconds, how long to wait
|
|
436
437
|
* for the condition to be true.
|
|
437
|
-
* @param {string=} message An optional message to use if the wait times out.
|
|
438
|
+
* @param {(string|Function)=} message An optional message to use if the wait times out.
|
|
438
439
|
* @param {number=} pollTimeout The duration in milliseconds, how long to
|
|
439
440
|
* wait between polling the condition.
|
|
440
441
|
* @return {!(IThenable<T>|WebElementPromise)} A promise that will be
|
|
@@ -445,7 +446,12 @@ class IWebDriver {
|
|
|
445
446
|
* @throws {TypeError} if the provided `condition` is not a valid type.
|
|
446
447
|
* @template T
|
|
447
448
|
*/
|
|
448
|
-
wait(
|
|
449
|
+
wait(
|
|
450
|
+
condition, // eslint-disable-line
|
|
451
|
+
timeout = undefined, // eslint-disable-line
|
|
452
|
+
message = undefined, // eslint-disable-line
|
|
453
|
+
pollTimeout = undefined // eslint-disable-line
|
|
454
|
+
) {}
|
|
449
455
|
|
|
450
456
|
/**
|
|
451
457
|
* Makes the driver sleep for the given amount of time.
|
|
@@ -454,7 +460,7 @@ class IWebDriver {
|
|
|
454
460
|
* @return {!Promise<void>} A promise that will be resolved when the sleep has
|
|
455
461
|
* finished.
|
|
456
462
|
*/
|
|
457
|
-
sleep(ms) {}
|
|
463
|
+
sleep(ms) {} // eslint-disable-line
|
|
458
464
|
|
|
459
465
|
/**
|
|
460
466
|
* Retrieves the current window handle.
|
|
@@ -473,7 +479,7 @@ class IWebDriver {
|
|
|
473
479
|
getAllWindowHandles() {}
|
|
474
480
|
|
|
475
481
|
/**
|
|
476
|
-
* Retrieves the current page's source. The returned
|
|
482
|
+
* Retrieves the current page's source. The returned source is a representation
|
|
477
483
|
* of the underlying DOM: do not expect it to be formatted or escaped in the
|
|
478
484
|
* same way as the raw response sent from the web server.
|
|
479
485
|
*
|
|
@@ -497,7 +503,7 @@ class IWebDriver {
|
|
|
497
503
|
* @return {!Promise<void>} A promise that will be resolved when the document
|
|
498
504
|
* has finished loading.
|
|
499
505
|
*/
|
|
500
|
-
get(url) {}
|
|
506
|
+
get(url) {} // eslint-disable-line
|
|
501
507
|
|
|
502
508
|
/**
|
|
503
509
|
* Retrieves the URL for the current page.
|
|
@@ -517,7 +523,7 @@ class IWebDriver {
|
|
|
517
523
|
|
|
518
524
|
/**
|
|
519
525
|
* Locates an element on the page. If the element cannot be found, a
|
|
520
|
-
* {@link error.
|
|
526
|
+
* {@link error.NoSuchElementError} will be returned by the driver.
|
|
521
527
|
*
|
|
522
528
|
* This function should not be used to test whether an element is present on
|
|
523
529
|
* the page. Rather, you should use {@link #findElements}:
|
|
@@ -553,7 +559,7 @@ class IWebDriver {
|
|
|
553
559
|
* commands against the located element. If the element is not found, the
|
|
554
560
|
* element will be invalidated and all scheduled commands aborted.
|
|
555
561
|
*/
|
|
556
|
-
findElement(locator) {}
|
|
562
|
+
findElement(locator) {} // eslint-disable-line
|
|
557
563
|
|
|
558
564
|
/**
|
|
559
565
|
* Search for multiple elements on the page. Refer to the documentation on
|
|
@@ -563,7 +569,7 @@ class IWebDriver {
|
|
|
563
569
|
* @return {!Promise<!Array<!WebElement>>} A promise that will resolve to an
|
|
564
570
|
* array of WebElements.
|
|
565
571
|
*/
|
|
566
|
-
findElements(locator) {}
|
|
572
|
+
findElements(locator) {} // eslint-disable-line
|
|
567
573
|
|
|
568
574
|
/**
|
|
569
575
|
* Takes a screenshot of the current page. The driver makes a best effort to
|
|
@@ -594,8 +600,26 @@ class IWebDriver {
|
|
|
594
600
|
* instance.
|
|
595
601
|
*/
|
|
596
602
|
switchTo() {}
|
|
597
|
-
}
|
|
598
603
|
|
|
604
|
+
/**
|
|
605
|
+
*
|
|
606
|
+
* Takes a PDF of the current page. The driver makes a best effort to
|
|
607
|
+
* return a PDF based on the provided parameters.
|
|
608
|
+
*
|
|
609
|
+
* @param {{orientation: (string|undefined),
|
|
610
|
+
* scale: (number|undefined),
|
|
611
|
+
* background: (boolean|undefined)
|
|
612
|
+
* width: (number|undefined)
|
|
613
|
+
* height: (number|undefined)
|
|
614
|
+
* top: (number|undefined)
|
|
615
|
+
* bottom: (number|undefined)
|
|
616
|
+
* left: (number|undefined)
|
|
617
|
+
* right: (number|undefined)
|
|
618
|
+
* shrinkToFit: (boolean|undefined)
|
|
619
|
+
* pageRanges: (<Array>|undefined)}} options.
|
|
620
|
+
*/
|
|
621
|
+
printPage(options) {} // eslint-disable-line
|
|
622
|
+
}
|
|
599
623
|
|
|
600
624
|
/**
|
|
601
625
|
* @param {!Capabilities} capabilities A capabilities object.
|
|
@@ -603,17 +627,16 @@ class IWebDriver {
|
|
|
603
627
|
* capability names that are not valid W3C names.
|
|
604
628
|
*/
|
|
605
629
|
function filterNonW3CCaps(capabilities) {
|
|
606
|
-
let newCaps = new Capabilities(capabilities)
|
|
630
|
+
let newCaps = new Capabilities(capabilities)
|
|
607
631
|
for (let k of newCaps.keys()) {
|
|
608
632
|
// Any key containing a colon is a vendor-prefixed capability.
|
|
609
633
|
if (!(W3C_CAPABILITY_NAMES.has(k) || k.indexOf(':') >= 0)) {
|
|
610
|
-
newCaps.delete(k)
|
|
634
|
+
newCaps.delete(k)
|
|
611
635
|
}
|
|
612
636
|
}
|
|
613
|
-
return newCaps
|
|
637
|
+
return newCaps
|
|
614
638
|
}
|
|
615
639
|
|
|
616
|
-
|
|
617
640
|
/**
|
|
618
641
|
* Each WebDriver instance provides automated control over a browser session.
|
|
619
642
|
*
|
|
@@ -630,21 +653,21 @@ class WebDriver {
|
|
|
630
653
|
*/
|
|
631
654
|
constructor(session, executor, onQuit = undefined) {
|
|
632
655
|
/** @private {!Promise<!Session>} */
|
|
633
|
-
this.session_ = Promise.resolve(session)
|
|
656
|
+
this.session_ = Promise.resolve(session)
|
|
634
657
|
|
|
635
658
|
// If session is a rejected promise, add a no-op rejection handler.
|
|
636
659
|
// This effectively hides setup errors until users attempt to interact
|
|
637
660
|
// with the session.
|
|
638
|
-
this.session_.catch(function() {})
|
|
661
|
+
this.session_.catch(function () {})
|
|
639
662
|
|
|
640
663
|
/** @private {!command.Executor} */
|
|
641
|
-
this.executor_ = executor
|
|
664
|
+
this.executor_ = executor
|
|
642
665
|
|
|
643
666
|
/** @private {input.FileDetector} */
|
|
644
|
-
this.fileDetector_ = null
|
|
667
|
+
this.fileDetector_ = null
|
|
645
668
|
|
|
646
669
|
/** @private @const {(function(this: void): ?|undefined)} */
|
|
647
|
-
this.onQuit_ = onQuit
|
|
670
|
+
this.onQuit_ = onQuit
|
|
648
671
|
}
|
|
649
672
|
|
|
650
673
|
/**
|
|
@@ -673,251 +696,288 @@ class WebDriver {
|
|
|
673
696
|
* @return {!WebDriver} The driver for the newly created session.
|
|
674
697
|
*/
|
|
675
698
|
static createSession(executor, capabilities, onQuit = undefined) {
|
|
676
|
-
let cmd = new command.Command(command.Name.NEW_SESSION)
|
|
699
|
+
let cmd = new command.Command(command.Name.NEW_SESSION)
|
|
677
700
|
|
|
678
701
|
// For OSS remote ends.
|
|
679
|
-
cmd.setParameter('desiredCapabilities', capabilities)
|
|
702
|
+
cmd.setParameter('desiredCapabilities', capabilities)
|
|
680
703
|
// For W3C remote ends.
|
|
681
704
|
cmd.setParameter('capabilities', {
|
|
682
705
|
alwaysMatch: filterNonW3CCaps(capabilities),
|
|
683
|
-
})
|
|
706
|
+
})
|
|
684
707
|
|
|
685
|
-
let session = executeCommand(executor, cmd)
|
|
708
|
+
let session = executeCommand(executor, cmd)
|
|
686
709
|
if (typeof onQuit === 'function') {
|
|
687
|
-
session = session.catch(err => {
|
|
688
|
-
return Promise.resolve(onQuit.call(void 0)).then(_ => {
|
|
689
|
-
|
|
710
|
+
session = session.catch((err) => {
|
|
711
|
+
return Promise.resolve(onQuit.call(void 0)).then((_) => {
|
|
712
|
+
throw err
|
|
713
|
+
})
|
|
714
|
+
})
|
|
690
715
|
}
|
|
691
|
-
return new this(session, executor, onQuit)
|
|
716
|
+
return new this(session, executor, onQuit)
|
|
692
717
|
}
|
|
693
718
|
|
|
694
719
|
/** @override */
|
|
695
720
|
async execute(command) {
|
|
696
|
-
command.setParameter('sessionId', this.session_)
|
|
697
|
-
let parameters = await toWireValue(command.getParameters())
|
|
698
|
-
command.setParameters(parameters)
|
|
699
|
-
let value = await this.executor_.execute(command)
|
|
700
|
-
return fromWireValue(this, value)
|
|
721
|
+
command.setParameter('sessionId', this.session_)
|
|
722
|
+
let parameters = await toWireValue(command.getParameters())
|
|
723
|
+
command.setParameters(parameters)
|
|
724
|
+
let value = await this.executor_.execute(command)
|
|
725
|
+
return fromWireValue(this, value)
|
|
701
726
|
}
|
|
702
727
|
|
|
703
728
|
/** @override */
|
|
704
729
|
setFileDetector(detector) {
|
|
705
|
-
this.fileDetector_ = detector
|
|
730
|
+
this.fileDetector_ = detector
|
|
706
731
|
}
|
|
707
732
|
|
|
708
733
|
/** @override */
|
|
709
734
|
getExecutor() {
|
|
710
|
-
return this.executor_
|
|
735
|
+
return this.executor_
|
|
711
736
|
}
|
|
712
737
|
|
|
713
738
|
/** @override */
|
|
714
739
|
getSession() {
|
|
715
|
-
return this.session_
|
|
740
|
+
return this.session_
|
|
716
741
|
}
|
|
717
742
|
|
|
718
743
|
/** @override */
|
|
719
744
|
getCapabilities() {
|
|
720
|
-
return this.session_.then(s => s.getCapabilities())
|
|
745
|
+
return this.session_.then((s) => s.getCapabilities())
|
|
721
746
|
}
|
|
722
747
|
|
|
723
748
|
/** @override */
|
|
724
749
|
quit() {
|
|
725
|
-
let result = this.execute(new command.Command(command.Name.QUIT))
|
|
750
|
+
let result = this.execute(new command.Command(command.Name.QUIT))
|
|
726
751
|
// Delete our session ID when the quit command finishes; this will allow us
|
|
727
752
|
// to throw an error when attempting to use a driver post-quit.
|
|
728
753
|
return promise.finally(result, () => {
|
|
729
|
-
this.session_ = Promise.reject(
|
|
730
|
-
|
|
731
|
-
|
|
754
|
+
this.session_ = Promise.reject(
|
|
755
|
+
new error.NoSuchSessionError(
|
|
756
|
+
'This driver instance does not have a valid session ID ' +
|
|
757
|
+
'(did you call WebDriver.quit()?) and may no longer be used.'
|
|
758
|
+
)
|
|
759
|
+
)
|
|
732
760
|
|
|
733
761
|
// Only want the session rejection to bubble if accessed.
|
|
734
|
-
this.session_.catch(function() {})
|
|
762
|
+
this.session_.catch(function () {})
|
|
735
763
|
|
|
736
764
|
if (this.onQuit_) {
|
|
737
|
-
return this.onQuit_.call(void 0)
|
|
765
|
+
return this.onQuit_.call(void 0)
|
|
738
766
|
}
|
|
739
|
-
})
|
|
767
|
+
})
|
|
740
768
|
}
|
|
741
769
|
|
|
742
770
|
/** @override */
|
|
743
771
|
actions(options) {
|
|
744
|
-
return new input.Actions(this, options || undefined)
|
|
772
|
+
return new input.Actions(this, options || undefined)
|
|
745
773
|
}
|
|
746
774
|
|
|
747
775
|
/** @override */
|
|
748
776
|
executeScript(script, ...args) {
|
|
749
777
|
if (typeof script === 'function') {
|
|
750
|
-
script = 'return (' + script + ').apply(null, arguments);'
|
|
778
|
+
script = 'return (' + script + ').apply(null, arguments);'
|
|
751
779
|
}
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
780
|
+
return this.execute(
|
|
781
|
+
new command.Command(command.Name.EXECUTE_SCRIPT)
|
|
782
|
+
.setParameter('script', script)
|
|
783
|
+
.setParameter('args', args)
|
|
784
|
+
)
|
|
756
785
|
}
|
|
757
786
|
|
|
758
787
|
/** @override */
|
|
759
788
|
executeAsyncScript(script, ...args) {
|
|
760
789
|
if (typeof script === 'function') {
|
|
761
|
-
script = 'return (' + script + ').apply(null, arguments);'
|
|
790
|
+
script = 'return (' + script + ').apply(null, arguments);'
|
|
762
791
|
}
|
|
763
792
|
return this.execute(
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
793
|
+
new command.Command(command.Name.EXECUTE_ASYNC_SCRIPT)
|
|
794
|
+
.setParameter('script', script)
|
|
795
|
+
.setParameter('args', args)
|
|
796
|
+
)
|
|
767
797
|
}
|
|
768
798
|
|
|
769
799
|
/** @override */
|
|
770
800
|
wait(condition, timeout = 0, message = undefined, pollTimeout = 200) {
|
|
771
801
|
if (typeof timeout !== 'number' || timeout < 0) {
|
|
772
|
-
throw TypeError('timeout must be a number >= 0: ' + timeout)
|
|
802
|
+
throw TypeError('timeout must be a number >= 0: ' + timeout)
|
|
773
803
|
}
|
|
774
804
|
|
|
775
805
|
if (typeof pollTimeout !== 'number' || pollTimeout < 0) {
|
|
776
|
-
throw TypeError('pollTimeout must be a number >= 0: ' + pollTimeout)
|
|
806
|
+
throw TypeError('pollTimeout must be a number >= 0: ' + pollTimeout)
|
|
777
807
|
}
|
|
778
808
|
|
|
779
809
|
if (promise.isPromise(condition)) {
|
|
780
810
|
return new Promise((resolve, reject) => {
|
|
781
811
|
if (!timeout) {
|
|
782
|
-
resolve(condition)
|
|
783
|
-
return
|
|
812
|
+
resolve(condition)
|
|
813
|
+
return
|
|
784
814
|
}
|
|
785
815
|
|
|
786
|
-
let start = Date.now()
|
|
787
|
-
let timer = setTimeout(function() {
|
|
788
|
-
timer = null
|
|
789
|
-
|
|
816
|
+
let start = Date.now()
|
|
817
|
+
let timer = setTimeout(function () {
|
|
818
|
+
timer = null
|
|
819
|
+
try {
|
|
820
|
+
let timeoutMessage = resolveWaitMessage(message)
|
|
821
|
+
reject(
|
|
790
822
|
new error.TimeoutError(
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
823
|
+
`${timeoutMessage}Timed out waiting for promise to resolve after ${
|
|
824
|
+
Date.now() - start
|
|
825
|
+
}ms`
|
|
826
|
+
)
|
|
827
|
+
)
|
|
828
|
+
} catch (ex) {
|
|
829
|
+
reject(
|
|
830
|
+
new error.TimeoutError(
|
|
831
|
+
`${
|
|
832
|
+
ex.message
|
|
833
|
+
}\nTimed out waiting for promise to resolve after ${
|
|
834
|
+
Date.now() - start
|
|
835
|
+
}ms`
|
|
836
|
+
)
|
|
837
|
+
)
|
|
838
|
+
}
|
|
839
|
+
}, timeout)
|
|
840
|
+
const clearTimer = () => timer && clearTimeout(timer)
|
|
841
|
+
|
|
842
|
+
/** @type {!IThenable} */ condition.then(
|
|
843
|
+
function (value) {
|
|
844
|
+
clearTimer()
|
|
845
|
+
resolve(value)
|
|
846
|
+
},
|
|
847
|
+
function (error) {
|
|
848
|
+
clearTimer()
|
|
849
|
+
reject(error)
|
|
850
|
+
}
|
|
851
|
+
)
|
|
852
|
+
})
|
|
807
853
|
}
|
|
808
854
|
|
|
809
|
-
let fn = /** @type {!Function} */(condition)
|
|
855
|
+
let fn = /** @type {!Function} */ (condition)
|
|
810
856
|
if (condition instanceof Condition) {
|
|
811
|
-
message = message || condition.description()
|
|
812
|
-
fn = condition.fn
|
|
857
|
+
message = message || condition.description()
|
|
858
|
+
fn = condition.fn
|
|
813
859
|
}
|
|
814
860
|
|
|
815
861
|
if (typeof fn !== 'function') {
|
|
816
862
|
throw TypeError(
|
|
817
|
-
|
|
818
|
-
|
|
863
|
+
'Wait condition must be a promise-like object, function, or a ' +
|
|
864
|
+
'Condition object'
|
|
865
|
+
)
|
|
819
866
|
}
|
|
820
867
|
|
|
821
|
-
const driver = this
|
|
868
|
+
const driver = this
|
|
822
869
|
function evaluateCondition() {
|
|
823
870
|
return new Promise((resolve, reject) => {
|
|
824
871
|
try {
|
|
825
|
-
resolve(fn(driver))
|
|
872
|
+
resolve(fn(driver))
|
|
826
873
|
} catch (ex) {
|
|
827
|
-
reject(ex)
|
|
874
|
+
reject(ex)
|
|
828
875
|
}
|
|
829
|
-
})
|
|
876
|
+
})
|
|
830
877
|
}
|
|
831
878
|
|
|
832
879
|
let result = new Promise((resolve, reject) => {
|
|
833
|
-
const startTime = Date.now()
|
|
880
|
+
const startTime = Date.now()
|
|
834
881
|
const pollCondition = async () => {
|
|
835
|
-
evaluateCondition().then(function(value) {
|
|
836
|
-
const elapsed = Date.now() - startTime
|
|
837
|
-
if (
|
|
838
|
-
resolve(value)
|
|
882
|
+
evaluateCondition().then(function (value) {
|
|
883
|
+
const elapsed = Date.now() - startTime
|
|
884
|
+
if (value) {
|
|
885
|
+
resolve(value)
|
|
839
886
|
} else if (timeout && elapsed >= timeout) {
|
|
840
|
-
|
|
887
|
+
try {
|
|
888
|
+
let timeoutMessage = resolveWaitMessage(message)
|
|
889
|
+
reject(
|
|
890
|
+
new error.TimeoutError(
|
|
891
|
+
`${timeoutMessage}Wait timed out after ${elapsed}ms`
|
|
892
|
+
)
|
|
893
|
+
)
|
|
894
|
+
} catch (ex) {
|
|
895
|
+
reject(
|
|
841
896
|
new error.TimeoutError(
|
|
842
|
-
|
|
843
|
-
|
|
897
|
+
`${ex.message}\nWait timed out after ${elapsed}ms`
|
|
898
|
+
)
|
|
899
|
+
)
|
|
900
|
+
}
|
|
844
901
|
} else {
|
|
845
|
-
setTimeout(pollCondition, pollTimeout)
|
|
902
|
+
setTimeout(pollCondition, pollTimeout)
|
|
846
903
|
}
|
|
847
|
-
}, reject)
|
|
848
|
-
}
|
|
849
|
-
pollCondition()
|
|
850
|
-
})
|
|
904
|
+
}, reject)
|
|
905
|
+
}
|
|
906
|
+
pollCondition()
|
|
907
|
+
})
|
|
851
908
|
|
|
852
909
|
if (condition instanceof WebElementCondition) {
|
|
853
|
-
result = new WebElementPromise(
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
910
|
+
result = new WebElementPromise(
|
|
911
|
+
this,
|
|
912
|
+
result.then(function (value) {
|
|
913
|
+
if (!(value instanceof WebElement)) {
|
|
914
|
+
throw TypeError(
|
|
915
|
+
'WebElementCondition did not resolve to a WebElement: ' +
|
|
916
|
+
Object.prototype.toString.call(value)
|
|
917
|
+
)
|
|
918
|
+
}
|
|
919
|
+
return value
|
|
920
|
+
})
|
|
921
|
+
)
|
|
861
922
|
}
|
|
862
|
-
return result
|
|
923
|
+
return result
|
|
863
924
|
}
|
|
864
925
|
|
|
865
926
|
/** @override */
|
|
866
927
|
sleep(ms) {
|
|
867
|
-
return new Promise(resolve => setTimeout(() => resolve(), ms))
|
|
928
|
+
return new Promise((resolve) => setTimeout(() => resolve(), ms))
|
|
868
929
|
}
|
|
869
930
|
|
|
870
931
|
/** @override */
|
|
871
932
|
getWindowHandle() {
|
|
872
933
|
return this.execute(
|
|
873
|
-
|
|
934
|
+
new command.Command(command.Name.GET_CURRENT_WINDOW_HANDLE)
|
|
935
|
+
)
|
|
874
936
|
}
|
|
875
937
|
|
|
876
938
|
/** @override */
|
|
877
939
|
getAllWindowHandles() {
|
|
878
|
-
return this.execute(
|
|
879
|
-
new command.Command(command.Name.GET_WINDOW_HANDLES));
|
|
940
|
+
return this.execute(new command.Command(command.Name.GET_WINDOW_HANDLES))
|
|
880
941
|
}
|
|
881
942
|
|
|
882
943
|
/** @override */
|
|
883
944
|
getPageSource() {
|
|
884
|
-
return this.execute(
|
|
885
|
-
new command.Command(command.Name.GET_PAGE_SOURCE));
|
|
945
|
+
return this.execute(new command.Command(command.Name.GET_PAGE_SOURCE))
|
|
886
946
|
}
|
|
887
947
|
|
|
888
948
|
/** @override */
|
|
889
949
|
close() {
|
|
890
|
-
return this.execute(new command.Command(command.Name.CLOSE))
|
|
950
|
+
return this.execute(new command.Command(command.Name.CLOSE))
|
|
891
951
|
}
|
|
892
952
|
|
|
893
953
|
/** @override */
|
|
894
954
|
get(url) {
|
|
895
|
-
return this.navigate().to(url)
|
|
955
|
+
return this.navigate().to(url)
|
|
896
956
|
}
|
|
897
957
|
|
|
898
958
|
/** @override */
|
|
899
959
|
getCurrentUrl() {
|
|
900
|
-
return this.execute(new command.Command(command.Name.GET_CURRENT_URL))
|
|
960
|
+
return this.execute(new command.Command(command.Name.GET_CURRENT_URL))
|
|
901
961
|
}
|
|
902
962
|
|
|
903
963
|
/** @override */
|
|
904
964
|
getTitle() {
|
|
905
|
-
return this.execute(new command.Command(command.Name.GET_TITLE))
|
|
965
|
+
return this.execute(new command.Command(command.Name.GET_TITLE))
|
|
906
966
|
}
|
|
907
967
|
|
|
908
968
|
/** @override */
|
|
909
969
|
findElement(locator) {
|
|
910
|
-
let id
|
|
911
|
-
locator = by.checkedLocator(locator)
|
|
970
|
+
let id
|
|
971
|
+
locator = by.checkedLocator(locator)
|
|
912
972
|
if (typeof locator === 'function') {
|
|
913
|
-
id = this.findElementInternal_(locator, this)
|
|
973
|
+
id = this.findElementInternal_(locator, this)
|
|
914
974
|
} else {
|
|
915
|
-
let cmd = new command.Command(command.Name.FIND_ELEMENT)
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
id = this.execute(cmd)
|
|
975
|
+
let cmd = new command.Command(command.Name.FIND_ELEMENT)
|
|
976
|
+
.setParameter('using', locator.using)
|
|
977
|
+
.setParameter('value', locator.value)
|
|
978
|
+
id = this.execute(cmd)
|
|
919
979
|
}
|
|
920
|
-
return new WebElementPromise(this, id)
|
|
980
|
+
return new WebElementPromise(this, id)
|
|
921
981
|
}
|
|
922
982
|
|
|
923
983
|
/**
|
|
@@ -928,34 +988,42 @@ class WebDriver {
|
|
|
928
988
|
* @private
|
|
929
989
|
*/
|
|
930
990
|
async findElementInternal_(locatorFn, context) {
|
|
931
|
-
let result = await locatorFn(context)
|
|
991
|
+
let result = await locatorFn(context)
|
|
932
992
|
if (Array.isArray(result)) {
|
|
933
|
-
result = result[0]
|
|
993
|
+
result = result[0]
|
|
934
994
|
}
|
|
935
995
|
if (!(result instanceof WebElement)) {
|
|
936
|
-
throw new TypeError('Custom locator did not return a WebElement')
|
|
996
|
+
throw new TypeError('Custom locator did not return a WebElement')
|
|
937
997
|
}
|
|
938
|
-
return result
|
|
998
|
+
return result
|
|
939
999
|
}
|
|
940
1000
|
|
|
941
1001
|
/** @override */
|
|
942
1002
|
async findElements(locator) {
|
|
943
|
-
|
|
944
|
-
if (
|
|
945
|
-
|
|
1003
|
+
let cmd = null
|
|
1004
|
+
if (locator instanceof RelativeBy) {
|
|
1005
|
+
cmd = new command.Command(
|
|
1006
|
+
command.Name.FIND_ELEMENTS_RELATIVE
|
|
1007
|
+
).setParameter('args', locator.marshall())
|
|
946
1008
|
} else {
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
1009
|
+
locator = by.checkedLocator(locator)
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
if (typeof locator === 'function') {
|
|
1013
|
+
return this.findElementsInternal_(locator, this)
|
|
1014
|
+
} else if (cmd === null) {
|
|
1015
|
+
cmd = new command.Command(command.Name.FIND_ELEMENTS)
|
|
1016
|
+
.setParameter('using', locator.using)
|
|
1017
|
+
.setParameter('value', locator.value)
|
|
1018
|
+
}
|
|
1019
|
+
try {
|
|
1020
|
+
let res = await this.execute(cmd)
|
|
1021
|
+
return Array.isArray(res) ? res : []
|
|
1022
|
+
} catch (ex) {
|
|
1023
|
+
if (ex instanceof error.NoSuchElementError) {
|
|
1024
|
+
return []
|
|
958
1025
|
}
|
|
1026
|
+
throw ex
|
|
959
1027
|
}
|
|
960
1028
|
}
|
|
961
1029
|
|
|
@@ -967,41 +1035,122 @@ class WebDriver {
|
|
|
967
1035
|
* @private
|
|
968
1036
|
*/
|
|
969
1037
|
async findElementsInternal_(locatorFn, context) {
|
|
970
|
-
const result = await locatorFn(context)
|
|
1038
|
+
const result = await locatorFn(context)
|
|
971
1039
|
if (result instanceof WebElement) {
|
|
972
|
-
return [result]
|
|
1040
|
+
return [result]
|
|
973
1041
|
}
|
|
974
1042
|
|
|
975
1043
|
if (!Array.isArray(result)) {
|
|
976
|
-
return []
|
|
1044
|
+
return []
|
|
977
1045
|
}
|
|
978
1046
|
|
|
979
|
-
return result.filter(function(item) {
|
|
980
|
-
return item instanceof WebElement
|
|
981
|
-
})
|
|
1047
|
+
return result.filter(function (item) {
|
|
1048
|
+
return item instanceof WebElement
|
|
1049
|
+
})
|
|
982
1050
|
}
|
|
983
1051
|
|
|
984
1052
|
/** @override */
|
|
985
1053
|
takeScreenshot() {
|
|
986
|
-
return this.execute(new command.Command(command.Name.SCREENSHOT))
|
|
1054
|
+
return this.execute(new command.Command(command.Name.SCREENSHOT))
|
|
987
1055
|
}
|
|
988
1056
|
|
|
989
1057
|
/** @override */
|
|
990
1058
|
manage() {
|
|
991
|
-
return new Options(this)
|
|
1059
|
+
return new Options(this)
|
|
992
1060
|
}
|
|
993
1061
|
|
|
994
1062
|
/** @override */
|
|
995
1063
|
navigate() {
|
|
996
|
-
return new Navigation(this)
|
|
1064
|
+
return new Navigation(this)
|
|
997
1065
|
}
|
|
998
1066
|
|
|
999
1067
|
/** @override */
|
|
1000
1068
|
switchTo() {
|
|
1001
|
-
return new TargetLocator(this)
|
|
1069
|
+
return new TargetLocator(this)
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
validatePrintPageParams(keys, object) {
|
|
1073
|
+
let page = {}
|
|
1074
|
+
let margin = {}
|
|
1075
|
+
let data
|
|
1076
|
+
Object.keys(keys).forEach(function (key) {
|
|
1077
|
+
data = keys[key]
|
|
1078
|
+
let obj = {
|
|
1079
|
+
orientation: function () {
|
|
1080
|
+
object.orientation = data
|
|
1081
|
+
},
|
|
1082
|
+
|
|
1083
|
+
scale: function () {
|
|
1084
|
+
object.scale = data
|
|
1085
|
+
},
|
|
1086
|
+
|
|
1087
|
+
background: function () {
|
|
1088
|
+
object.background = data
|
|
1089
|
+
},
|
|
1090
|
+
|
|
1091
|
+
width: function () {
|
|
1092
|
+
page.width = data
|
|
1093
|
+
object.page = page
|
|
1094
|
+
},
|
|
1095
|
+
|
|
1096
|
+
height: function () {
|
|
1097
|
+
page.height = data
|
|
1098
|
+
object.page = page
|
|
1099
|
+
},
|
|
1100
|
+
|
|
1101
|
+
top: function () {
|
|
1102
|
+
margin.top = data
|
|
1103
|
+
object.margin = margin
|
|
1104
|
+
},
|
|
1105
|
+
|
|
1106
|
+
left: function () {
|
|
1107
|
+
margin.left = data
|
|
1108
|
+
object.margin = margin
|
|
1109
|
+
},
|
|
1110
|
+
|
|
1111
|
+
bottom: function () {
|
|
1112
|
+
margin.bottom = data
|
|
1113
|
+
object.margin = margin
|
|
1114
|
+
},
|
|
1115
|
+
|
|
1116
|
+
right: function () {
|
|
1117
|
+
margin.right = data
|
|
1118
|
+
object.margin = margin
|
|
1119
|
+
},
|
|
1120
|
+
|
|
1121
|
+
shrinkToFit: function () {
|
|
1122
|
+
object.shrinkToFit = data
|
|
1123
|
+
},
|
|
1124
|
+
|
|
1125
|
+
pageRanges: function () {
|
|
1126
|
+
object.pageRanges = data
|
|
1127
|
+
},
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
if (!Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
1131
|
+
throw new error.InvalidArgumentError(`Invalid Argument '${key}'`)
|
|
1132
|
+
} else {
|
|
1133
|
+
obj[key]()
|
|
1134
|
+
}
|
|
1135
|
+
})
|
|
1136
|
+
|
|
1137
|
+
return object
|
|
1002
1138
|
}
|
|
1003
|
-
}
|
|
1004
1139
|
|
|
1140
|
+
/** @override */
|
|
1141
|
+
printPage(options = {}) {
|
|
1142
|
+
let keys = options
|
|
1143
|
+
let params = {}
|
|
1144
|
+
let resultObj
|
|
1145
|
+
|
|
1146
|
+
let self = this
|
|
1147
|
+
resultObj = self.validatePrintPageParams(keys, params)
|
|
1148
|
+
|
|
1149
|
+
return this.execute(
|
|
1150
|
+
new command.Command(command.Name.PRINT_PAGE).setParameters(resultObj)
|
|
1151
|
+
)
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1005
1154
|
|
|
1006
1155
|
/**
|
|
1007
1156
|
* Interface for navigating back and forth in the browser history.
|
|
@@ -1020,7 +1169,7 @@ class Navigation {
|
|
|
1020
1169
|
*/
|
|
1021
1170
|
constructor(driver) {
|
|
1022
1171
|
/** @private {!WebDriver} */
|
|
1023
|
-
this.driver_ = driver
|
|
1172
|
+
this.driver_ = driver
|
|
1024
1173
|
}
|
|
1025
1174
|
|
|
1026
1175
|
/**
|
|
@@ -1032,8 +1181,8 @@ class Navigation {
|
|
|
1032
1181
|
*/
|
|
1033
1182
|
to(url) {
|
|
1034
1183
|
return this.driver_.execute(
|
|
1035
|
-
|
|
1036
|
-
|
|
1184
|
+
new command.Command(command.Name.GET).setParameter('url', url)
|
|
1185
|
+
)
|
|
1037
1186
|
}
|
|
1038
1187
|
|
|
1039
1188
|
/**
|
|
@@ -1043,7 +1192,7 @@ class Navigation {
|
|
|
1043
1192
|
* navigation event has completed.
|
|
1044
1193
|
*/
|
|
1045
1194
|
back() {
|
|
1046
|
-
return this.driver_.execute(new command.Command(command.Name.GO_BACK))
|
|
1195
|
+
return this.driver_.execute(new command.Command(command.Name.GO_BACK))
|
|
1047
1196
|
}
|
|
1048
1197
|
|
|
1049
1198
|
/**
|
|
@@ -1053,7 +1202,7 @@ class Navigation {
|
|
|
1053
1202
|
* navigation event has completed.
|
|
1054
1203
|
*/
|
|
1055
1204
|
forward() {
|
|
1056
|
-
return this.driver_.execute(new command.Command(command.Name.GO_FORWARD))
|
|
1205
|
+
return this.driver_.execute(new command.Command(command.Name.GO_FORWARD))
|
|
1057
1206
|
}
|
|
1058
1207
|
|
|
1059
1208
|
/**
|
|
@@ -1063,11 +1212,10 @@ class Navigation {
|
|
|
1063
1212
|
* navigation event has completed.
|
|
1064
1213
|
*/
|
|
1065
1214
|
refresh() {
|
|
1066
|
-
return this.driver_.execute(new command.Command(command.Name.REFRESH))
|
|
1215
|
+
return this.driver_.execute(new command.Command(command.Name.REFRESH))
|
|
1067
1216
|
}
|
|
1068
1217
|
}
|
|
1069
1218
|
|
|
1070
|
-
|
|
1071
1219
|
/**
|
|
1072
1220
|
* Provides methods for managing browser and driver state.
|
|
1073
1221
|
*
|
|
@@ -1081,7 +1229,7 @@ class Options {
|
|
|
1081
1229
|
*/
|
|
1082
1230
|
constructor(driver) {
|
|
1083
1231
|
/** @private {!WebDriver} */
|
|
1084
|
-
this.driver_ = driver
|
|
1232
|
+
this.driver_ = driver
|
|
1085
1233
|
}
|
|
1086
1234
|
|
|
1087
1235
|
/**
|
|
@@ -1110,37 +1258,50 @@ class Options {
|
|
|
1110
1258
|
* invalid.
|
|
1111
1259
|
* @throws {TypeError} if `spec` is not a cookie object.
|
|
1112
1260
|
*/
|
|
1113
|
-
addCookie({name, value, path, domain, secure, httpOnly, expiry}) {
|
|
1261
|
+
addCookie({ name, value, path, domain, secure, httpOnly, expiry, sameSite }) {
|
|
1114
1262
|
// We do not allow '=' or ';' in the name.
|
|
1115
1263
|
if (/[;=]/.test(name)) {
|
|
1116
|
-
throw new error.InvalidArgumentError(
|
|
1117
|
-
'Invalid cookie name "' + name + '"');
|
|
1264
|
+
throw new error.InvalidArgumentError('Invalid cookie name "' + name + '"')
|
|
1118
1265
|
}
|
|
1119
1266
|
|
|
1120
1267
|
// We do not allow ';' in value.
|
|
1121
1268
|
if (/;/.test(value)) {
|
|
1122
1269
|
throw new error.InvalidArgumentError(
|
|
1123
|
-
|
|
1270
|
+
'Invalid cookie value "' + value + '"'
|
|
1271
|
+
)
|
|
1124
1272
|
}
|
|
1125
1273
|
|
|
1126
1274
|
if (typeof expiry === 'number') {
|
|
1127
|
-
expiry = Math.floor(expiry)
|
|
1275
|
+
expiry = Math.floor(expiry)
|
|
1128
1276
|
} else if (expiry instanceof Date) {
|
|
1129
|
-
let date = /** @type {!Date} */(expiry)
|
|
1130
|
-
expiry = Math.floor(date.getTime() / 1000)
|
|
1277
|
+
let date = /** @type {!Date} */ (expiry)
|
|
1278
|
+
expiry = Math.floor(date.getTime() / 1000)
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
if (sameSite && !['Strict', 'Lax', 'None'].includes(sameSite)) {
|
|
1282
|
+
throw new error.InvalidArgumentError(
|
|
1283
|
+
`Invalid sameSite cookie value '${sameSite}'. It should be one of "Lax", "Strict" or "None"`
|
|
1284
|
+
)
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
if (sameSite === 'None' && !secure) {
|
|
1288
|
+
throw new error.InvalidArgumentError(
|
|
1289
|
+
'Invalid cookie configuration: SameSite=None must be Secure'
|
|
1290
|
+
)
|
|
1131
1291
|
}
|
|
1132
1292
|
|
|
1133
1293
|
return this.driver_.execute(
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1294
|
+
new command.Command(command.Name.ADD_COOKIE).setParameter('cookie', {
|
|
1295
|
+
name: name,
|
|
1296
|
+
value: value,
|
|
1297
|
+
path: path,
|
|
1298
|
+
domain: domain,
|
|
1299
|
+
secure: !!secure,
|
|
1300
|
+
httpOnly: !!httpOnly,
|
|
1301
|
+
expiry: expiry,
|
|
1302
|
+
sameSite: sameSite,
|
|
1303
|
+
})
|
|
1304
|
+
)
|
|
1144
1305
|
}
|
|
1145
1306
|
|
|
1146
1307
|
/**
|
|
@@ -1151,7 +1312,8 @@ class Options {
|
|
|
1151
1312
|
*/
|
|
1152
1313
|
deleteAllCookies() {
|
|
1153
1314
|
return this.driver_.execute(
|
|
1154
|
-
|
|
1315
|
+
new command.Command(command.Name.DELETE_ALL_COOKIES)
|
|
1316
|
+
)
|
|
1155
1317
|
}
|
|
1156
1318
|
|
|
1157
1319
|
/**
|
|
@@ -1164,8 +1326,8 @@ class Options {
|
|
|
1164
1326
|
*/
|
|
1165
1327
|
deleteCookie(name) {
|
|
1166
1328
|
return this.driver_.execute(
|
|
1167
|
-
|
|
1168
|
-
|
|
1329
|
+
new command.Command(command.Name.DELETE_COOKIE).setParameter('name', name)
|
|
1330
|
+
)
|
|
1169
1331
|
}
|
|
1170
1332
|
|
|
1171
1333
|
/**
|
|
@@ -1177,7 +1339,8 @@ class Options {
|
|
|
1177
1339
|
*/
|
|
1178
1340
|
getCookies() {
|
|
1179
1341
|
return this.driver_.execute(
|
|
1180
|
-
|
|
1342
|
+
new command.Command(command.Name.GET_ALL_COOKIES)
|
|
1343
|
+
)
|
|
1181
1344
|
}
|
|
1182
1345
|
|
|
1183
1346
|
/**
|
|
@@ -1187,28 +1350,30 @@ class Options {
|
|
|
1187
1350
|
*
|
|
1188
1351
|
* @param {string} name The name of the cookie to retrieve.
|
|
1189
1352
|
* @return {!Promise<?Options.Cookie>} A promise that will be resolved
|
|
1190
|
-
* with the named cookie
|
|
1353
|
+
* with the named cookie
|
|
1354
|
+
* @throws {error.NoSuchCookieError} if there is no such cookie.
|
|
1191
1355
|
*/
|
|
1192
1356
|
async getCookie(name) {
|
|
1193
1357
|
try {
|
|
1194
|
-
const cookie =
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
return cookie;
|
|
1358
|
+
const cookie = await this.driver_.execute(
|
|
1359
|
+
new command.Command(command.Name.GET_COOKIE).setParameter('name', name)
|
|
1360
|
+
)
|
|
1361
|
+
return cookie
|
|
1199
1362
|
} catch (err) {
|
|
1200
|
-
if (
|
|
1201
|
-
|
|
1202
|
-
|
|
1363
|
+
if (
|
|
1364
|
+
!(err instanceof error.UnknownCommandError) &&
|
|
1365
|
+
!(err instanceof error.UnsupportedOperationError)
|
|
1366
|
+
) {
|
|
1367
|
+
throw err
|
|
1203
1368
|
}
|
|
1204
1369
|
|
|
1205
|
-
const cookies = await this.getCookies()
|
|
1370
|
+
const cookies = await this.getCookies()
|
|
1206
1371
|
for (let cookie of cookies) {
|
|
1207
1372
|
if (cookie && cookie['name'] === name) {
|
|
1208
|
-
return cookie
|
|
1373
|
+
return cookie
|
|
1209
1374
|
}
|
|
1210
1375
|
}
|
|
1211
|
-
return null
|
|
1376
|
+
return null
|
|
1212
1377
|
}
|
|
1213
1378
|
}
|
|
1214
1379
|
|
|
@@ -1223,7 +1388,7 @@ class Options {
|
|
|
1223
1388
|
* @see #setTimeouts()
|
|
1224
1389
|
*/
|
|
1225
1390
|
getTimeouts() {
|
|
1226
|
-
return this.driver_.execute(new command.Command(command.Name.GET_TIMEOUT))
|
|
1391
|
+
return this.driver_.execute(new command.Command(command.Name.GET_TIMEOUT))
|
|
1227
1392
|
}
|
|
1228
1393
|
|
|
1229
1394
|
/**
|
|
@@ -1255,60 +1420,59 @@ class Options {
|
|
|
1255
1420
|
* @see #getTimeouts()
|
|
1256
1421
|
* @see <https://w3c.github.io/webdriver/webdriver-spec.html#dfn-set-timeouts>
|
|
1257
1422
|
*/
|
|
1258
|
-
setTimeouts({script, pageLoad, implicit} = {}) {
|
|
1259
|
-
let cmd = new command.Command(command.Name.SET_TIMEOUT)
|
|
1423
|
+
setTimeouts({ script, pageLoad, implicit } = {}) {
|
|
1424
|
+
let cmd = new command.Command(command.Name.SET_TIMEOUT)
|
|
1260
1425
|
|
|
1261
|
-
let valid = false
|
|
1426
|
+
let valid = false
|
|
1262
1427
|
function setParam(key, value) {
|
|
1263
1428
|
if (value === null || typeof value === 'number') {
|
|
1264
|
-
valid = true
|
|
1265
|
-
cmd.setParameter(key, value)
|
|
1429
|
+
valid = true
|
|
1430
|
+
cmd.setParameter(key, value)
|
|
1266
1431
|
} else if (typeof value !== 'undefined') {
|
|
1267
1432
|
throw TypeError(
|
|
1268
|
-
|
|
1269
|
-
|
|
1433
|
+
'invalid timeouts configuration:' +
|
|
1434
|
+
` expected "${key}" to be a number, got ${typeof value}`
|
|
1435
|
+
)
|
|
1270
1436
|
}
|
|
1271
1437
|
}
|
|
1272
|
-
setParam('implicit', implicit)
|
|
1273
|
-
setParam('pageLoad', pageLoad)
|
|
1274
|
-
setParam('script', script)
|
|
1438
|
+
setParam('implicit', implicit)
|
|
1439
|
+
setParam('pageLoad', pageLoad)
|
|
1440
|
+
setParam('script', script)
|
|
1275
1441
|
|
|
1276
1442
|
if (valid) {
|
|
1277
|
-
return this.driver_.execute(cmd)
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
});
|
|
1443
|
+
return this.driver_.execute(cmd).catch(() => {
|
|
1444
|
+
// Fallback to the legacy method.
|
|
1445
|
+
let cmds = []
|
|
1446
|
+
if (typeof script === 'number') {
|
|
1447
|
+
cmds.push(legacyTimeout(this.driver_, 'script', script))
|
|
1448
|
+
}
|
|
1449
|
+
if (typeof implicit === 'number') {
|
|
1450
|
+
cmds.push(legacyTimeout(this.driver_, 'implicit', implicit))
|
|
1451
|
+
}
|
|
1452
|
+
if (typeof pageLoad === 'number') {
|
|
1453
|
+
cmds.push(legacyTimeout(this.driver_, 'page load', pageLoad))
|
|
1454
|
+
}
|
|
1455
|
+
return Promise.all(cmds)
|
|
1456
|
+
})
|
|
1292
1457
|
}
|
|
1293
|
-
throw TypeError('no timeouts specified')
|
|
1458
|
+
throw TypeError('no timeouts specified')
|
|
1294
1459
|
}
|
|
1295
1460
|
|
|
1296
1461
|
/**
|
|
1297
1462
|
* @return {!Logs} The interface for managing driver logs.
|
|
1298
1463
|
*/
|
|
1299
1464
|
logs() {
|
|
1300
|
-
return new Logs(this.driver_)
|
|
1465
|
+
return new Logs(this.driver_)
|
|
1301
1466
|
}
|
|
1302
1467
|
|
|
1303
1468
|
/**
|
|
1304
1469
|
* @return {!Window} The interface for managing the current window.
|
|
1305
1470
|
*/
|
|
1306
1471
|
window() {
|
|
1307
|
-
return new Window(this.driver_)
|
|
1472
|
+
return new Window(this.driver_)
|
|
1308
1473
|
}
|
|
1309
1474
|
}
|
|
1310
1475
|
|
|
1311
|
-
|
|
1312
1476
|
/**
|
|
1313
1477
|
* @param {!WebDriver} driver
|
|
1314
1478
|
* @param {string} type
|
|
@@ -1317,44 +1481,39 @@ class Options {
|
|
|
1317
1481
|
*/
|
|
1318
1482
|
function legacyTimeout(driver, type, ms) {
|
|
1319
1483
|
return driver.execute(
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1484
|
+
new command.Command(command.Name.SET_TIMEOUT)
|
|
1485
|
+
.setParameter('type', type)
|
|
1486
|
+
.setParameter('ms', ms)
|
|
1487
|
+
)
|
|
1323
1488
|
}
|
|
1324
1489
|
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
1490
|
/**
|
|
1328
1491
|
* A record object describing a browser cookie.
|
|
1329
1492
|
*
|
|
1330
1493
|
* @record
|
|
1331
1494
|
*/
|
|
1332
|
-
Options.Cookie = function() {}
|
|
1333
|
-
|
|
1495
|
+
Options.Cookie = function () {}
|
|
1334
1496
|
|
|
1335
1497
|
/**
|
|
1336
1498
|
* The name of the cookie.
|
|
1337
1499
|
*
|
|
1338
1500
|
* @type {string}
|
|
1339
1501
|
*/
|
|
1340
|
-
Options.Cookie.prototype.name
|
|
1341
|
-
|
|
1502
|
+
Options.Cookie.prototype.name
|
|
1342
1503
|
|
|
1343
1504
|
/**
|
|
1344
1505
|
* The cookie value.
|
|
1345
1506
|
*
|
|
1346
1507
|
* @type {string}
|
|
1347
1508
|
*/
|
|
1348
|
-
Options.Cookie.prototype.value
|
|
1349
|
-
|
|
1509
|
+
Options.Cookie.prototype.value
|
|
1350
1510
|
|
|
1351
1511
|
/**
|
|
1352
1512
|
* The cookie path. Defaults to "/" when adding a cookie.
|
|
1353
1513
|
*
|
|
1354
1514
|
* @type {(string|undefined)}
|
|
1355
1515
|
*/
|
|
1356
|
-
Options.Cookie.prototype.path
|
|
1357
|
-
|
|
1516
|
+
Options.Cookie.prototype.path
|
|
1358
1517
|
|
|
1359
1518
|
/**
|
|
1360
1519
|
* The domain the cookie is visible to. Defaults to the current browsing
|
|
@@ -1362,8 +1521,7 @@ Options.Cookie.prototype.path;
|
|
|
1362
1521
|
*
|
|
1363
1522
|
* @type {(string|undefined)}
|
|
1364
1523
|
*/
|
|
1365
|
-
Options.Cookie.prototype.domain
|
|
1366
|
-
|
|
1524
|
+
Options.Cookie.prototype.domain
|
|
1367
1525
|
|
|
1368
1526
|
/**
|
|
1369
1527
|
* Whether the cookie is a secure cookie. Defaults to false when adding a new
|
|
@@ -1371,8 +1529,7 @@ Options.Cookie.prototype.domain;
|
|
|
1371
1529
|
*
|
|
1372
1530
|
* @type {(boolean|undefined)}
|
|
1373
1531
|
*/
|
|
1374
|
-
Options.Cookie.prototype.secure
|
|
1375
|
-
|
|
1532
|
+
Options.Cookie.prototype.secure
|
|
1376
1533
|
|
|
1377
1534
|
/**
|
|
1378
1535
|
* Whether the cookie is an HTTP only cookie. Defaults to false when adding a
|
|
@@ -1380,8 +1537,7 @@ Options.Cookie.prototype.secure;
|
|
|
1380
1537
|
*
|
|
1381
1538
|
* @type {(boolean|undefined)}
|
|
1382
1539
|
*/
|
|
1383
|
-
Options.Cookie.prototype.httpOnly
|
|
1384
|
-
|
|
1540
|
+
Options.Cookie.prototype.httpOnly
|
|
1385
1541
|
|
|
1386
1542
|
/**
|
|
1387
1543
|
* When the cookie expires.
|
|
@@ -1394,8 +1550,18 @@ Options.Cookie.prototype.httpOnly;
|
|
|
1394
1550
|
*
|
|
1395
1551
|
* @type {(!Date|number|undefined)}
|
|
1396
1552
|
*/
|
|
1397
|
-
Options.Cookie.prototype.expiry
|
|
1553
|
+
Options.Cookie.prototype.expiry
|
|
1398
1554
|
|
|
1555
|
+
/**
|
|
1556
|
+
* When the cookie applies to a SameSite policy.
|
|
1557
|
+
*
|
|
1558
|
+
* When {@linkplain Options#addCookie() adding a cookie}, this may be specified
|
|
1559
|
+
* as a {@link string} object which is one of 'Lax', 'Strict' or 'None'.
|
|
1560
|
+
*
|
|
1561
|
+
*
|
|
1562
|
+
* @type {(string|undefined)}
|
|
1563
|
+
*/
|
|
1564
|
+
Options.Cookie.prototype.sameSite
|
|
1399
1565
|
|
|
1400
1566
|
/**
|
|
1401
1567
|
* An interface for managing the current window.
|
|
@@ -1415,7 +1581,7 @@ class Window {
|
|
|
1415
1581
|
*/
|
|
1416
1582
|
constructor(driver) {
|
|
1417
1583
|
/** @private {!WebDriver} */
|
|
1418
|
-
this.driver_ = driver
|
|
1584
|
+
this.driver_ = driver
|
|
1419
1585
|
}
|
|
1420
1586
|
|
|
1421
1587
|
/**
|
|
@@ -1428,20 +1594,25 @@ class Window {
|
|
|
1428
1594
|
async getRect() {
|
|
1429
1595
|
try {
|
|
1430
1596
|
return await this.driver_.execute(
|
|
1431
|
-
|
|
1597
|
+
new command.Command(command.Name.GET_WINDOW_RECT)
|
|
1598
|
+
)
|
|
1432
1599
|
} catch (ex) {
|
|
1433
1600
|
if (ex instanceof error.UnknownCommandError) {
|
|
1434
|
-
let {width, height} =
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1601
|
+
let { width, height } = await this.driver_.execute(
|
|
1602
|
+
new command.Command(command.Name.GET_WINDOW_SIZE).setParameter(
|
|
1603
|
+
'windowHandle',
|
|
1604
|
+
'current'
|
|
1605
|
+
)
|
|
1606
|
+
)
|
|
1607
|
+
let { x, y } = await this.driver_.execute(
|
|
1608
|
+
new command.Command(command.Name.GET_WINDOW_POSITION).setParameter(
|
|
1609
|
+
'windowHandle',
|
|
1610
|
+
'current'
|
|
1611
|
+
)
|
|
1612
|
+
)
|
|
1613
|
+
return { x, y, width, height }
|
|
1443
1614
|
}
|
|
1444
|
-
throw ex
|
|
1615
|
+
throw ex
|
|
1445
1616
|
}
|
|
1446
1617
|
}
|
|
1447
1618
|
|
|
@@ -1456,34 +1627,41 @@ class Window {
|
|
|
1456
1627
|
* height: (number|undefined)}} options
|
|
1457
1628
|
* The desired window size and position.
|
|
1458
1629
|
* @return {!Promise<{x: number, y: number, width: number, height: number}>}
|
|
1459
|
-
* A promise that will resolve to the current
|
|
1630
|
+
* A promise that will resolve to the current window's updated window
|
|
1460
1631
|
* rect.
|
|
1461
1632
|
*/
|
|
1462
|
-
async setRect({x, y, width, height}) {
|
|
1633
|
+
async setRect({ x, y, width, height }) {
|
|
1463
1634
|
try {
|
|
1464
1635
|
return await this.driver_.execute(
|
|
1465
|
-
|
|
1466
|
-
|
|
1636
|
+
new command.Command(command.Name.SET_WINDOW_RECT).setParameters({
|
|
1637
|
+
x,
|
|
1638
|
+
y,
|
|
1639
|
+
width,
|
|
1640
|
+
height,
|
|
1641
|
+
})
|
|
1642
|
+
)
|
|
1467
1643
|
} catch (ex) {
|
|
1468
1644
|
if (ex instanceof error.UnknownCommandError) {
|
|
1469
1645
|
if (typeof x === 'number' && typeof y === 'number') {
|
|
1470
1646
|
await this.driver_.execute(
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1647
|
+
new command.Command(command.Name.SET_WINDOW_POSITION)
|
|
1648
|
+
.setParameter('windowHandle', 'current')
|
|
1649
|
+
.setParameter('x', x)
|
|
1650
|
+
.setParameter('y', y)
|
|
1651
|
+
)
|
|
1475
1652
|
}
|
|
1476
1653
|
|
|
1477
|
-
if (typeof
|
|
1654
|
+
if (typeof width === 'number' && typeof height === 'number') {
|
|
1478
1655
|
await this.driver_.execute(
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1656
|
+
new command.Command(command.Name.SET_WINDOW_SIZE)
|
|
1657
|
+
.setParameter('windowHandle', 'current')
|
|
1658
|
+
.setParameter('width', width)
|
|
1659
|
+
.setParameter('height', height)
|
|
1660
|
+
)
|
|
1483
1661
|
}
|
|
1484
|
-
return this.getRect()
|
|
1662
|
+
return this.getRect()
|
|
1485
1663
|
}
|
|
1486
|
-
throw ex
|
|
1664
|
+
throw ex
|
|
1487
1665
|
}
|
|
1488
1666
|
}
|
|
1489
1667
|
|
|
@@ -1497,13 +1675,16 @@ class Window {
|
|
|
1497
1675
|
*/
|
|
1498
1676
|
maximize() {
|
|
1499
1677
|
return this.driver_.execute(
|
|
1500
|
-
|
|
1501
|
-
|
|
1678
|
+
new command.Command(command.Name.MAXIMIZE_WINDOW).setParameter(
|
|
1679
|
+
'windowHandle',
|
|
1680
|
+
'current'
|
|
1681
|
+
)
|
|
1682
|
+
)
|
|
1502
1683
|
}
|
|
1503
1684
|
|
|
1504
1685
|
/**
|
|
1505
1686
|
* Minimizes the current window. The exact behavior of this command is
|
|
1506
|
-
* specific to individual window managers, but
|
|
1687
|
+
* specific to individual window managers, but typically involves hiding
|
|
1507
1688
|
* the window in the system tray.
|
|
1508
1689
|
*
|
|
1509
1690
|
* @return {!Promise<void>} A promise that will be resolved when the command
|
|
@@ -1511,7 +1692,8 @@ class Window {
|
|
|
1511
1692
|
*/
|
|
1512
1693
|
minimize() {
|
|
1513
1694
|
return this.driver_.execute(
|
|
1514
|
-
|
|
1695
|
+
new command.Command(command.Name.MINIMIZE_WINDOW)
|
|
1696
|
+
)
|
|
1515
1697
|
}
|
|
1516
1698
|
|
|
1517
1699
|
/**
|
|
@@ -1526,11 +1708,11 @@ class Window {
|
|
|
1526
1708
|
*/
|
|
1527
1709
|
fullscreen() {
|
|
1528
1710
|
return this.driver_.execute(
|
|
1529
|
-
|
|
1711
|
+
new command.Command(command.Name.FULLSCREEN_WINDOW)
|
|
1712
|
+
)
|
|
1530
1713
|
}
|
|
1531
1714
|
}
|
|
1532
1715
|
|
|
1533
|
-
|
|
1534
1716
|
/**
|
|
1535
1717
|
* Interface for managing WebDriver log records.
|
|
1536
1718
|
*
|
|
@@ -1549,7 +1731,7 @@ class Logs {
|
|
|
1549
1731
|
*/
|
|
1550
1732
|
constructor(driver) {
|
|
1551
1733
|
/** @private {!WebDriver} */
|
|
1552
|
-
this.driver_ = driver
|
|
1734
|
+
this.driver_ = driver
|
|
1553
1735
|
}
|
|
1554
1736
|
|
|
1555
1737
|
/**
|
|
@@ -1566,19 +1748,23 @@ class Logs {
|
|
|
1566
1748
|
* type.
|
|
1567
1749
|
*/
|
|
1568
1750
|
get(type) {
|
|
1569
|
-
let cmd = new command.Command(command.Name.GET_LOG).
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1751
|
+
let cmd = new command.Command(command.Name.GET_LOG).setParameter(
|
|
1752
|
+
'type',
|
|
1753
|
+
type
|
|
1754
|
+
)
|
|
1755
|
+
return this.driver_.execute(cmd).then(function (entries) {
|
|
1756
|
+
return entries.map(function (entry) {
|
|
1757
|
+
if (!(entry instanceof logging.Entry)) {
|
|
1758
|
+
return new logging.Entry(
|
|
1759
|
+
entry['level'],
|
|
1760
|
+
entry['message'],
|
|
1761
|
+
entry['timestamp'],
|
|
1762
|
+
entry['type']
|
|
1763
|
+
)
|
|
1764
|
+
}
|
|
1765
|
+
return entry
|
|
1766
|
+
})
|
|
1767
|
+
})
|
|
1582
1768
|
}
|
|
1583
1769
|
|
|
1584
1770
|
/**
|
|
@@ -1588,11 +1774,11 @@ class Logs {
|
|
|
1588
1774
|
*/
|
|
1589
1775
|
getAvailableLogTypes() {
|
|
1590
1776
|
return this.driver_.execute(
|
|
1591
|
-
|
|
1777
|
+
new command.Command(command.Name.GET_AVAILABLE_LOG_TYPES)
|
|
1778
|
+
)
|
|
1592
1779
|
}
|
|
1593
1780
|
}
|
|
1594
1781
|
|
|
1595
|
-
|
|
1596
1782
|
/**
|
|
1597
1783
|
* An interface for changing the focus of the driver to another frame or window.
|
|
1598
1784
|
*
|
|
@@ -1610,7 +1796,7 @@ class TargetLocator {
|
|
|
1610
1796
|
*/
|
|
1611
1797
|
constructor(driver) {
|
|
1612
1798
|
/** @private {!WebDriver} */
|
|
1613
|
-
this.driver_ = driver
|
|
1799
|
+
this.driver_ = driver
|
|
1614
1800
|
}
|
|
1615
1801
|
|
|
1616
1802
|
/**
|
|
@@ -1622,8 +1808,9 @@ class TargetLocator {
|
|
|
1622
1808
|
*/
|
|
1623
1809
|
activeElement() {
|
|
1624
1810
|
var id = this.driver_.execute(
|
|
1625
|
-
|
|
1626
|
-
|
|
1811
|
+
new command.Command(command.Name.GET_ACTIVE_ELEMENT)
|
|
1812
|
+
)
|
|
1813
|
+
return new WebElementPromise(this.driver_, id)
|
|
1627
1814
|
}
|
|
1628
1815
|
|
|
1629
1816
|
/**
|
|
@@ -1635,8 +1822,8 @@ class TargetLocator {
|
|
|
1635
1822
|
*/
|
|
1636
1823
|
defaultContent() {
|
|
1637
1824
|
return this.driver_.execute(
|
|
1638
|
-
|
|
1639
|
-
|
|
1825
|
+
new command.Command(command.Name.SWITCH_TO_FRAME).setParameter('id', null)
|
|
1826
|
+
)
|
|
1640
1827
|
}
|
|
1641
1828
|
|
|
1642
1829
|
/**
|
|
@@ -1659,8 +1846,8 @@ class TargetLocator {
|
|
|
1659
1846
|
*/
|
|
1660
1847
|
frame(id) {
|
|
1661
1848
|
return this.driver_.execute(
|
|
1662
|
-
|
|
1663
|
-
|
|
1849
|
+
new command.Command(command.Name.SWITCH_TO_FRAME).setParameter('id', id)
|
|
1850
|
+
)
|
|
1664
1851
|
}
|
|
1665
1852
|
|
|
1666
1853
|
/**
|
|
@@ -1673,7 +1860,8 @@ class TargetLocator {
|
|
|
1673
1860
|
*/
|
|
1674
1861
|
parentFrame() {
|
|
1675
1862
|
return this.driver_.execute(
|
|
1676
|
-
|
|
1863
|
+
new command.Command(command.Name.SWITCH_TO_FRAME_PARENT)
|
|
1864
|
+
)
|
|
1677
1865
|
}
|
|
1678
1866
|
|
|
1679
1867
|
/**
|
|
@@ -1691,11 +1879,12 @@ class TargetLocator {
|
|
|
1691
1879
|
*/
|
|
1692
1880
|
window(nameOrHandle) {
|
|
1693
1881
|
return this.driver_.execute(
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1882
|
+
new command.Command(command.Name.SWITCH_TO_WINDOW)
|
|
1883
|
+
// "name" supports the legacy drivers. "handle" is the W3C
|
|
1884
|
+
// compliant parameter.
|
|
1885
|
+
.setParameter('name', nameOrHandle)
|
|
1886
|
+
.setParameter('handle', nameOrHandle)
|
|
1887
|
+
)
|
|
1699
1888
|
}
|
|
1700
1889
|
|
|
1701
1890
|
/**
|
|
@@ -1711,12 +1900,16 @@ class TargetLocator {
|
|
|
1711
1900
|
*/
|
|
1712
1901
|
newWindow(typeHint) {
|
|
1713
1902
|
var driver = this.driver_
|
|
1714
|
-
return this.driver_
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1903
|
+
return this.driver_
|
|
1904
|
+
.execute(
|
|
1905
|
+
new command.Command(command.Name.SWITCH_TO_NEW_WINDOW).setParameter(
|
|
1906
|
+
'type',
|
|
1907
|
+
typeHint
|
|
1908
|
+
)
|
|
1909
|
+
)
|
|
1910
|
+
.then(function (response) {
|
|
1911
|
+
return driver.switchTo().window(response.handle)
|
|
1912
|
+
})
|
|
1720
1913
|
}
|
|
1721
1914
|
|
|
1722
1915
|
/**
|
|
@@ -1729,25 +1922,26 @@ class TargetLocator {
|
|
|
1729
1922
|
*/
|
|
1730
1923
|
alert() {
|
|
1731
1924
|
var text = this.driver_.execute(
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1925
|
+
new command.Command(command.Name.GET_ALERT_TEXT)
|
|
1926
|
+
)
|
|
1927
|
+
var driver = this.driver_
|
|
1928
|
+
return new AlertPromise(
|
|
1929
|
+
driver,
|
|
1930
|
+
text.then(function (text) {
|
|
1931
|
+
return new Alert(driver, text)
|
|
1932
|
+
})
|
|
1933
|
+
)
|
|
1737
1934
|
}
|
|
1738
1935
|
}
|
|
1739
1936
|
|
|
1740
|
-
|
|
1741
1937
|
//////////////////////////////////////////////////////////////////////////////
|
|
1742
1938
|
//
|
|
1743
1939
|
// WebElement
|
|
1744
1940
|
//
|
|
1745
1941
|
//////////////////////////////////////////////////////////////////////////////
|
|
1746
1942
|
|
|
1747
|
-
|
|
1748
|
-
const
|
|
1749
|
-
const ELEMENT_ID_KEY = 'element-6066-11e4-a52e-4f735466cecf';
|
|
1750
|
-
|
|
1943
|
+
const LEGACY_ELEMENT_ID_KEY = 'ELEMENT'
|
|
1944
|
+
const ELEMENT_ID_KEY = 'element-6066-11e4-a52e-4f735466cecf'
|
|
1751
1945
|
|
|
1752
1946
|
/**
|
|
1753
1947
|
* Represents a DOM element. WebElements can be found by searching from the
|
|
@@ -1767,10 +1961,10 @@ class WebElement {
|
|
|
1767
1961
|
*/
|
|
1768
1962
|
constructor(driver, id) {
|
|
1769
1963
|
/** @private {!WebDriver} */
|
|
1770
|
-
this.driver_ = driver
|
|
1964
|
+
this.driver_ = driver
|
|
1771
1965
|
|
|
1772
1966
|
/** @private {!Promise<string>} */
|
|
1773
|
-
this.id_ = Promise.resolve(id)
|
|
1967
|
+
this.id_ = Promise.resolve(id)
|
|
1774
1968
|
}
|
|
1775
1969
|
|
|
1776
1970
|
/**
|
|
@@ -1780,8 +1974,8 @@ class WebElement {
|
|
|
1780
1974
|
*/
|
|
1781
1975
|
static buildId(id, noLegacy = false) {
|
|
1782
1976
|
return noLegacy
|
|
1783
|
-
|
|
1784
|
-
|
|
1977
|
+
? { [ELEMENT_ID_KEY]: id }
|
|
1978
|
+
: { [ELEMENT_ID_KEY]: id, [LEGACY_ELEMENT_ID_KEY]: id }
|
|
1785
1979
|
}
|
|
1786
1980
|
|
|
1787
1981
|
/**
|
|
@@ -1794,12 +1988,12 @@ class WebElement {
|
|
|
1794
1988
|
static extractId(obj) {
|
|
1795
1989
|
if (obj && typeof obj === 'object') {
|
|
1796
1990
|
if (typeof obj[ELEMENT_ID_KEY] === 'string') {
|
|
1797
|
-
return obj[ELEMENT_ID_KEY]
|
|
1991
|
+
return obj[ELEMENT_ID_KEY]
|
|
1798
1992
|
} else if (typeof obj[LEGACY_ELEMENT_ID_KEY] === 'string') {
|
|
1799
|
-
return obj[LEGACY_ELEMENT_ID_KEY]
|
|
1993
|
+
return obj[LEGACY_ELEMENT_ID_KEY]
|
|
1800
1994
|
}
|
|
1801
1995
|
}
|
|
1802
|
-
throw new TypeError('object is not a WebElement ID')
|
|
1996
|
+
throw new TypeError('object is not a WebElement ID')
|
|
1803
1997
|
}
|
|
1804
1998
|
|
|
1805
1999
|
/**
|
|
@@ -1807,9 +2001,12 @@ class WebElement {
|
|
|
1807
2001
|
* @return {boolean} whether the object is a valid encoded WebElement ID.
|
|
1808
2002
|
*/
|
|
1809
2003
|
static isId(obj) {
|
|
1810
|
-
return
|
|
1811
|
-
|
|
1812
|
-
|
|
2004
|
+
return (
|
|
2005
|
+
obj &&
|
|
2006
|
+
typeof obj === 'object' &&
|
|
2007
|
+
(typeof obj[ELEMENT_ID_KEY] === 'string' ||
|
|
2008
|
+
typeof obj[LEGACY_ELEMENT_ID_KEY] === 'string')
|
|
2009
|
+
)
|
|
1813
2010
|
}
|
|
1814
2011
|
|
|
1815
2012
|
/**
|
|
@@ -1822,15 +2019,14 @@ class WebElement {
|
|
|
1822
2019
|
*/
|
|
1823
2020
|
static async equals(a, b) {
|
|
1824
2021
|
if (a === b) {
|
|
1825
|
-
return true
|
|
2022
|
+
return true
|
|
1826
2023
|
}
|
|
1827
|
-
return a.driver_.executeScript(
|
|
1828
|
-
'return arguments[0] === arguments[1]', a, b);
|
|
2024
|
+
return a.driver_.executeScript('return arguments[0] === arguments[1]', a, b)
|
|
1829
2025
|
}
|
|
1830
2026
|
|
|
1831
2027
|
/** @return {!WebDriver} The parent driver for this instance. */
|
|
1832
2028
|
getDriver() {
|
|
1833
|
-
return this.driver_
|
|
2029
|
+
return this.driver_
|
|
1834
2030
|
}
|
|
1835
2031
|
|
|
1836
2032
|
/**
|
|
@@ -1838,14 +2034,14 @@ class WebElement {
|
|
|
1838
2034
|
* the server-assigned opaque ID assigned to this element.
|
|
1839
2035
|
*/
|
|
1840
2036
|
getId() {
|
|
1841
|
-
return this.id_
|
|
2037
|
+
return this.id_
|
|
1842
2038
|
}
|
|
1843
2039
|
|
|
1844
2040
|
/**
|
|
1845
2041
|
* @return {!Object} Returns the serialized representation of this WebElement.
|
|
1846
2042
|
*/
|
|
1847
2043
|
[Symbols.serialize]() {
|
|
1848
|
-
return this.getId().then(WebElement.buildId)
|
|
2044
|
+
return this.getId().then(WebElement.buildId)
|
|
1849
2045
|
}
|
|
1850
2046
|
|
|
1851
2047
|
/**
|
|
@@ -1860,8 +2056,8 @@ class WebElement {
|
|
|
1860
2056
|
* @private
|
|
1861
2057
|
*/
|
|
1862
2058
|
execute_(command) {
|
|
1863
|
-
command.setParameter('id', this)
|
|
1864
|
-
return this.driver_.execute(command)
|
|
2059
|
+
command.setParameter('id', this)
|
|
2060
|
+
return this.driver_.execute(command)
|
|
1865
2061
|
}
|
|
1866
2062
|
|
|
1867
2063
|
/**
|
|
@@ -1899,18 +2095,17 @@ class WebElement {
|
|
|
1899
2095
|
* element will be invalidated and all scheduled commands aborted.
|
|
1900
2096
|
*/
|
|
1901
2097
|
findElement(locator) {
|
|
1902
|
-
locator = by.checkedLocator(locator)
|
|
1903
|
-
let id
|
|
2098
|
+
locator = by.checkedLocator(locator)
|
|
2099
|
+
let id
|
|
1904
2100
|
if (typeof locator === 'function') {
|
|
1905
|
-
id = this.driver_.findElementInternal_(locator, this)
|
|
2101
|
+
id = this.driver_.findElementInternal_(locator, this)
|
|
1906
2102
|
} else {
|
|
1907
|
-
let cmd = new command.Command(
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
id = this.execute_(cmd);
|
|
2103
|
+
let cmd = new command.Command(command.Name.FIND_CHILD_ELEMENT)
|
|
2104
|
+
.setParameter('using', locator.using)
|
|
2105
|
+
.setParameter('value', locator.value)
|
|
2106
|
+
id = this.execute_(cmd)
|
|
1912
2107
|
}
|
|
1913
|
-
return new WebElementPromise(this.driver_, id)
|
|
2108
|
+
return new WebElementPromise(this.driver_, id)
|
|
1914
2109
|
}
|
|
1915
2110
|
|
|
1916
2111
|
/**
|
|
@@ -1923,16 +2118,15 @@ class WebElement {
|
|
|
1923
2118
|
* array of WebElements.
|
|
1924
2119
|
*/
|
|
1925
2120
|
async findElements(locator) {
|
|
1926
|
-
locator = by.checkedLocator(locator)
|
|
1927
|
-
let id;
|
|
2121
|
+
locator = by.checkedLocator(locator)
|
|
1928
2122
|
if (typeof locator === 'function') {
|
|
1929
|
-
return this.driver_.findElementsInternal_(locator, this)
|
|
2123
|
+
return this.driver_.findElementsInternal_(locator, this)
|
|
1930
2124
|
} else {
|
|
1931
2125
|
let cmd = new command.Command(command.Name.FIND_CHILD_ELEMENTS)
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
let result = await this.execute_(cmd)
|
|
1935
|
-
return Array.isArray(result) ? result : []
|
|
2126
|
+
.setParameter('using', locator.using)
|
|
2127
|
+
.setParameter('value', locator.value)
|
|
2128
|
+
let result = await this.execute_(cmd)
|
|
2129
|
+
return Array.isArray(result) ? result : []
|
|
1936
2130
|
}
|
|
1937
2131
|
}
|
|
1938
2132
|
|
|
@@ -1943,7 +2137,7 @@ class WebElement {
|
|
|
1943
2137
|
* command has completed.
|
|
1944
2138
|
*/
|
|
1945
2139
|
click() {
|
|
1946
|
-
return this.execute_(new command.Command(command.Name.CLICK_ELEMENT))
|
|
2140
|
+
return this.execute_(new command.Command(command.Name.CLICK_ELEMENT))
|
|
1947
2141
|
}
|
|
1948
2142
|
|
|
1949
2143
|
/**
|
|
@@ -2002,34 +2196,37 @@ class WebElement {
|
|
|
2002
2196
|
* have been typed.
|
|
2003
2197
|
*/
|
|
2004
2198
|
async sendKeys(...args) {
|
|
2005
|
-
let keys = []
|
|
2006
|
-
(await Promise.all(args)).forEach(key => {
|
|
2007
|
-
let type = typeof key
|
|
2199
|
+
let keys = []
|
|
2200
|
+
;(await Promise.all(args)).forEach((key) => {
|
|
2201
|
+
let type = typeof key
|
|
2008
2202
|
if (type === 'number') {
|
|
2009
|
-
key = String(key)
|
|
2203
|
+
key = String(key)
|
|
2010
2204
|
} else if (type !== 'string') {
|
|
2011
|
-
throw TypeError('each key must be a number of string; got ' + type)
|
|
2205
|
+
throw TypeError('each key must be a number of string; got ' + type)
|
|
2012
2206
|
}
|
|
2013
2207
|
|
|
2014
2208
|
// The W3C protocol requires keys to be specified as an array where
|
|
2015
2209
|
// each element is a single key.
|
|
2016
|
-
keys.push(...key.split(''))
|
|
2017
|
-
})
|
|
2210
|
+
keys.push(...key.split(''))
|
|
2211
|
+
})
|
|
2018
2212
|
|
|
2019
2213
|
if (!this.driver_.fileDetector_) {
|
|
2020
2214
|
return this.execute_(
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2215
|
+
new command.Command(command.Name.SEND_KEYS_TO_ELEMENT)
|
|
2216
|
+
.setParameter('text', keys.join(''))
|
|
2217
|
+
.setParameter('value', keys)
|
|
2218
|
+
)
|
|
2024
2219
|
}
|
|
2025
2220
|
|
|
2026
|
-
keys =
|
|
2027
|
-
|
|
2028
|
-
|
|
2221
|
+
keys = await this.driver_.fileDetector_.handleFile(
|
|
2222
|
+
this.driver_,
|
|
2223
|
+
keys.join('')
|
|
2224
|
+
)
|
|
2029
2225
|
return this.execute_(
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2226
|
+
new command.Command(command.Name.SEND_KEYS_TO_ELEMENT)
|
|
2227
|
+
.setParameter('text', keys)
|
|
2228
|
+
.setParameter('value', keys.split(''))
|
|
2229
|
+
)
|
|
2033
2230
|
}
|
|
2034
2231
|
|
|
2035
2232
|
/**
|
|
@@ -2039,8 +2236,7 @@ class WebElement {
|
|
|
2039
2236
|
* element's tag name.
|
|
2040
2237
|
*/
|
|
2041
2238
|
getTagName() {
|
|
2042
|
-
return this.execute_(
|
|
2043
|
-
new command.Command(command.Name.GET_ELEMENT_TAG_NAME));
|
|
2239
|
+
return this.execute_(new command.Command(command.Name.GET_ELEMENT_TAG_NAME))
|
|
2044
2240
|
}
|
|
2045
2241
|
|
|
2046
2242
|
/**
|
|
@@ -2058,10 +2254,10 @@ class WebElement {
|
|
|
2058
2254
|
* requested CSS value.
|
|
2059
2255
|
*/
|
|
2060
2256
|
getCssValue(cssStyleProperty) {
|
|
2061
|
-
var name = command.Name.GET_ELEMENT_VALUE_OF_CSS_PROPERTY
|
|
2257
|
+
var name = command.Name.GET_ELEMENT_VALUE_OF_CSS_PROPERTY
|
|
2062
2258
|
return this.execute_(
|
|
2063
|
-
|
|
2064
|
-
|
|
2259
|
+
new command.Command(name).setParameter('propertyName', cssStyleProperty)
|
|
2260
|
+
)
|
|
2065
2261
|
}
|
|
2066
2262
|
|
|
2067
2263
|
/**
|
|
@@ -2095,8 +2291,26 @@ class WebElement {
|
|
|
2095
2291
|
*/
|
|
2096
2292
|
getAttribute(attributeName) {
|
|
2097
2293
|
return this.execute_(
|
|
2098
|
-
|
|
2099
|
-
|
|
2294
|
+
new command.Command(command.Name.GET_ELEMENT_ATTRIBUTE).setParameter(
|
|
2295
|
+
'name',
|
|
2296
|
+
attributeName
|
|
2297
|
+
)
|
|
2298
|
+
)
|
|
2299
|
+
}
|
|
2300
|
+
|
|
2301
|
+
/**
|
|
2302
|
+
* Get the given property of the referenced web element
|
|
2303
|
+
* @param {string} propertyName The name of the attribute to query.
|
|
2304
|
+
* @return {!Promise<string>} A promise that will be
|
|
2305
|
+
* resolved with the element's property value
|
|
2306
|
+
*/
|
|
2307
|
+
getProperty(propertyName) {
|
|
2308
|
+
return this.execute_(
|
|
2309
|
+
new command.Command(command.Name.GET_ELEMENT_PROPERTY).setParameter(
|
|
2310
|
+
'name',
|
|
2311
|
+
propertyName
|
|
2312
|
+
)
|
|
2313
|
+
)
|
|
2100
2314
|
}
|
|
2101
2315
|
|
|
2102
2316
|
/**
|
|
@@ -2107,7 +2321,7 @@ class WebElement {
|
|
|
2107
2321
|
* resolved with the element's visible text.
|
|
2108
2322
|
*/
|
|
2109
2323
|
getText() {
|
|
2110
|
-
return this.execute_(new command.Command(command.Name.GET_ELEMENT_TEXT))
|
|
2324
|
+
return this.execute_(new command.Command(command.Name.GET_ELEMENT_TEXT))
|
|
2111
2325
|
}
|
|
2112
2326
|
|
|
2113
2327
|
/**
|
|
@@ -2120,16 +2334,17 @@ class WebElement {
|
|
|
2120
2334
|
async getRect() {
|
|
2121
2335
|
try {
|
|
2122
2336
|
return await this.execute_(
|
|
2123
|
-
|
|
2337
|
+
new command.Command(command.Name.GET_ELEMENT_RECT)
|
|
2338
|
+
)
|
|
2124
2339
|
} catch (err) {
|
|
2125
2340
|
if (err instanceof error.UnknownCommandError) {
|
|
2126
|
-
const {width, height} =
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
const {x, y} =
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
return {x, y, width, height}
|
|
2341
|
+
const { width, height } = await this.execute_(
|
|
2342
|
+
new command.Command(command.Name.GET_ELEMENT_SIZE)
|
|
2343
|
+
)
|
|
2344
|
+
const { x, y } = await this.execute_(
|
|
2345
|
+
new command.Command(command.Name.GET_ELEMENT_LOCATION)
|
|
2346
|
+
)
|
|
2347
|
+
return { x, y, width, height }
|
|
2133
2348
|
}
|
|
2134
2349
|
}
|
|
2135
2350
|
}
|
|
@@ -2142,7 +2357,7 @@ class WebElement {
|
|
|
2142
2357
|
* resolved with whether this element is currently enabled.
|
|
2143
2358
|
*/
|
|
2144
2359
|
isEnabled() {
|
|
2145
|
-
return this.execute_(new command.Command(command.Name.IS_ELEMENT_ENABLED))
|
|
2360
|
+
return this.execute_(new command.Command(command.Name.IS_ELEMENT_ENABLED))
|
|
2146
2361
|
}
|
|
2147
2362
|
|
|
2148
2363
|
/**
|
|
@@ -2152,8 +2367,7 @@ class WebElement {
|
|
|
2152
2367
|
* resolved with whether this element is currently selected.
|
|
2153
2368
|
*/
|
|
2154
2369
|
isSelected() {
|
|
2155
|
-
return this.execute_(
|
|
2156
|
-
new command.Command(command.Name.IS_ELEMENT_SELECTED));
|
|
2370
|
+
return this.execute_(new command.Command(command.Name.IS_ELEMENT_SELECTED))
|
|
2157
2371
|
}
|
|
2158
2372
|
|
|
2159
2373
|
/**
|
|
@@ -2165,7 +2379,7 @@ class WebElement {
|
|
|
2165
2379
|
* when the form has been submitted.
|
|
2166
2380
|
*/
|
|
2167
2381
|
submit() {
|
|
2168
|
-
return this.execute_(new command.Command(command.Name.SUBMIT_ELEMENT))
|
|
2382
|
+
return this.execute_(new command.Command(command.Name.SUBMIT_ELEMENT))
|
|
2169
2383
|
}
|
|
2170
2384
|
|
|
2171
2385
|
/**
|
|
@@ -2177,7 +2391,7 @@ class WebElement {
|
|
|
2177
2391
|
* when the element has been cleared.
|
|
2178
2392
|
*/
|
|
2179
2393
|
clear() {
|
|
2180
|
-
return this.execute_(new command.Command(command.Name.CLEAR_ELEMENT))
|
|
2394
|
+
return this.execute_(new command.Command(command.Name.CLEAR_ELEMENT))
|
|
2181
2395
|
}
|
|
2182
2396
|
|
|
2183
2397
|
/**
|
|
@@ -2187,8 +2401,7 @@ class WebElement {
|
|
|
2187
2401
|
* resolved with whether this element is currently visible on the page.
|
|
2188
2402
|
*/
|
|
2189
2403
|
isDisplayed() {
|
|
2190
|
-
return this.execute_(
|
|
2191
|
-
new command.Command(command.Name.IS_ELEMENT_DISPLAYED));
|
|
2404
|
+
return this.execute_(new command.Command(command.Name.IS_ELEMENT_DISPLAYED))
|
|
2192
2405
|
}
|
|
2193
2406
|
|
|
2194
2407
|
/**
|
|
@@ -2203,12 +2416,14 @@ class WebElement {
|
|
|
2203
2416
|
*/
|
|
2204
2417
|
takeScreenshot(scroll = false) {
|
|
2205
2418
|
return this.execute_(
|
|
2206
|
-
|
|
2207
|
-
|
|
2419
|
+
new command.Command(command.Name.TAKE_ELEMENT_SCREENSHOT).setParameter(
|
|
2420
|
+
'scroll',
|
|
2421
|
+
scroll
|
|
2422
|
+
)
|
|
2423
|
+
)
|
|
2208
2424
|
}
|
|
2209
2425
|
}
|
|
2210
2426
|
|
|
2211
|
-
|
|
2212
2427
|
/**
|
|
2213
2428
|
* WebElementPromise is a promise that will be fulfilled with a WebElement.
|
|
2214
2429
|
* This serves as a forward proxy on WebElement, allowing calls to be
|
|
@@ -2232,35 +2447,33 @@ class WebElementPromise extends WebElement {
|
|
|
2232
2447
|
* that will resolve to the promised element.
|
|
2233
2448
|
*/
|
|
2234
2449
|
constructor(driver, el) {
|
|
2235
|
-
super(driver, 'unused')
|
|
2450
|
+
super(driver, 'unused')
|
|
2236
2451
|
|
|
2237
2452
|
/** @override */
|
|
2238
|
-
this.then = el.then.bind(el)
|
|
2453
|
+
this.then = el.then.bind(el)
|
|
2239
2454
|
|
|
2240
2455
|
/** @override */
|
|
2241
|
-
this.catch = el.catch.bind(el)
|
|
2456
|
+
this.catch = el.catch.bind(el)
|
|
2242
2457
|
|
|
2243
2458
|
/**
|
|
2244
2459
|
* Defers returning the element ID until the wrapped WebElement has been
|
|
2245
2460
|
* resolved.
|
|
2246
2461
|
* @override
|
|
2247
2462
|
*/
|
|
2248
|
-
this.getId = function() {
|
|
2249
|
-
return el.then(function(el) {
|
|
2250
|
-
return el.getId()
|
|
2251
|
-
})
|
|
2252
|
-
}
|
|
2463
|
+
this.getId = function () {
|
|
2464
|
+
return el.then(function (el) {
|
|
2465
|
+
return el.getId()
|
|
2466
|
+
})
|
|
2467
|
+
}
|
|
2253
2468
|
}
|
|
2254
2469
|
}
|
|
2255
2470
|
|
|
2256
|
-
|
|
2257
2471
|
//////////////////////////////////////////////////////////////////////////////
|
|
2258
2472
|
//
|
|
2259
2473
|
// Alert
|
|
2260
2474
|
//
|
|
2261
2475
|
//////////////////////////////////////////////////////////////////////////////
|
|
2262
2476
|
|
|
2263
|
-
|
|
2264
2477
|
/**
|
|
2265
2478
|
* Represents a modal dialog such as {@code alert}, {@code confirm}, or
|
|
2266
2479
|
* {@code prompt}. Provides functions to retrieve the message displayed with
|
|
@@ -2275,10 +2488,10 @@ class Alert {
|
|
|
2275
2488
|
*/
|
|
2276
2489
|
constructor(driver, text) {
|
|
2277
2490
|
/** @private {!WebDriver} */
|
|
2278
|
-
this.driver_ = driver
|
|
2491
|
+
this.driver_ = driver
|
|
2279
2492
|
|
|
2280
2493
|
/** @private {!Promise<string>} */
|
|
2281
|
-
this.text_ = Promise.resolve(text)
|
|
2494
|
+
this.text_ = Promise.resolve(text)
|
|
2282
2495
|
}
|
|
2283
2496
|
|
|
2284
2497
|
/**
|
|
@@ -2289,7 +2502,7 @@ class Alert {
|
|
|
2289
2502
|
* resolved to the text displayed with this alert.
|
|
2290
2503
|
*/
|
|
2291
2504
|
getText() {
|
|
2292
|
-
return this.text_
|
|
2505
|
+
return this.text_
|
|
2293
2506
|
}
|
|
2294
2507
|
|
|
2295
2508
|
/**
|
|
@@ -2299,8 +2512,7 @@ class Alert {
|
|
|
2299
2512
|
* when this command has completed.
|
|
2300
2513
|
*/
|
|
2301
2514
|
accept() {
|
|
2302
|
-
return this.driver_.execute(
|
|
2303
|
-
new command.Command(command.Name.ACCEPT_ALERT));
|
|
2515
|
+
return this.driver_.execute(new command.Command(command.Name.ACCEPT_ALERT))
|
|
2304
2516
|
}
|
|
2305
2517
|
|
|
2306
2518
|
/**
|
|
@@ -2310,8 +2522,7 @@ class Alert {
|
|
|
2310
2522
|
* when this command has completed.
|
|
2311
2523
|
*/
|
|
2312
2524
|
dismiss() {
|
|
2313
|
-
return this.driver_.execute(
|
|
2314
|
-
new command.Command(command.Name.DISMISS_ALERT));
|
|
2525
|
+
return this.driver_.execute(new command.Command(command.Name.DISMISS_ALERT))
|
|
2315
2526
|
}
|
|
2316
2527
|
|
|
2317
2528
|
/**
|
|
@@ -2325,12 +2536,14 @@ class Alert {
|
|
|
2325
2536
|
*/
|
|
2326
2537
|
sendKeys(text) {
|
|
2327
2538
|
return this.driver_.execute(
|
|
2328
|
-
|
|
2329
|
-
|
|
2539
|
+
new command.Command(command.Name.SET_ALERT_TEXT).setParameter(
|
|
2540
|
+
'text',
|
|
2541
|
+
text
|
|
2542
|
+
)
|
|
2543
|
+
)
|
|
2330
2544
|
}
|
|
2331
2545
|
}
|
|
2332
2546
|
|
|
2333
|
-
|
|
2334
2547
|
/**
|
|
2335
2548
|
* AlertPromise is a promise that will be fulfilled with an Alert. This promise
|
|
2336
2549
|
* serves as a forward proxy on an Alert, allowing calls to be scheduled
|
|
@@ -2353,60 +2566,58 @@ class AlertPromise extends Alert {
|
|
|
2353
2566
|
* that will be fulfilled with the promised alert.
|
|
2354
2567
|
*/
|
|
2355
2568
|
constructor(driver, alert) {
|
|
2356
|
-
super(driver, 'unused')
|
|
2569
|
+
super(driver, 'unused')
|
|
2357
2570
|
|
|
2358
2571
|
/** @override */
|
|
2359
|
-
this.then = alert.then.bind(alert)
|
|
2572
|
+
this.then = alert.then.bind(alert)
|
|
2360
2573
|
|
|
2361
2574
|
/** @override */
|
|
2362
|
-
this.catch = alert.catch.bind(alert)
|
|
2575
|
+
this.catch = alert.catch.bind(alert)
|
|
2363
2576
|
|
|
2364
2577
|
/**
|
|
2365
2578
|
* Defer returning text until the promised alert has been resolved.
|
|
2366
2579
|
* @override
|
|
2367
2580
|
*/
|
|
2368
|
-
this.getText = function() {
|
|
2369
|
-
return alert.then(function(alert) {
|
|
2370
|
-
return alert.getText()
|
|
2371
|
-
})
|
|
2372
|
-
}
|
|
2581
|
+
this.getText = function () {
|
|
2582
|
+
return alert.then(function (alert) {
|
|
2583
|
+
return alert.getText()
|
|
2584
|
+
})
|
|
2585
|
+
}
|
|
2373
2586
|
|
|
2374
2587
|
/**
|
|
2375
2588
|
* Defers action until the alert has been located.
|
|
2376
2589
|
* @override
|
|
2377
2590
|
*/
|
|
2378
|
-
this.accept = function() {
|
|
2379
|
-
return alert.then(function(alert) {
|
|
2380
|
-
return alert.accept()
|
|
2381
|
-
})
|
|
2382
|
-
}
|
|
2591
|
+
this.accept = function () {
|
|
2592
|
+
return alert.then(function (alert) {
|
|
2593
|
+
return alert.accept()
|
|
2594
|
+
})
|
|
2595
|
+
}
|
|
2383
2596
|
|
|
2384
2597
|
/**
|
|
2385
2598
|
* Defers action until the alert has been located.
|
|
2386
2599
|
* @override
|
|
2387
2600
|
*/
|
|
2388
|
-
this.dismiss = function() {
|
|
2389
|
-
return alert.then(function(alert) {
|
|
2390
|
-
return alert.dismiss()
|
|
2391
|
-
})
|
|
2392
|
-
}
|
|
2601
|
+
this.dismiss = function () {
|
|
2602
|
+
return alert.then(function (alert) {
|
|
2603
|
+
return alert.dismiss()
|
|
2604
|
+
})
|
|
2605
|
+
}
|
|
2393
2606
|
|
|
2394
2607
|
/**
|
|
2395
2608
|
* Defers action until the alert has been located.
|
|
2396
2609
|
* @override
|
|
2397
2610
|
*/
|
|
2398
|
-
this.sendKeys = function(text) {
|
|
2399
|
-
return alert.then(function(alert) {
|
|
2400
|
-
return alert.sendKeys(text)
|
|
2401
|
-
})
|
|
2402
|
-
}
|
|
2611
|
+
this.sendKeys = function (text) {
|
|
2612
|
+
return alert.then(function (alert) {
|
|
2613
|
+
return alert.sendKeys(text)
|
|
2614
|
+
})
|
|
2615
|
+
}
|
|
2403
2616
|
}
|
|
2404
2617
|
}
|
|
2405
2618
|
|
|
2406
|
-
|
|
2407
2619
|
// PUBLIC API
|
|
2408
2620
|
|
|
2409
|
-
|
|
2410
2621
|
module.exports = {
|
|
2411
2622
|
Alert,
|
|
2412
2623
|
AlertPromise,
|
|
@@ -2420,5 +2631,5 @@ module.exports = {
|
|
|
2420
2631
|
WebElement,
|
|
2421
2632
|
WebElementCondition,
|
|
2422
2633
|
WebElementPromise,
|
|
2423
|
-
Window
|
|
2424
|
-
}
|
|
2634
|
+
Window,
|
|
2635
|
+
}
|