selenium-webdriver 4.0.0-alpha.7 → 4.0.0-beta.3
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 +56 -0
- package/LICENSE +202 -0
- package/NOTICE +2 -0
- package/README.md +2 -0
- package/chrome.js +69 -79
- package/chromium.js +231 -164
- package/{lib/atoms/make-atoms-module.js → devtools/CDPConnection.js} +15 -9
- package/edge.js +104 -146
- package/example/chrome_android.js +45 -0
- package/example/chrome_mobile_emulation.js +46 -0
- package/example/firefox_channels.js +84 -0
- package/example/google_search.js +50 -0
- package/example/google_search_test.js +70 -0
- package/example/headless.js +63 -0
- package/example/logging.js +64 -0
- package/firefox.js +199 -200
- package/http/index.js +128 -116
- package/http/util.js +56 -64
- package/ie.js +180 -104
- package/index.js +246 -199
- package/io/exec.js +35 -40
- package/io/index.js +146 -157
- package/io/zip.js +75 -66
- package/lib/atoms/find-elements.js +123 -0
- package/lib/atoms/get-attribute.js +75 -59
- package/lib/atoms/is-displayed.js +72 -72
- package/lib/atoms/mutation-listener.js +55 -0
- package/lib/by.js +192 -65
- package/lib/capabilities.js +76 -86
- package/lib/command.js +19 -35
- package/lib/error.js +134 -168
- package/lib/http.js +308 -232
- package/lib/input.js +192 -453
- package/lib/logging.js +126 -137
- package/lib/promise.js +53 -71
- package/lib/proxy.js +31 -41
- package/lib/session.js +12 -15
- package/lib/symbols.js +3 -4
- package/lib/until.js +162 -160
- package/lib/webdriver.js +1014 -549
- package/net/index.js +30 -36
- package/net/portprober.js +30 -143
- package/opera.js +406 -0
- package/package.json +15 -7
- package/proxy.js +2 -2
- package/remote/index.js +189 -187
- package/safari.js +40 -49
- package/testing/index.js +504 -0
- package/lib/README +0 -5
- package/lib/actions.js +0 -609
package/lib/webdriver.js
CHANGED
|
@@ -19,33 +19,37 @@
|
|
|
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 cdpTargets = ['page', 'browser']
|
|
33
|
+
const cdp = require('../devtools/CDPConnection')
|
|
34
|
+
const WebSocket = require('ws')
|
|
35
|
+
const http = require('../http/index')
|
|
36
|
+
const fs = require('fs')
|
|
37
|
+
const { Capabilities } = require('./capabilities')
|
|
38
|
+
const path = require('path')
|
|
34
39
|
|
|
35
40
|
// Capability names that are defined in the W3C spec.
|
|
36
41
|
const W3C_CAPABILITY_NAMES = new Set([
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
])
|
|
48
|
-
|
|
42
|
+
'acceptInsecureCerts',
|
|
43
|
+
'browserName',
|
|
44
|
+
'browserVersion',
|
|
45
|
+
'platformName',
|
|
46
|
+
'pageLoadStrategy',
|
|
47
|
+
'proxy',
|
|
48
|
+
'setWindowRect',
|
|
49
|
+
'timeouts',
|
|
50
|
+
'strictFileInteractability',
|
|
51
|
+
'unhandledPromptBehavior',
|
|
52
|
+
])
|
|
49
53
|
|
|
50
54
|
/**
|
|
51
55
|
* Defines a condition for use with WebDriver's {@linkplain WebDriver#wait wait
|
|
@@ -62,19 +66,18 @@ class Condition {
|
|
|
62
66
|
*/
|
|
63
67
|
constructor(message, fn) {
|
|
64
68
|
/** @private {string} */
|
|
65
|
-
this.description_ = 'Waiting ' + message
|
|
69
|
+
this.description_ = 'Waiting ' + message
|
|
66
70
|
|
|
67
71
|
/** @type {function(!WebDriver): OUT} */
|
|
68
|
-
this.fn = fn
|
|
72
|
+
this.fn = fn
|
|
69
73
|
}
|
|
70
74
|
|
|
71
75
|
/** @return {string} A description of this condition. */
|
|
72
76
|
description() {
|
|
73
|
-
return this.description_
|
|
77
|
+
return this.description_
|
|
74
78
|
}
|
|
75
79
|
}
|
|
76
80
|
|
|
77
|
-
|
|
78
81
|
/**
|
|
79
82
|
* Defines a condition that will result in a {@link WebElement}.
|
|
80
83
|
*
|
|
@@ -89,18 +92,16 @@ class WebElementCondition extends Condition {
|
|
|
89
92
|
* loop.
|
|
90
93
|
*/
|
|
91
94
|
constructor(message, fn) {
|
|
92
|
-
super(message, fn)
|
|
95
|
+
super(message, fn)
|
|
93
96
|
}
|
|
94
97
|
}
|
|
95
98
|
|
|
96
|
-
|
|
97
99
|
//////////////////////////////////////////////////////////////////////////////
|
|
98
100
|
//
|
|
99
101
|
// WebDriver
|
|
100
102
|
//
|
|
101
103
|
//////////////////////////////////////////////////////////////////////////////
|
|
102
104
|
|
|
103
|
-
|
|
104
105
|
/**
|
|
105
106
|
* Translates a command to its wire-protocol representation before passing it
|
|
106
107
|
* to the given `executor` for execution.
|
|
@@ -109,14 +110,12 @@ class WebElementCondition extends Condition {
|
|
|
109
110
|
* @return {!Promise} A promise that will resolve with the command response.
|
|
110
111
|
*/
|
|
111
112
|
function executeCommand(executor, command) {
|
|
112
|
-
return toWireValue(command.getParameters()).
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
});
|
|
113
|
+
return toWireValue(command.getParameters()).then(function (parameters) {
|
|
114
|
+
command.setParameters(parameters)
|
|
115
|
+
return executor.execute(command)
|
|
116
|
+
})
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
-
|
|
120
119
|
/**
|
|
121
120
|
* Converts an object to its JSON representation in the WebDriver wire protocol.
|
|
122
121
|
* When converting values of type object, the following steps will be taken:
|
|
@@ -136,64 +135,62 @@ function executeCommand(executor, command) {
|
|
|
136
135
|
* representation.
|
|
137
136
|
*/
|
|
138
137
|
async function toWireValue(obj) {
|
|
139
|
-
let value = await Promise.resolve(obj)
|
|
138
|
+
let value = await Promise.resolve(obj)
|
|
140
139
|
if (value === void 0 || value === null) {
|
|
141
|
-
return value
|
|
140
|
+
return value
|
|
142
141
|
}
|
|
143
142
|
|
|
144
|
-
if (
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
143
|
+
if (
|
|
144
|
+
typeof value === 'boolean' ||
|
|
145
|
+
typeof value === 'number' ||
|
|
146
|
+
typeof value === 'string'
|
|
147
|
+
) {
|
|
148
|
+
return value
|
|
148
149
|
}
|
|
149
150
|
|
|
150
151
|
if (Array.isArray(value)) {
|
|
151
|
-
return convertKeys(value)
|
|
152
|
+
return convertKeys(value)
|
|
152
153
|
}
|
|
153
154
|
|
|
154
155
|
if (typeof value === 'function') {
|
|
155
|
-
return '' + value
|
|
156
|
+
return '' + value
|
|
156
157
|
}
|
|
157
158
|
|
|
158
159
|
if (typeof value[Symbols.serialize] === 'function') {
|
|
159
|
-
return toWireValue(value[Symbols.serialize]())
|
|
160
|
+
return toWireValue(value[Symbols.serialize]())
|
|
160
161
|
} else if (typeof value.toJSON === 'function') {
|
|
161
|
-
return toWireValue(value.toJSON())
|
|
162
|
+
return toWireValue(value.toJSON())
|
|
162
163
|
}
|
|
163
|
-
return convertKeys(value)
|
|
164
|
+
return convertKeys(value)
|
|
164
165
|
}
|
|
165
166
|
|
|
166
|
-
|
|
167
167
|
async function convertKeys(obj) {
|
|
168
|
-
const isArray = Array.isArray(obj)
|
|
169
|
-
const numKeys = isArray ? obj.length : Object.keys(obj).length
|
|
170
|
-
const ret = isArray ? new Array(numKeys) : {}
|
|
168
|
+
const isArray = Array.isArray(obj)
|
|
169
|
+
const numKeys = isArray ? obj.length : Object.keys(obj).length
|
|
170
|
+
const ret = isArray ? new Array(numKeys) : {}
|
|
171
171
|
if (!numKeys) {
|
|
172
|
-
return ret
|
|
172
|
+
return ret
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
-
let numResolved = 0;
|
|
176
|
-
|
|
177
175
|
async function forEachKey(obj, fn) {
|
|
178
176
|
if (Array.isArray(obj)) {
|
|
179
177
|
for (let i = 0, n = obj.length; i < n; i++) {
|
|
180
|
-
await fn(obj[i], i)
|
|
178
|
+
await fn(obj[i], i)
|
|
181
179
|
}
|
|
182
180
|
} else {
|
|
183
181
|
for (let key in obj) {
|
|
184
|
-
await fn(obj[key], key)
|
|
182
|
+
await fn(obj[key], key)
|
|
185
183
|
}
|
|
186
184
|
}
|
|
187
185
|
}
|
|
188
186
|
|
|
189
|
-
await forEachKey(obj, async function(value, key) {
|
|
190
|
-
ret[key] = await toWireValue(value)
|
|
191
|
-
})
|
|
187
|
+
await forEachKey(obj, async function (value, key) {
|
|
188
|
+
ret[key] = await toWireValue(value)
|
|
189
|
+
})
|
|
192
190
|
|
|
193
|
-
return ret
|
|
191
|
+
return ret
|
|
194
192
|
}
|
|
195
193
|
|
|
196
|
-
|
|
197
194
|
/**
|
|
198
195
|
* Converts a value from its JSON representation according to the WebDriver wire
|
|
199
196
|
* protocol. Any JSON object that defines a WebElement ID will be decoded to a
|
|
@@ -206,22 +203,32 @@ async function convertKeys(obj) {
|
|
|
206
203
|
*/
|
|
207
204
|
function fromWireValue(driver, value) {
|
|
208
205
|
if (Array.isArray(value)) {
|
|
209
|
-
value = value.map(v => fromWireValue(driver, v))
|
|
206
|
+
value = value.map((v) => fromWireValue(driver, v))
|
|
210
207
|
} else if (WebElement.isId(value)) {
|
|
211
|
-
let id = WebElement.extractId(value)
|
|
212
|
-
value = new WebElement(driver, id)
|
|
208
|
+
let id = WebElement.extractId(value)
|
|
209
|
+
value = new WebElement(driver, id)
|
|
213
210
|
} else if (value && typeof value === 'object') {
|
|
214
|
-
let result = {}
|
|
211
|
+
let result = {}
|
|
215
212
|
for (let key in value) {
|
|
216
|
-
if (
|
|
217
|
-
result[key] = fromWireValue(driver, value[key])
|
|
213
|
+
if (Object.prototype.hasOwnProperty.call(value, key)) {
|
|
214
|
+
result[key] = fromWireValue(driver, value[key])
|
|
218
215
|
}
|
|
219
216
|
}
|
|
220
|
-
value = result
|
|
217
|
+
value = result
|
|
221
218
|
}
|
|
222
|
-
return value
|
|
219
|
+
return value
|
|
223
220
|
}
|
|
224
221
|
|
|
222
|
+
/**
|
|
223
|
+
* Resolves a wait message from either a function or a string.
|
|
224
|
+
* @param {(string|Function)=} message An optional message to use if the wait times out.
|
|
225
|
+
* @return {string} The resolved message
|
|
226
|
+
*/
|
|
227
|
+
function resolveWaitMessage(message) {
|
|
228
|
+
return message
|
|
229
|
+
? `${typeof message === 'function' ? message() : message}\n`
|
|
230
|
+
: ''
|
|
231
|
+
}
|
|
225
232
|
|
|
226
233
|
/**
|
|
227
234
|
* Structural interface for a WebDriver client.
|
|
@@ -229,7 +236,6 @@ function fromWireValue(driver, value) {
|
|
|
229
236
|
* @record
|
|
230
237
|
*/
|
|
231
238
|
class IWebDriver {
|
|
232
|
-
|
|
233
239
|
/**
|
|
234
240
|
* Executes the provided {@link command.Command} using this driver's
|
|
235
241
|
* {@link command.Executor}.
|
|
@@ -239,30 +245,30 @@ class IWebDriver {
|
|
|
239
245
|
* result.
|
|
240
246
|
* @template T
|
|
241
247
|
*/
|
|
242
|
-
execute(command) {}
|
|
248
|
+
execute(command) { } // eslint-disable-line
|
|
243
249
|
|
|
244
250
|
/**
|
|
245
251
|
* Sets the {@linkplain input.FileDetector file detector} that should be
|
|
246
252
|
* used with this instance.
|
|
247
253
|
* @param {input.FileDetector} detector The detector to use or `null`.
|
|
248
254
|
*/
|
|
249
|
-
setFileDetector(detector) {}
|
|
255
|
+
setFileDetector(detector) { } // eslint-disable-line
|
|
250
256
|
|
|
251
257
|
/**
|
|
252
258
|
* @return {!command.Executor} The command executor used by this instance.
|
|
253
259
|
*/
|
|
254
|
-
getExecutor() {}
|
|
260
|
+
getExecutor() { }
|
|
255
261
|
|
|
256
262
|
/**
|
|
257
263
|
* @return {!Promise<!Session>} A promise for this client's session.
|
|
258
264
|
*/
|
|
259
|
-
getSession() {}
|
|
265
|
+
getSession() { }
|
|
260
266
|
|
|
261
267
|
/**
|
|
262
268
|
* @return {!Promise<!Capabilities>} A promise that will resolve with
|
|
263
269
|
* the this instance's capabilities.
|
|
264
270
|
*/
|
|
265
|
-
getCapabilities() {}
|
|
271
|
+
getCapabilities() { }
|
|
266
272
|
|
|
267
273
|
/**
|
|
268
274
|
* Terminates the browser session. After calling quit, this instance will be
|
|
@@ -272,7 +278,7 @@ class IWebDriver {
|
|
|
272
278
|
* @return {!Promise<void>} A promise that will be resolved when the
|
|
273
279
|
* command has completed.
|
|
274
280
|
*/
|
|
275
|
-
quit() {}
|
|
281
|
+
quit() { }
|
|
276
282
|
|
|
277
283
|
/**
|
|
278
284
|
* Creates a new action sequence using this driver. The sequence will not be
|
|
@@ -285,7 +291,7 @@ class IWebDriver {
|
|
|
285
291
|
* for details).
|
|
286
292
|
* @return {!input.Actions} A new action sequence for this instance.
|
|
287
293
|
*/
|
|
288
|
-
actions(options) {}
|
|
294
|
+
actions(options) { } // eslint-disable-line
|
|
289
295
|
|
|
290
296
|
/**
|
|
291
297
|
* Executes a snippet of JavaScript in the context of the currently selected
|
|
@@ -323,7 +329,7 @@ class IWebDriver {
|
|
|
323
329
|
* scripts return value.
|
|
324
330
|
* @template T
|
|
325
331
|
*/
|
|
326
|
-
executeScript(script, ...args) {}
|
|
332
|
+
executeScript(script, ...args) { } // eslint-disable-line
|
|
327
333
|
|
|
328
334
|
/**
|
|
329
335
|
* Executes a snippet of asynchronous JavaScript in the context of the
|
|
@@ -400,7 +406,7 @@ class IWebDriver {
|
|
|
400
406
|
* value.
|
|
401
407
|
* @template T
|
|
402
408
|
*/
|
|
403
|
-
executeAsyncScript(script, ...args) {}
|
|
409
|
+
executeAsyncScript(script, ...args) { } // eslint-disable-line
|
|
404
410
|
|
|
405
411
|
/**
|
|
406
412
|
* Waits for a condition to evaluate to a "truthy" value. The condition may be
|
|
@@ -435,7 +441,7 @@ class IWebDriver {
|
|
|
435
441
|
* evaluate as a condition.
|
|
436
442
|
* @param {number=} timeout The duration in milliseconds, how long to wait
|
|
437
443
|
* for the condition to be true.
|
|
438
|
-
* @param {string=} message An optional message to use if the wait times out.
|
|
444
|
+
* @param {(string|Function)=} message An optional message to use if the wait times out.
|
|
439
445
|
* @param {number=} pollTimeout The duration in milliseconds, how long to
|
|
440
446
|
* wait between polling the condition.
|
|
441
447
|
* @return {!(IThenable<T>|WebElementPromise)} A promise that will be
|
|
@@ -446,7 +452,12 @@ class IWebDriver {
|
|
|
446
452
|
* @throws {TypeError} if the provided `condition` is not a valid type.
|
|
447
453
|
* @template T
|
|
448
454
|
*/
|
|
449
|
-
wait(
|
|
455
|
+
wait(
|
|
456
|
+
condition, // eslint-disable-line
|
|
457
|
+
timeout = undefined, // eslint-disable-line
|
|
458
|
+
message = undefined, // eslint-disable-line
|
|
459
|
+
pollTimeout = undefined // eslint-disable-line
|
|
460
|
+
) { }
|
|
450
461
|
|
|
451
462
|
/**
|
|
452
463
|
* Makes the driver sleep for the given amount of time.
|
|
@@ -455,7 +466,7 @@ class IWebDriver {
|
|
|
455
466
|
* @return {!Promise<void>} A promise that will be resolved when the sleep has
|
|
456
467
|
* finished.
|
|
457
468
|
*/
|
|
458
|
-
sleep(ms) {}
|
|
469
|
+
sleep(ms) { } // eslint-disable-line
|
|
459
470
|
|
|
460
471
|
/**
|
|
461
472
|
* Retrieves the current window handle.
|
|
@@ -463,7 +474,7 @@ class IWebDriver {
|
|
|
463
474
|
* @return {!Promise<string>} A promise that will be resolved with the current
|
|
464
475
|
* window handle.
|
|
465
476
|
*/
|
|
466
|
-
getWindowHandle() {}
|
|
477
|
+
getWindowHandle() { }
|
|
467
478
|
|
|
468
479
|
/**
|
|
469
480
|
* Retrieves a list of all available window handles.
|
|
@@ -471,17 +482,17 @@ class IWebDriver {
|
|
|
471
482
|
* @return {!Promise<!Array<string>>} A promise that will be resolved with an
|
|
472
483
|
* array of window handles.
|
|
473
484
|
*/
|
|
474
|
-
getAllWindowHandles() {}
|
|
485
|
+
getAllWindowHandles() { }
|
|
475
486
|
|
|
476
487
|
/**
|
|
477
|
-
* Retrieves the current page's source. The returned
|
|
488
|
+
* Retrieves the current page's source. The returned source is a representation
|
|
478
489
|
* of the underlying DOM: do not expect it to be formatted or escaped in the
|
|
479
490
|
* same way as the raw response sent from the web server.
|
|
480
491
|
*
|
|
481
492
|
* @return {!Promise<string>} A promise that will be resolved with the current
|
|
482
493
|
* page source.
|
|
483
494
|
*/
|
|
484
|
-
getPageSource() {}
|
|
495
|
+
getPageSource() { }
|
|
485
496
|
|
|
486
497
|
/**
|
|
487
498
|
* Closes the current window.
|
|
@@ -489,7 +500,7 @@ class IWebDriver {
|
|
|
489
500
|
* @return {!Promise<void>} A promise that will be resolved when this command
|
|
490
501
|
* has completed.
|
|
491
502
|
*/
|
|
492
|
-
close() {}
|
|
503
|
+
close() { }
|
|
493
504
|
|
|
494
505
|
/**
|
|
495
506
|
* Navigates to the given URL.
|
|
@@ -498,7 +509,7 @@ class IWebDriver {
|
|
|
498
509
|
* @return {!Promise<void>} A promise that will be resolved when the document
|
|
499
510
|
* has finished loading.
|
|
500
511
|
*/
|
|
501
|
-
get(url) {}
|
|
512
|
+
get(url) { } // eslint-disable-line
|
|
502
513
|
|
|
503
514
|
/**
|
|
504
515
|
* Retrieves the URL for the current page.
|
|
@@ -506,7 +517,7 @@ class IWebDriver {
|
|
|
506
517
|
* @return {!Promise<string>} A promise that will be resolved with the
|
|
507
518
|
* current URL.
|
|
508
519
|
*/
|
|
509
|
-
getCurrentUrl() {}
|
|
520
|
+
getCurrentUrl() { }
|
|
510
521
|
|
|
511
522
|
/**
|
|
512
523
|
* Retrieves the current page title.
|
|
@@ -514,11 +525,11 @@ class IWebDriver {
|
|
|
514
525
|
* @return {!Promise<string>} A promise that will be resolved with the current
|
|
515
526
|
* page's title.
|
|
516
527
|
*/
|
|
517
|
-
getTitle() {}
|
|
528
|
+
getTitle() { }
|
|
518
529
|
|
|
519
530
|
/**
|
|
520
531
|
* Locates an element on the page. If the element cannot be found, a
|
|
521
|
-
* {@link error.
|
|
532
|
+
* {@link error.NoSuchElementError} will be returned by the driver.
|
|
522
533
|
*
|
|
523
534
|
* This function should not be used to test whether an element is present on
|
|
524
535
|
* the page. Rather, you should use {@link #findElements}:
|
|
@@ -554,7 +565,7 @@ class IWebDriver {
|
|
|
554
565
|
* commands against the located element. If the element is not found, the
|
|
555
566
|
* element will be invalidated and all scheduled commands aborted.
|
|
556
567
|
*/
|
|
557
|
-
findElement(locator) {}
|
|
568
|
+
findElement(locator) { } // eslint-disable-line
|
|
558
569
|
|
|
559
570
|
/**
|
|
560
571
|
* Search for multiple elements on the page. Refer to the documentation on
|
|
@@ -564,7 +575,7 @@ class IWebDriver {
|
|
|
564
575
|
* @return {!Promise<!Array<!WebElement>>} A promise that will resolve to an
|
|
565
576
|
* array of WebElements.
|
|
566
577
|
*/
|
|
567
|
-
findElements(locator) {}
|
|
578
|
+
findElements(locator) { } // eslint-disable-line
|
|
568
579
|
|
|
569
580
|
/**
|
|
570
581
|
* Takes a screenshot of the current page. The driver makes a best effort to
|
|
@@ -578,25 +589,43 @@ class IWebDriver {
|
|
|
578
589
|
* @return {!Promise<string>} A promise that will be resolved to the
|
|
579
590
|
* screenshot as a base-64 encoded PNG.
|
|
580
591
|
*/
|
|
581
|
-
takeScreenshot() {}
|
|
592
|
+
takeScreenshot() { }
|
|
582
593
|
|
|
583
594
|
/**
|
|
584
595
|
* @return {!Options} The options interface for this instance.
|
|
585
596
|
*/
|
|
586
|
-
manage() {}
|
|
597
|
+
manage() { }
|
|
587
598
|
|
|
588
599
|
/**
|
|
589
600
|
* @return {!Navigation} The navigation interface for this instance.
|
|
590
601
|
*/
|
|
591
|
-
navigate() {}
|
|
602
|
+
navigate() { }
|
|
592
603
|
|
|
593
604
|
/**
|
|
594
605
|
* @return {!TargetLocator} The target locator interface for this
|
|
595
606
|
* instance.
|
|
596
607
|
*/
|
|
597
|
-
switchTo() {}
|
|
598
|
-
}
|
|
608
|
+
switchTo() { }
|
|
599
609
|
|
|
610
|
+
/**
|
|
611
|
+
*
|
|
612
|
+
* Takes a PDF of the current page. The driver makes a best effort to
|
|
613
|
+
* return a PDF based on the provided parameters.
|
|
614
|
+
*
|
|
615
|
+
* @param {{orientation: (string|undefined),
|
|
616
|
+
* scale: (number|undefined),
|
|
617
|
+
* background: (boolean|undefined)
|
|
618
|
+
* width: (number|undefined)
|
|
619
|
+
* height: (number|undefined)
|
|
620
|
+
* top: (number|undefined)
|
|
621
|
+
* bottom: (number|undefined)
|
|
622
|
+
* left: (number|undefined)
|
|
623
|
+
* right: (number|undefined)
|
|
624
|
+
* shrinkToFit: (boolean|undefined)
|
|
625
|
+
* pageRanges: (<Array>|undefined)}} options.
|
|
626
|
+
*/
|
|
627
|
+
printPage(options) { } // eslint-disable-line
|
|
628
|
+
}
|
|
600
629
|
|
|
601
630
|
/**
|
|
602
631
|
* @param {!Capabilities} capabilities A capabilities object.
|
|
@@ -604,23 +633,23 @@ class IWebDriver {
|
|
|
604
633
|
* capability names that are not valid W3C names.
|
|
605
634
|
*/
|
|
606
635
|
function filterNonW3CCaps(capabilities) {
|
|
607
|
-
let newCaps = new Capabilities(capabilities)
|
|
636
|
+
let newCaps = new Capabilities(capabilities)
|
|
608
637
|
for (let k of newCaps.keys()) {
|
|
609
638
|
// Any key containing a colon is a vendor-prefixed capability.
|
|
610
639
|
if (!(W3C_CAPABILITY_NAMES.has(k) || k.indexOf(':') >= 0)) {
|
|
611
|
-
newCaps.delete(k)
|
|
640
|
+
newCaps.delete(k)
|
|
612
641
|
}
|
|
613
642
|
}
|
|
614
|
-
return newCaps
|
|
643
|
+
return newCaps
|
|
615
644
|
}
|
|
616
645
|
|
|
617
|
-
|
|
618
646
|
/**
|
|
619
647
|
* Each WebDriver instance provides automated control over a browser session.
|
|
620
648
|
*
|
|
621
649
|
* @implements {IWebDriver}
|
|
622
650
|
*/
|
|
623
651
|
class WebDriver {
|
|
652
|
+
|
|
624
653
|
/**
|
|
625
654
|
* @param {!(./session.Session|IThenable<!./session.Session>)} session Either
|
|
626
655
|
* a known session or a promise that will be resolved to a session.
|
|
@@ -631,21 +660,21 @@ class WebDriver {
|
|
|
631
660
|
*/
|
|
632
661
|
constructor(session, executor, onQuit = undefined) {
|
|
633
662
|
/** @private {!Promise<!Session>} */
|
|
634
|
-
this.session_ = Promise.resolve(session)
|
|
663
|
+
this.session_ = Promise.resolve(session)
|
|
635
664
|
|
|
636
665
|
// If session is a rejected promise, add a no-op rejection handler.
|
|
637
666
|
// This effectively hides setup errors until users attempt to interact
|
|
638
667
|
// with the session.
|
|
639
|
-
this.session_.catch(function() {})
|
|
668
|
+
this.session_.catch(function () { })
|
|
640
669
|
|
|
641
670
|
/** @private {!command.Executor} */
|
|
642
|
-
this.executor_ = executor
|
|
671
|
+
this.executor_ = executor
|
|
643
672
|
|
|
644
673
|
/** @private {input.FileDetector} */
|
|
645
|
-
this.fileDetector_ = null
|
|
674
|
+
this.fileDetector_ = null
|
|
646
675
|
|
|
647
676
|
/** @private @const {(function(this: void): ?|undefined)} */
|
|
648
|
-
this.onQuit_ = onQuit
|
|
677
|
+
this.onQuit_ = onQuit
|
|
649
678
|
}
|
|
650
679
|
|
|
651
680
|
/**
|
|
@@ -674,251 +703,285 @@ class WebDriver {
|
|
|
674
703
|
* @return {!WebDriver} The driver for the newly created session.
|
|
675
704
|
*/
|
|
676
705
|
static createSession(executor, capabilities, onQuit = undefined) {
|
|
677
|
-
let cmd = new command.Command(command.Name.NEW_SESSION)
|
|
706
|
+
let cmd = new command.Command(command.Name.NEW_SESSION)
|
|
678
707
|
|
|
679
708
|
// For OSS remote ends.
|
|
680
|
-
cmd.setParameter('desiredCapabilities', capabilities)
|
|
709
|
+
cmd.setParameter('desiredCapabilities', capabilities)
|
|
681
710
|
// For W3C remote ends.
|
|
682
711
|
cmd.setParameter('capabilities', {
|
|
683
712
|
alwaysMatch: filterNonW3CCaps(capabilities),
|
|
684
|
-
})
|
|
713
|
+
})
|
|
685
714
|
|
|
686
|
-
let session = executeCommand(executor, cmd)
|
|
715
|
+
let session = executeCommand(executor, cmd)
|
|
687
716
|
if (typeof onQuit === 'function') {
|
|
688
|
-
session = session.catch(err => {
|
|
689
|
-
return Promise.resolve(onQuit.call(void 0)).then(_ => {
|
|
690
|
-
|
|
717
|
+
session = session.catch((err) => {
|
|
718
|
+
return Promise.resolve(onQuit.call(void 0)).then((_) => {
|
|
719
|
+
throw err
|
|
720
|
+
})
|
|
721
|
+
})
|
|
691
722
|
}
|
|
692
|
-
return new this(session, executor, onQuit)
|
|
723
|
+
return new this(session, executor, onQuit)
|
|
693
724
|
}
|
|
694
725
|
|
|
695
726
|
/** @override */
|
|
696
727
|
async execute(command) {
|
|
697
|
-
command.setParameter('sessionId', this.session_)
|
|
698
|
-
let parameters = await toWireValue(command.getParameters())
|
|
699
|
-
command.setParameters(parameters)
|
|
700
|
-
let value = await this.executor_.execute(command)
|
|
701
|
-
return fromWireValue(this, value)
|
|
728
|
+
command.setParameter('sessionId', this.session_)
|
|
729
|
+
let parameters = await toWireValue(command.getParameters())
|
|
730
|
+
command.setParameters(parameters)
|
|
731
|
+
let value = await this.executor_.execute(command)
|
|
732
|
+
return fromWireValue(this, value)
|
|
702
733
|
}
|
|
703
734
|
|
|
704
735
|
/** @override */
|
|
705
736
|
setFileDetector(detector) {
|
|
706
|
-
this.fileDetector_ = detector
|
|
737
|
+
this.fileDetector_ = detector
|
|
707
738
|
}
|
|
708
739
|
|
|
709
740
|
/** @override */
|
|
710
741
|
getExecutor() {
|
|
711
|
-
return this.executor_
|
|
742
|
+
return this.executor_
|
|
712
743
|
}
|
|
713
744
|
|
|
714
745
|
/** @override */
|
|
715
746
|
getSession() {
|
|
716
|
-
return this.session_
|
|
747
|
+
return this.session_
|
|
717
748
|
}
|
|
718
749
|
|
|
719
750
|
/** @override */
|
|
720
751
|
getCapabilities() {
|
|
721
|
-
return this.session_.then(s => s.getCapabilities())
|
|
752
|
+
return this.session_.then((s) => s.getCapabilities())
|
|
722
753
|
}
|
|
723
754
|
|
|
724
755
|
/** @override */
|
|
725
756
|
quit() {
|
|
726
|
-
let result = this.execute(new command.Command(command.Name.QUIT))
|
|
757
|
+
let result = this.execute(new command.Command(command.Name.QUIT))
|
|
727
758
|
// Delete our session ID when the quit command finishes; this will allow us
|
|
728
759
|
// to throw an error when attempting to use a driver post-quit.
|
|
729
760
|
return promise.finally(result, () => {
|
|
730
|
-
this.session_ = Promise.reject(
|
|
731
|
-
|
|
732
|
-
|
|
761
|
+
this.session_ = Promise.reject(
|
|
762
|
+
new error.NoSuchSessionError(
|
|
763
|
+
'This driver instance does not have a valid session ID ' +
|
|
764
|
+
'(did you call WebDriver.quit()?) and may no longer be used.'
|
|
765
|
+
)
|
|
766
|
+
)
|
|
733
767
|
|
|
734
768
|
// Only want the session rejection to bubble if accessed.
|
|
735
|
-
this.session_.catch(function() {})
|
|
769
|
+
this.session_.catch(function () { })
|
|
736
770
|
|
|
737
771
|
if (this.onQuit_) {
|
|
738
|
-
return this.onQuit_.call(void 0)
|
|
772
|
+
return this.onQuit_.call(void 0)
|
|
739
773
|
}
|
|
740
|
-
})
|
|
774
|
+
})
|
|
741
775
|
}
|
|
742
776
|
|
|
743
777
|
/** @override */
|
|
744
778
|
actions(options) {
|
|
745
|
-
return new input.Actions(this, options || undefined)
|
|
779
|
+
return new input.Actions(this, options || undefined)
|
|
746
780
|
}
|
|
747
781
|
|
|
748
782
|
/** @override */
|
|
749
783
|
executeScript(script, ...args) {
|
|
750
784
|
if (typeof script === 'function') {
|
|
751
|
-
script = 'return (' + script + ').apply(null, arguments);'
|
|
785
|
+
script = 'return (' + script + ').apply(null, arguments);'
|
|
752
786
|
}
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
787
|
+
return this.execute(
|
|
788
|
+
new command.Command(command.Name.EXECUTE_SCRIPT)
|
|
789
|
+
.setParameter('script', script)
|
|
790
|
+
.setParameter('args', args)
|
|
791
|
+
)
|
|
757
792
|
}
|
|
758
793
|
|
|
759
794
|
/** @override */
|
|
760
795
|
executeAsyncScript(script, ...args) {
|
|
761
796
|
if (typeof script === 'function') {
|
|
762
|
-
script = 'return (' + script + ').apply(null, arguments);'
|
|
797
|
+
script = 'return (' + script + ').apply(null, arguments);'
|
|
763
798
|
}
|
|
764
799
|
return this.execute(
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
800
|
+
new command.Command(command.Name.EXECUTE_ASYNC_SCRIPT)
|
|
801
|
+
.setParameter('script', script)
|
|
802
|
+
.setParameter('args', args)
|
|
803
|
+
)
|
|
768
804
|
}
|
|
769
805
|
|
|
770
806
|
/** @override */
|
|
771
807
|
wait(condition, timeout = 0, message = undefined, pollTimeout = 200) {
|
|
772
808
|
if (typeof timeout !== 'number' || timeout < 0) {
|
|
773
|
-
throw TypeError('timeout must be a number >= 0: ' + timeout)
|
|
809
|
+
throw TypeError('timeout must be a number >= 0: ' + timeout)
|
|
774
810
|
}
|
|
775
811
|
|
|
776
812
|
if (typeof pollTimeout !== 'number' || pollTimeout < 0) {
|
|
777
|
-
throw TypeError('pollTimeout must be a number >= 0: ' + pollTimeout)
|
|
813
|
+
throw TypeError('pollTimeout must be a number >= 0: ' + pollTimeout)
|
|
778
814
|
}
|
|
779
815
|
|
|
780
816
|
if (promise.isPromise(condition)) {
|
|
781
817
|
return new Promise((resolve, reject) => {
|
|
782
818
|
if (!timeout) {
|
|
783
|
-
resolve(condition)
|
|
784
|
-
return
|
|
819
|
+
resolve(condition)
|
|
820
|
+
return
|
|
785
821
|
}
|
|
786
822
|
|
|
787
|
-
let start = Date.now()
|
|
788
|
-
let timer = setTimeout(function() {
|
|
789
|
-
timer = null
|
|
790
|
-
|
|
823
|
+
let start = Date.now()
|
|
824
|
+
let timer = setTimeout(function () {
|
|
825
|
+
timer = null
|
|
826
|
+
try {
|
|
827
|
+
let timeoutMessage = resolveWaitMessage(message)
|
|
828
|
+
reject(
|
|
791
829
|
new error.TimeoutError(
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
830
|
+
`${timeoutMessage}Timed out waiting for promise to resolve after ${Date.now() - start
|
|
831
|
+
}ms`
|
|
832
|
+
)
|
|
833
|
+
)
|
|
834
|
+
} catch (ex) {
|
|
835
|
+
reject(
|
|
836
|
+
new error.TimeoutError(
|
|
837
|
+
`${ex.message
|
|
838
|
+
}\nTimed out waiting for promise to resolve after ${Date.now() - start
|
|
839
|
+
}ms`
|
|
840
|
+
)
|
|
841
|
+
)
|
|
842
|
+
}
|
|
843
|
+
}, timeout)
|
|
844
|
+
const clearTimer = () => timer && clearTimeout(timer)
|
|
845
|
+
|
|
846
|
+
/** @type {!IThenable} */ condition.then(
|
|
847
|
+
function (value) {
|
|
848
|
+
clearTimer()
|
|
849
|
+
resolve(value)
|
|
850
|
+
},
|
|
851
|
+
function (error) {
|
|
852
|
+
clearTimer()
|
|
853
|
+
reject(error)
|
|
854
|
+
}
|
|
855
|
+
)
|
|
856
|
+
})
|
|
808
857
|
}
|
|
809
858
|
|
|
810
|
-
let fn = /** @type {!Function} */(condition)
|
|
859
|
+
let fn = /** @type {!Function} */ (condition)
|
|
811
860
|
if (condition instanceof Condition) {
|
|
812
|
-
message = message || condition.description()
|
|
813
|
-
fn = condition.fn
|
|
861
|
+
message = message || condition.description()
|
|
862
|
+
fn = condition.fn
|
|
814
863
|
}
|
|
815
864
|
|
|
816
865
|
if (typeof fn !== 'function') {
|
|
817
866
|
throw TypeError(
|
|
818
|
-
|
|
819
|
-
|
|
867
|
+
'Wait condition must be a promise-like object, function, or a ' +
|
|
868
|
+
'Condition object'
|
|
869
|
+
)
|
|
820
870
|
}
|
|
821
871
|
|
|
822
|
-
const driver = this
|
|
872
|
+
const driver = this
|
|
823
873
|
function evaluateCondition() {
|
|
824
874
|
return new Promise((resolve, reject) => {
|
|
825
875
|
try {
|
|
826
|
-
resolve(fn(driver))
|
|
876
|
+
resolve(fn(driver))
|
|
827
877
|
} catch (ex) {
|
|
828
|
-
reject(ex)
|
|
878
|
+
reject(ex)
|
|
829
879
|
}
|
|
830
|
-
})
|
|
880
|
+
})
|
|
831
881
|
}
|
|
832
882
|
|
|
833
883
|
let result = new Promise((resolve, reject) => {
|
|
834
|
-
const startTime = Date.now()
|
|
884
|
+
const startTime = Date.now()
|
|
835
885
|
const pollCondition = async () => {
|
|
836
|
-
evaluateCondition().then(function(value) {
|
|
837
|
-
const elapsed = Date.now() - startTime
|
|
838
|
-
if (
|
|
839
|
-
resolve(value)
|
|
886
|
+
evaluateCondition().then(function (value) {
|
|
887
|
+
const elapsed = Date.now() - startTime
|
|
888
|
+
if (value) {
|
|
889
|
+
resolve(value)
|
|
840
890
|
} else if (timeout && elapsed >= timeout) {
|
|
841
|
-
|
|
891
|
+
try {
|
|
892
|
+
let timeoutMessage = resolveWaitMessage(message)
|
|
893
|
+
reject(
|
|
894
|
+
new error.TimeoutError(
|
|
895
|
+
`${timeoutMessage}Wait timed out after ${elapsed}ms`
|
|
896
|
+
)
|
|
897
|
+
)
|
|
898
|
+
} catch (ex) {
|
|
899
|
+
reject(
|
|
842
900
|
new error.TimeoutError(
|
|
843
|
-
|
|
844
|
-
|
|
901
|
+
`${ex.message}\nWait timed out after ${elapsed}ms`
|
|
902
|
+
)
|
|
903
|
+
)
|
|
904
|
+
}
|
|
845
905
|
} else {
|
|
846
|
-
setTimeout(pollCondition, pollTimeout)
|
|
906
|
+
setTimeout(pollCondition, pollTimeout)
|
|
847
907
|
}
|
|
848
|
-
}, reject)
|
|
849
|
-
}
|
|
850
|
-
pollCondition()
|
|
851
|
-
})
|
|
908
|
+
}, reject)
|
|
909
|
+
}
|
|
910
|
+
pollCondition()
|
|
911
|
+
})
|
|
852
912
|
|
|
853
913
|
if (condition instanceof WebElementCondition) {
|
|
854
|
-
result = new WebElementPromise(
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
914
|
+
result = new WebElementPromise(
|
|
915
|
+
this,
|
|
916
|
+
result.then(function (value) {
|
|
917
|
+
if (!(value instanceof WebElement)) {
|
|
918
|
+
throw TypeError(
|
|
919
|
+
'WebElementCondition did not resolve to a WebElement: ' +
|
|
920
|
+
Object.prototype.toString.call(value)
|
|
921
|
+
)
|
|
922
|
+
}
|
|
923
|
+
return value
|
|
924
|
+
})
|
|
925
|
+
)
|
|
862
926
|
}
|
|
863
|
-
return result
|
|
927
|
+
return result
|
|
864
928
|
}
|
|
865
929
|
|
|
866
930
|
/** @override */
|
|
867
931
|
sleep(ms) {
|
|
868
|
-
return new Promise(resolve => setTimeout(
|
|
932
|
+
return new Promise((resolve) => setTimeout(resolve, ms))
|
|
869
933
|
}
|
|
870
934
|
|
|
871
935
|
/** @override */
|
|
872
936
|
getWindowHandle() {
|
|
873
937
|
return this.execute(
|
|
874
|
-
|
|
938
|
+
new command.Command(command.Name.GET_CURRENT_WINDOW_HANDLE)
|
|
939
|
+
)
|
|
875
940
|
}
|
|
876
941
|
|
|
877
942
|
/** @override */
|
|
878
943
|
getAllWindowHandles() {
|
|
879
|
-
return this.execute(
|
|
880
|
-
new command.Command(command.Name.GET_WINDOW_HANDLES));
|
|
944
|
+
return this.execute(new command.Command(command.Name.GET_WINDOW_HANDLES))
|
|
881
945
|
}
|
|
882
946
|
|
|
883
947
|
/** @override */
|
|
884
948
|
getPageSource() {
|
|
885
|
-
return this.execute(
|
|
886
|
-
new command.Command(command.Name.GET_PAGE_SOURCE));
|
|
949
|
+
return this.execute(new command.Command(command.Name.GET_PAGE_SOURCE))
|
|
887
950
|
}
|
|
888
951
|
|
|
889
952
|
/** @override */
|
|
890
953
|
close() {
|
|
891
|
-
return this.execute(new command.Command(command.Name.CLOSE))
|
|
954
|
+
return this.execute(new command.Command(command.Name.CLOSE))
|
|
892
955
|
}
|
|
893
956
|
|
|
894
957
|
/** @override */
|
|
895
958
|
get(url) {
|
|
896
|
-
return this.navigate().to(url)
|
|
959
|
+
return this.navigate().to(url)
|
|
897
960
|
}
|
|
898
961
|
|
|
899
962
|
/** @override */
|
|
900
963
|
getCurrentUrl() {
|
|
901
|
-
return this.execute(new command.Command(command.Name.GET_CURRENT_URL))
|
|
964
|
+
return this.execute(new command.Command(command.Name.GET_CURRENT_URL))
|
|
902
965
|
}
|
|
903
966
|
|
|
904
967
|
/** @override */
|
|
905
968
|
getTitle() {
|
|
906
|
-
return this.execute(new command.Command(command.Name.GET_TITLE))
|
|
969
|
+
return this.execute(new command.Command(command.Name.GET_TITLE))
|
|
907
970
|
}
|
|
908
971
|
|
|
909
972
|
/** @override */
|
|
910
973
|
findElement(locator) {
|
|
911
|
-
let id
|
|
912
|
-
locator = by.checkedLocator(locator)
|
|
974
|
+
let id
|
|
975
|
+
locator = by.checkedLocator(locator)
|
|
913
976
|
if (typeof locator === 'function') {
|
|
914
|
-
id = this.findElementInternal_(locator, this)
|
|
977
|
+
id = this.findElementInternal_(locator, this)
|
|
915
978
|
} else {
|
|
916
|
-
let cmd = new command.Command(command.Name.FIND_ELEMENT)
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
id = this.execute(cmd)
|
|
979
|
+
let cmd = new command.Command(command.Name.FIND_ELEMENT)
|
|
980
|
+
.setParameter('using', locator.using)
|
|
981
|
+
.setParameter('value', locator.value)
|
|
982
|
+
id = this.execute(cmd)
|
|
920
983
|
}
|
|
921
|
-
return new WebElementPromise(this, id)
|
|
984
|
+
return new WebElementPromise(this, id)
|
|
922
985
|
}
|
|
923
986
|
|
|
924
987
|
/**
|
|
@@ -929,34 +992,42 @@ class WebDriver {
|
|
|
929
992
|
* @private
|
|
930
993
|
*/
|
|
931
994
|
async findElementInternal_(locatorFn, context) {
|
|
932
|
-
let result = await locatorFn(context)
|
|
995
|
+
let result = await locatorFn(context)
|
|
933
996
|
if (Array.isArray(result)) {
|
|
934
|
-
result = result[0]
|
|
997
|
+
result = result[0]
|
|
935
998
|
}
|
|
936
999
|
if (!(result instanceof WebElement)) {
|
|
937
|
-
throw new TypeError('Custom locator did not return a WebElement')
|
|
1000
|
+
throw new TypeError('Custom locator did not return a WebElement')
|
|
938
1001
|
}
|
|
939
|
-
return result
|
|
1002
|
+
return result
|
|
940
1003
|
}
|
|
941
1004
|
|
|
942
1005
|
/** @override */
|
|
943
1006
|
async findElements(locator) {
|
|
944
|
-
|
|
945
|
-
if (
|
|
946
|
-
|
|
1007
|
+
let cmd = null
|
|
1008
|
+
if (locator instanceof RelativeBy) {
|
|
1009
|
+
cmd = new command.Command(
|
|
1010
|
+
command.Name.FIND_ELEMENTS_RELATIVE
|
|
1011
|
+
).setParameter('args', locator.marshall())
|
|
947
1012
|
} else {
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
1013
|
+
locator = by.checkedLocator(locator)
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
if (typeof locator === 'function') {
|
|
1017
|
+
return this.findElementsInternal_(locator, this)
|
|
1018
|
+
} else if (cmd === null) {
|
|
1019
|
+
cmd = new command.Command(command.Name.FIND_ELEMENTS)
|
|
1020
|
+
.setParameter('using', locator.using)
|
|
1021
|
+
.setParameter('value', locator.value)
|
|
1022
|
+
}
|
|
1023
|
+
try {
|
|
1024
|
+
let res = await this.execute(cmd)
|
|
1025
|
+
return Array.isArray(res) ? res : []
|
|
1026
|
+
} catch (ex) {
|
|
1027
|
+
if (ex instanceof error.NoSuchElementError) {
|
|
1028
|
+
return []
|
|
959
1029
|
}
|
|
1030
|
+
throw ex
|
|
960
1031
|
}
|
|
961
1032
|
}
|
|
962
1033
|
|
|
@@ -968,41 +1039,383 @@ class WebDriver {
|
|
|
968
1039
|
* @private
|
|
969
1040
|
*/
|
|
970
1041
|
async findElementsInternal_(locatorFn, context) {
|
|
971
|
-
const result = await locatorFn(context)
|
|
1042
|
+
const result = await locatorFn(context)
|
|
972
1043
|
if (result instanceof WebElement) {
|
|
973
|
-
return [result]
|
|
1044
|
+
return [result]
|
|
974
1045
|
}
|
|
975
1046
|
|
|
976
1047
|
if (!Array.isArray(result)) {
|
|
977
|
-
return []
|
|
1048
|
+
return []
|
|
978
1049
|
}
|
|
979
1050
|
|
|
980
|
-
return result.filter(function(item) {
|
|
981
|
-
return item instanceof WebElement
|
|
982
|
-
})
|
|
1051
|
+
return result.filter(function (item) {
|
|
1052
|
+
return item instanceof WebElement
|
|
1053
|
+
})
|
|
983
1054
|
}
|
|
984
1055
|
|
|
985
1056
|
/** @override */
|
|
986
1057
|
takeScreenshot() {
|
|
987
|
-
return this.execute(new command.Command(command.Name.SCREENSHOT))
|
|
1058
|
+
return this.execute(new command.Command(command.Name.SCREENSHOT))
|
|
988
1059
|
}
|
|
989
1060
|
|
|
990
1061
|
/** @override */
|
|
991
1062
|
manage() {
|
|
992
|
-
return new Options(this)
|
|
1063
|
+
return new Options(this)
|
|
993
1064
|
}
|
|
994
1065
|
|
|
995
1066
|
/** @override */
|
|
996
1067
|
navigate() {
|
|
997
|
-
return new Navigation(this)
|
|
1068
|
+
return new Navigation(this)
|
|
998
1069
|
}
|
|
999
1070
|
|
|
1000
1071
|
/** @override */
|
|
1001
1072
|
switchTo() {
|
|
1002
|
-
return new TargetLocator(this)
|
|
1073
|
+
return new TargetLocator(this)
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
validatePrintPageParams(keys, object) {
|
|
1077
|
+
let page = {}
|
|
1078
|
+
let margin = {}
|
|
1079
|
+
let data
|
|
1080
|
+
Object.keys(keys).forEach(function (key) {
|
|
1081
|
+
data = keys[key]
|
|
1082
|
+
let obj = {
|
|
1083
|
+
orientation: function () {
|
|
1084
|
+
object.orientation = data
|
|
1085
|
+
},
|
|
1086
|
+
|
|
1087
|
+
scale: function () {
|
|
1088
|
+
object.scale = data
|
|
1089
|
+
},
|
|
1090
|
+
|
|
1091
|
+
background: function () {
|
|
1092
|
+
object.background = data
|
|
1093
|
+
},
|
|
1094
|
+
|
|
1095
|
+
width: function () {
|
|
1096
|
+
page.width = data
|
|
1097
|
+
object.page = page
|
|
1098
|
+
},
|
|
1099
|
+
|
|
1100
|
+
height: function () {
|
|
1101
|
+
page.height = data
|
|
1102
|
+
object.page = page
|
|
1103
|
+
},
|
|
1104
|
+
|
|
1105
|
+
top: function () {
|
|
1106
|
+
margin.top = data
|
|
1107
|
+
object.margin = margin
|
|
1108
|
+
},
|
|
1109
|
+
|
|
1110
|
+
left: function () {
|
|
1111
|
+
margin.left = data
|
|
1112
|
+
object.margin = margin
|
|
1113
|
+
},
|
|
1114
|
+
|
|
1115
|
+
bottom: function () {
|
|
1116
|
+
margin.bottom = data
|
|
1117
|
+
object.margin = margin
|
|
1118
|
+
},
|
|
1119
|
+
|
|
1120
|
+
right: function () {
|
|
1121
|
+
margin.right = data
|
|
1122
|
+
object.margin = margin
|
|
1123
|
+
},
|
|
1124
|
+
|
|
1125
|
+
shrinkToFit: function () {
|
|
1126
|
+
object.shrinkToFit = data
|
|
1127
|
+
},
|
|
1128
|
+
|
|
1129
|
+
pageRanges: function () {
|
|
1130
|
+
object.pageRanges = data
|
|
1131
|
+
},
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
if (!Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
1135
|
+
throw new error.InvalidArgumentError(`Invalid Argument '${key}'`)
|
|
1136
|
+
} else {
|
|
1137
|
+
obj[key]()
|
|
1138
|
+
}
|
|
1139
|
+
})
|
|
1140
|
+
|
|
1141
|
+
return object
|
|
1003
1142
|
}
|
|
1004
|
-
}
|
|
1005
1143
|
|
|
1144
|
+
/** @override */
|
|
1145
|
+
printPage(options = {}) {
|
|
1146
|
+
let keys = options
|
|
1147
|
+
let params = {}
|
|
1148
|
+
let resultObj
|
|
1149
|
+
|
|
1150
|
+
let self = this
|
|
1151
|
+
resultObj = self.validatePrintPageParams(keys, params)
|
|
1152
|
+
|
|
1153
|
+
return this.execute(
|
|
1154
|
+
new command.Command(command.Name.PRINT_PAGE).setParameters(resultObj)
|
|
1155
|
+
)
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
/**
|
|
1159
|
+
* Creates a new WebSocket connection.
|
|
1160
|
+
* @return {!Promise<resolved>} A new CDP instance.
|
|
1161
|
+
*/
|
|
1162
|
+
async createCDPConnection(target) {
|
|
1163
|
+
const caps = await this.getCapabilities()
|
|
1164
|
+
const seCdp = caps['map_'].get('se:cdp')
|
|
1165
|
+
const vendorInfo =
|
|
1166
|
+
caps['map_'].get(this.VENDOR_COMMAND_PREFIX + ':chromeOptions') ||
|
|
1167
|
+
caps['map_'].get(this.VENDOR_CAPABILITY_PREFIX + ':edgeOptions') ||
|
|
1168
|
+
caps['map_'].get('moz:debuggerAddress') ||
|
|
1169
|
+
new Map();
|
|
1170
|
+
const debuggerUrl = seCdp || vendorInfo['debuggerAddress'] || vendorInfo
|
|
1171
|
+
this._wsUrl = await this.getWsUrl(debuggerUrl, target)
|
|
1172
|
+
|
|
1173
|
+
return new Promise((resolve, reject) => {
|
|
1174
|
+
try {
|
|
1175
|
+
this._wsConnection = new WebSocket(this._wsUrl)
|
|
1176
|
+
} catch (err) {
|
|
1177
|
+
reject(err)
|
|
1178
|
+
return
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
this._wsConnection.on('open', () => {
|
|
1182
|
+
this._cdpConnection = new cdp.CdpConnection(this._wsConnection)
|
|
1183
|
+
resolve(this._cdpConnection)
|
|
1184
|
+
})
|
|
1185
|
+
|
|
1186
|
+
this._wsConnection.on('error', (error) => {
|
|
1187
|
+
reject(error)
|
|
1188
|
+
})
|
|
1189
|
+
})
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
/**
|
|
1193
|
+
* Retrieves 'webSocketDebuggerUrl' by sending a http request using debugger address
|
|
1194
|
+
* @param {string} debuggerAddress
|
|
1195
|
+
* @param {string} target
|
|
1196
|
+
* @return {string} Returns parsed webSocketDebuggerUrl obtained from the http request
|
|
1197
|
+
*/
|
|
1198
|
+
async getWsUrl(debuggerAddress, target) {
|
|
1199
|
+
if (target && cdpTargets.indexOf(target.toLowerCase()) === -1) {
|
|
1200
|
+
throw new error.InvalidArgumentError('invalid target value')
|
|
1201
|
+
}
|
|
1202
|
+
let path
|
|
1203
|
+
if (target === 'page') {
|
|
1204
|
+
path = '/json'
|
|
1205
|
+
} else {
|
|
1206
|
+
path = '/json/version'
|
|
1207
|
+
}
|
|
1208
|
+
let request = new http.Request('GET', path)
|
|
1209
|
+
let client = new http.HttpClient('http://' + debuggerAddress)
|
|
1210
|
+
let response = await client.send(request)
|
|
1211
|
+
let url
|
|
1212
|
+
if (target.toLowerCase() === 'page') {
|
|
1213
|
+
url = JSON.parse(response.body)[0]['webSocketDebuggerUrl']
|
|
1214
|
+
} else {
|
|
1215
|
+
url = JSON.parse(response.body)['webSocketDebuggerUrl']
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
return url
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
/**
|
|
1222
|
+
* Sets a listener for Fetch.authRequired event from CDP
|
|
1223
|
+
* If event is triggered, it enter username and password
|
|
1224
|
+
* and allows the test to move forward
|
|
1225
|
+
* @param {string} username
|
|
1226
|
+
* @param {string} password
|
|
1227
|
+
* @param connection CDP Connection
|
|
1228
|
+
*/
|
|
1229
|
+
async register(username, password, connection) {
|
|
1230
|
+
await connection.execute(
|
|
1231
|
+
'Network.setCacheDisabled',
|
|
1232
|
+
this.getRandomNumber(1, 10),
|
|
1233
|
+
{
|
|
1234
|
+
cacheDisabled: true,
|
|
1235
|
+
},
|
|
1236
|
+
null
|
|
1237
|
+
)
|
|
1238
|
+
|
|
1239
|
+
this._wsConnection.on('message', (message) => {
|
|
1240
|
+
const params = JSON.parse(message)
|
|
1241
|
+
|
|
1242
|
+
if (params.method === 'Fetch.authRequired') {
|
|
1243
|
+
const requestParams = params['params']
|
|
1244
|
+
connection.execute(
|
|
1245
|
+
'Fetch.continueWithAuth',
|
|
1246
|
+
this.getRandomNumber(1, 10),
|
|
1247
|
+
{
|
|
1248
|
+
requestId: requestParams['requestId'],
|
|
1249
|
+
authChallengeResponse: {
|
|
1250
|
+
response: 'ProvideCredentials',
|
|
1251
|
+
username: username,
|
|
1252
|
+
password: password,
|
|
1253
|
+
},
|
|
1254
|
+
}
|
|
1255
|
+
)
|
|
1256
|
+
} else if (params.method === 'Fetch.requestPaused') {
|
|
1257
|
+
const requestPausedParams = params['params']
|
|
1258
|
+
connection.execute(
|
|
1259
|
+
'Fetch.continueRequest',
|
|
1260
|
+
this.getRandomNumber(1, 10),
|
|
1261
|
+
{
|
|
1262
|
+
requestId: requestPausedParams['requestId'],
|
|
1263
|
+
}
|
|
1264
|
+
)
|
|
1265
|
+
}
|
|
1266
|
+
})
|
|
1267
|
+
|
|
1268
|
+
await connection.execute(
|
|
1269
|
+
'Fetch.enable',
|
|
1270
|
+
1,
|
|
1271
|
+
{
|
|
1272
|
+
handleAuthRequests: true,
|
|
1273
|
+
},
|
|
1274
|
+
null
|
|
1275
|
+
)
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
/**
|
|
1279
|
+
*
|
|
1280
|
+
* @param connection
|
|
1281
|
+
* @param callback
|
|
1282
|
+
* @returns {Promise<void>}
|
|
1283
|
+
*/
|
|
1284
|
+
async onLogEvent(connection, callback) {
|
|
1285
|
+
await connection.execute(
|
|
1286
|
+
'Runtime.enable',
|
|
1287
|
+
this.getRandomNumber(1, 10),
|
|
1288
|
+
{},
|
|
1289
|
+
null
|
|
1290
|
+
)
|
|
1291
|
+
|
|
1292
|
+
this._wsConnection.on('message', (message) => {
|
|
1293
|
+
const params = JSON.parse(message)
|
|
1294
|
+
|
|
1295
|
+
if (params.method === 'Runtime.consoleAPICalled') {
|
|
1296
|
+
const consoleEventParams = params['params']
|
|
1297
|
+
let event = {
|
|
1298
|
+
type: consoleEventParams['type'],
|
|
1299
|
+
timestamp: new Date(consoleEventParams['timestamp']),
|
|
1300
|
+
args: consoleEventParams['args'],
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
callback(event)
|
|
1304
|
+
}
|
|
1305
|
+
})
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
/**
|
|
1309
|
+
*
|
|
1310
|
+
* @param connection
|
|
1311
|
+
* @param callback
|
|
1312
|
+
* @returns {Promise<void>}
|
|
1313
|
+
*/
|
|
1314
|
+
async onLogException(connection, callback) {
|
|
1315
|
+
await connection.execute(
|
|
1316
|
+
'Runtime.enable',
|
|
1317
|
+
this.getRandomNumber(1, 10),
|
|
1318
|
+
{},
|
|
1319
|
+
null
|
|
1320
|
+
)
|
|
1321
|
+
|
|
1322
|
+
this._wsConnection.on('message', (message) => {
|
|
1323
|
+
const params = JSON.parse(message)
|
|
1324
|
+
|
|
1325
|
+
if (params.method === 'Runtime.exceptionThrown') {
|
|
1326
|
+
const exceptionEventParams = params['params']
|
|
1327
|
+
let event = {
|
|
1328
|
+
exceptionDetails: exceptionEventParams['exceptionDetails'],
|
|
1329
|
+
timestamp: new Date(exceptionEventParams['timestamp']),
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
callback(event)
|
|
1333
|
+
}
|
|
1334
|
+
})
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
/**
|
|
1338
|
+
* @param connection
|
|
1339
|
+
* @param callback
|
|
1340
|
+
* @returns {Promise<void>}
|
|
1341
|
+
*/
|
|
1342
|
+
async logMutationEvents(connection, callback) {
|
|
1343
|
+
await connection.execute(
|
|
1344
|
+
'Runtime.enable',
|
|
1345
|
+
this.getRandomNumber(1, 10),
|
|
1346
|
+
{},
|
|
1347
|
+
null
|
|
1348
|
+
)
|
|
1349
|
+
await connection.execute(
|
|
1350
|
+
'Page.enable',
|
|
1351
|
+
this.getRandomNumber(1, 10),
|
|
1352
|
+
{},
|
|
1353
|
+
null
|
|
1354
|
+
)
|
|
1355
|
+
|
|
1356
|
+
await connection.execute(
|
|
1357
|
+
'Runtime.addBinding',
|
|
1358
|
+
this.getRandomNumber(1, 10),
|
|
1359
|
+
{
|
|
1360
|
+
name: '__webdriver_attribute',
|
|
1361
|
+
},
|
|
1362
|
+
null
|
|
1363
|
+
)
|
|
1364
|
+
|
|
1365
|
+
let mutationListener = ''
|
|
1366
|
+
try {
|
|
1367
|
+
// Depending on what is running the code it could appear in 2 different places which is why we try
|
|
1368
|
+
// here and then the other location
|
|
1369
|
+
mutationListener = fs
|
|
1370
|
+
.readFileSync(
|
|
1371
|
+
'./javascript/node/selenium-webdriver/lib/atoms/mutation-listener.js',
|
|
1372
|
+
'utf-8'
|
|
1373
|
+
)
|
|
1374
|
+
.toString()
|
|
1375
|
+
} catch {
|
|
1376
|
+
mutationListener = fs
|
|
1377
|
+
.readFileSync(path.resolve(__dirname, './atoms/mutation-listener.js'), 'utf-8')
|
|
1378
|
+
.toString()
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
this.executeScript(mutationListener)
|
|
1382
|
+
|
|
1383
|
+
await connection.execute(
|
|
1384
|
+
'Page.addScriptToEvaluateOnNewDocument',
|
|
1385
|
+
this.getRandomNumber(1, 10),
|
|
1386
|
+
{
|
|
1387
|
+
source: mutationListener,
|
|
1388
|
+
},
|
|
1389
|
+
null
|
|
1390
|
+
)
|
|
1391
|
+
|
|
1392
|
+
this._wsConnection.on('message', async (message) => {
|
|
1393
|
+
const params = JSON.parse(message)
|
|
1394
|
+
if (params.method === 'Runtime.bindingCalled') {
|
|
1395
|
+
let payload = JSON.parse(params['params']['payload'])
|
|
1396
|
+
let elements = await this.findElements({
|
|
1397
|
+
css: '*[data-__webdriver_id=' + payload['target'],
|
|
1398
|
+
})
|
|
1399
|
+
|
|
1400
|
+
if (elements.length === 0) {
|
|
1401
|
+
return
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
let event = {
|
|
1405
|
+
element: elements[0],
|
|
1406
|
+
attribute_name: payload['name'],
|
|
1407
|
+
current_value: payload['value'],
|
|
1408
|
+
old_value: payload['oldValue'],
|
|
1409
|
+
}
|
|
1410
|
+
callback(event)
|
|
1411
|
+
}
|
|
1412
|
+
})
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1415
|
+
getRandomNumber(min, max) {
|
|
1416
|
+
return Math.floor(Math.random() * (max - min + 1) + min)
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1006
1419
|
|
|
1007
1420
|
/**
|
|
1008
1421
|
* Interface for navigating back and forth in the browser history.
|
|
@@ -1021,7 +1434,7 @@ class Navigation {
|
|
|
1021
1434
|
*/
|
|
1022
1435
|
constructor(driver) {
|
|
1023
1436
|
/** @private {!WebDriver} */
|
|
1024
|
-
this.driver_ = driver
|
|
1437
|
+
this.driver_ = driver
|
|
1025
1438
|
}
|
|
1026
1439
|
|
|
1027
1440
|
/**
|
|
@@ -1033,8 +1446,8 @@ class Navigation {
|
|
|
1033
1446
|
*/
|
|
1034
1447
|
to(url) {
|
|
1035
1448
|
return this.driver_.execute(
|
|
1036
|
-
|
|
1037
|
-
|
|
1449
|
+
new command.Command(command.Name.GET).setParameter('url', url)
|
|
1450
|
+
)
|
|
1038
1451
|
}
|
|
1039
1452
|
|
|
1040
1453
|
/**
|
|
@@ -1044,7 +1457,7 @@ class Navigation {
|
|
|
1044
1457
|
* navigation event has completed.
|
|
1045
1458
|
*/
|
|
1046
1459
|
back() {
|
|
1047
|
-
return this.driver_.execute(new command.Command(command.Name.GO_BACK))
|
|
1460
|
+
return this.driver_.execute(new command.Command(command.Name.GO_BACK))
|
|
1048
1461
|
}
|
|
1049
1462
|
|
|
1050
1463
|
/**
|
|
@@ -1054,7 +1467,7 @@ class Navigation {
|
|
|
1054
1467
|
* navigation event has completed.
|
|
1055
1468
|
*/
|
|
1056
1469
|
forward() {
|
|
1057
|
-
return this.driver_.execute(new command.Command(command.Name.GO_FORWARD))
|
|
1470
|
+
return this.driver_.execute(new command.Command(command.Name.GO_FORWARD))
|
|
1058
1471
|
}
|
|
1059
1472
|
|
|
1060
1473
|
/**
|
|
@@ -1064,11 +1477,10 @@ class Navigation {
|
|
|
1064
1477
|
* navigation event has completed.
|
|
1065
1478
|
*/
|
|
1066
1479
|
refresh() {
|
|
1067
|
-
return this.driver_.execute(new command.Command(command.Name.REFRESH))
|
|
1480
|
+
return this.driver_.execute(new command.Command(command.Name.REFRESH))
|
|
1068
1481
|
}
|
|
1069
1482
|
}
|
|
1070
1483
|
|
|
1071
|
-
|
|
1072
1484
|
/**
|
|
1073
1485
|
* Provides methods for managing browser and driver state.
|
|
1074
1486
|
*
|
|
@@ -1082,7 +1494,7 @@ class Options {
|
|
|
1082
1494
|
*/
|
|
1083
1495
|
constructor(driver) {
|
|
1084
1496
|
/** @private {!WebDriver} */
|
|
1085
|
-
this.driver_ = driver
|
|
1497
|
+
this.driver_ = driver
|
|
1086
1498
|
}
|
|
1087
1499
|
|
|
1088
1500
|
/**
|
|
@@ -1111,43 +1523,50 @@ class Options {
|
|
|
1111
1523
|
* invalid.
|
|
1112
1524
|
* @throws {TypeError} if `spec` is not a cookie object.
|
|
1113
1525
|
*/
|
|
1114
|
-
addCookie({name, value, path, domain, secure, httpOnly, expiry, sameSite}) {
|
|
1526
|
+
addCookie({ name, value, path, domain, secure, httpOnly, expiry, sameSite }) {
|
|
1115
1527
|
// We do not allow '=' or ';' in the name.
|
|
1116
1528
|
if (/[;=]/.test(name)) {
|
|
1117
|
-
throw new error.InvalidArgumentError(
|
|
1118
|
-
'Invalid cookie name "' + name + '"');
|
|
1529
|
+
throw new error.InvalidArgumentError('Invalid cookie name "' + name + '"')
|
|
1119
1530
|
}
|
|
1120
1531
|
|
|
1121
1532
|
// We do not allow ';' in value.
|
|
1122
1533
|
if (/;/.test(value)) {
|
|
1123
1534
|
throw new error.InvalidArgumentError(
|
|
1124
|
-
|
|
1535
|
+
'Invalid cookie value "' + value + '"'
|
|
1536
|
+
)
|
|
1125
1537
|
}
|
|
1126
1538
|
|
|
1127
1539
|
if (typeof expiry === 'number') {
|
|
1128
|
-
expiry = Math.floor(expiry)
|
|
1540
|
+
expiry = Math.floor(expiry)
|
|
1129
1541
|
} else if (expiry instanceof Date) {
|
|
1130
|
-
let date = /** @type {!Date} */(expiry)
|
|
1131
|
-
expiry = Math.floor(date.getTime() / 1000)
|
|
1542
|
+
let date = /** @type {!Date} */ (expiry)
|
|
1543
|
+
expiry = Math.floor(date.getTime() / 1000)
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
if (sameSite && !['Strict', 'Lax', 'None'].includes(sameSite)) {
|
|
1547
|
+
throw new error.InvalidArgumentError(
|
|
1548
|
+
`Invalid sameSite cookie value '${sameSite}'. It should be one of "Lax", "Strict" or "None"`
|
|
1549
|
+
)
|
|
1132
1550
|
}
|
|
1133
1551
|
|
|
1134
|
-
if(sameSite
|
|
1552
|
+
if (sameSite === 'None' && !secure) {
|
|
1135
1553
|
throw new error.InvalidArgumentError(
|
|
1136
|
-
|
|
1554
|
+
'Invalid cookie configuration: SameSite=None must be Secure'
|
|
1555
|
+
)
|
|
1137
1556
|
}
|
|
1138
1557
|
|
|
1139
1558
|
return this.driver_.execute(
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1559
|
+
new command.Command(command.Name.ADD_COOKIE).setParameter('cookie', {
|
|
1560
|
+
name: name,
|
|
1561
|
+
value: value,
|
|
1562
|
+
path: path,
|
|
1563
|
+
domain: domain,
|
|
1564
|
+
secure: !!secure,
|
|
1565
|
+
httpOnly: !!httpOnly,
|
|
1566
|
+
expiry: expiry,
|
|
1567
|
+
sameSite: sameSite,
|
|
1568
|
+
})
|
|
1569
|
+
)
|
|
1151
1570
|
}
|
|
1152
1571
|
|
|
1153
1572
|
/**
|
|
@@ -1158,7 +1577,8 @@ class Options {
|
|
|
1158
1577
|
*/
|
|
1159
1578
|
deleteAllCookies() {
|
|
1160
1579
|
return this.driver_.execute(
|
|
1161
|
-
|
|
1580
|
+
new command.Command(command.Name.DELETE_ALL_COOKIES)
|
|
1581
|
+
)
|
|
1162
1582
|
}
|
|
1163
1583
|
|
|
1164
1584
|
/**
|
|
@@ -1171,8 +1591,8 @@ class Options {
|
|
|
1171
1591
|
*/
|
|
1172
1592
|
deleteCookie(name) {
|
|
1173
1593
|
return this.driver_.execute(
|
|
1174
|
-
|
|
1175
|
-
|
|
1594
|
+
new command.Command(command.Name.DELETE_COOKIE).setParameter('name', name)
|
|
1595
|
+
)
|
|
1176
1596
|
}
|
|
1177
1597
|
|
|
1178
1598
|
/**
|
|
@@ -1184,7 +1604,8 @@ class Options {
|
|
|
1184
1604
|
*/
|
|
1185
1605
|
getCookies() {
|
|
1186
1606
|
return this.driver_.execute(
|
|
1187
|
-
|
|
1607
|
+
new command.Command(command.Name.GET_ALL_COOKIES)
|
|
1608
|
+
)
|
|
1188
1609
|
}
|
|
1189
1610
|
|
|
1190
1611
|
/**
|
|
@@ -1199,24 +1620,25 @@ class Options {
|
|
|
1199
1620
|
*/
|
|
1200
1621
|
async getCookie(name) {
|
|
1201
1622
|
try {
|
|
1202
|
-
const cookie =
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
return cookie;
|
|
1623
|
+
const cookie = await this.driver_.execute(
|
|
1624
|
+
new command.Command(command.Name.GET_COOKIE).setParameter('name', name)
|
|
1625
|
+
)
|
|
1626
|
+
return cookie
|
|
1207
1627
|
} catch (err) {
|
|
1208
|
-
if (
|
|
1209
|
-
|
|
1210
|
-
|
|
1628
|
+
if (
|
|
1629
|
+
!(err instanceof error.UnknownCommandError) &&
|
|
1630
|
+
!(err instanceof error.UnsupportedOperationError)
|
|
1631
|
+
) {
|
|
1632
|
+
throw err
|
|
1211
1633
|
}
|
|
1212
1634
|
|
|
1213
|
-
const cookies = await this.getCookies()
|
|
1635
|
+
const cookies = await this.getCookies()
|
|
1214
1636
|
for (let cookie of cookies) {
|
|
1215
1637
|
if (cookie && cookie['name'] === name) {
|
|
1216
|
-
return cookie
|
|
1638
|
+
return cookie
|
|
1217
1639
|
}
|
|
1218
1640
|
}
|
|
1219
|
-
return null
|
|
1641
|
+
return null
|
|
1220
1642
|
}
|
|
1221
1643
|
}
|
|
1222
1644
|
|
|
@@ -1231,7 +1653,7 @@ class Options {
|
|
|
1231
1653
|
* @see #setTimeouts()
|
|
1232
1654
|
*/
|
|
1233
1655
|
getTimeouts() {
|
|
1234
|
-
return this.driver_.execute(new command.Command(command.Name.GET_TIMEOUT))
|
|
1656
|
+
return this.driver_.execute(new command.Command(command.Name.GET_TIMEOUT))
|
|
1235
1657
|
}
|
|
1236
1658
|
|
|
1237
1659
|
/**
|
|
@@ -1263,60 +1685,59 @@ class Options {
|
|
|
1263
1685
|
* @see #getTimeouts()
|
|
1264
1686
|
* @see <https://w3c.github.io/webdriver/webdriver-spec.html#dfn-set-timeouts>
|
|
1265
1687
|
*/
|
|
1266
|
-
setTimeouts({script, pageLoad, implicit} = {}) {
|
|
1267
|
-
let cmd = new command.Command(command.Name.SET_TIMEOUT)
|
|
1688
|
+
setTimeouts({ script, pageLoad, implicit } = {}) {
|
|
1689
|
+
let cmd = new command.Command(command.Name.SET_TIMEOUT)
|
|
1268
1690
|
|
|
1269
|
-
let valid = false
|
|
1691
|
+
let valid = false
|
|
1270
1692
|
function setParam(key, value) {
|
|
1271
1693
|
if (value === null || typeof value === 'number') {
|
|
1272
|
-
valid = true
|
|
1273
|
-
cmd.setParameter(key, value)
|
|
1694
|
+
valid = true
|
|
1695
|
+
cmd.setParameter(key, value)
|
|
1274
1696
|
} else if (typeof value !== 'undefined') {
|
|
1275
1697
|
throw TypeError(
|
|
1276
|
-
|
|
1277
|
-
|
|
1698
|
+
'invalid timeouts configuration:' +
|
|
1699
|
+
` expected "${key}" to be a number, got ${typeof value}`
|
|
1700
|
+
)
|
|
1278
1701
|
}
|
|
1279
1702
|
}
|
|
1280
|
-
setParam('implicit', implicit)
|
|
1281
|
-
setParam('pageLoad', pageLoad)
|
|
1282
|
-
setParam('script', script)
|
|
1703
|
+
setParam('implicit', implicit)
|
|
1704
|
+
setParam('pageLoad', pageLoad)
|
|
1705
|
+
setParam('script', script)
|
|
1283
1706
|
|
|
1284
1707
|
if (valid) {
|
|
1285
|
-
return this.driver_.execute(cmd)
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
});
|
|
1708
|
+
return this.driver_.execute(cmd).catch(() => {
|
|
1709
|
+
// Fallback to the legacy method.
|
|
1710
|
+
let cmds = []
|
|
1711
|
+
if (typeof script === 'number') {
|
|
1712
|
+
cmds.push(legacyTimeout(this.driver_, 'script', script))
|
|
1713
|
+
}
|
|
1714
|
+
if (typeof implicit === 'number') {
|
|
1715
|
+
cmds.push(legacyTimeout(this.driver_, 'implicit', implicit))
|
|
1716
|
+
}
|
|
1717
|
+
if (typeof pageLoad === 'number') {
|
|
1718
|
+
cmds.push(legacyTimeout(this.driver_, 'page load', pageLoad))
|
|
1719
|
+
}
|
|
1720
|
+
return Promise.all(cmds)
|
|
1721
|
+
})
|
|
1300
1722
|
}
|
|
1301
|
-
throw TypeError('no timeouts specified')
|
|
1723
|
+
throw TypeError('no timeouts specified')
|
|
1302
1724
|
}
|
|
1303
1725
|
|
|
1304
1726
|
/**
|
|
1305
1727
|
* @return {!Logs} The interface for managing driver logs.
|
|
1306
1728
|
*/
|
|
1307
1729
|
logs() {
|
|
1308
|
-
return new Logs(this.driver_)
|
|
1730
|
+
return new Logs(this.driver_)
|
|
1309
1731
|
}
|
|
1310
1732
|
|
|
1311
1733
|
/**
|
|
1312
1734
|
* @return {!Window} The interface for managing the current window.
|
|
1313
1735
|
*/
|
|
1314
1736
|
window() {
|
|
1315
|
-
return new Window(this.driver_)
|
|
1737
|
+
return new Window(this.driver_)
|
|
1316
1738
|
}
|
|
1317
1739
|
}
|
|
1318
1740
|
|
|
1319
|
-
|
|
1320
1741
|
/**
|
|
1321
1742
|
* @param {!WebDriver} driver
|
|
1322
1743
|
* @param {string} type
|
|
@@ -1325,44 +1746,39 @@ class Options {
|
|
|
1325
1746
|
*/
|
|
1326
1747
|
function legacyTimeout(driver, type, ms) {
|
|
1327
1748
|
return driver.execute(
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1749
|
+
new command.Command(command.Name.SET_TIMEOUT)
|
|
1750
|
+
.setParameter('type', type)
|
|
1751
|
+
.setParameter('ms', ms)
|
|
1752
|
+
)
|
|
1331
1753
|
}
|
|
1332
1754
|
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
1755
|
/**
|
|
1336
1756
|
* A record object describing a browser cookie.
|
|
1337
1757
|
*
|
|
1338
1758
|
* @record
|
|
1339
1759
|
*/
|
|
1340
|
-
Options.Cookie = function() {}
|
|
1341
|
-
|
|
1760
|
+
Options.Cookie = function () { }
|
|
1342
1761
|
|
|
1343
1762
|
/**
|
|
1344
1763
|
* The name of the cookie.
|
|
1345
1764
|
*
|
|
1346
1765
|
* @type {string}
|
|
1347
1766
|
*/
|
|
1348
|
-
Options.Cookie.prototype.name
|
|
1349
|
-
|
|
1767
|
+
Options.Cookie.prototype.name
|
|
1350
1768
|
|
|
1351
1769
|
/**
|
|
1352
1770
|
* The cookie value.
|
|
1353
1771
|
*
|
|
1354
1772
|
* @type {string}
|
|
1355
1773
|
*/
|
|
1356
|
-
Options.Cookie.prototype.value
|
|
1357
|
-
|
|
1774
|
+
Options.Cookie.prototype.value
|
|
1358
1775
|
|
|
1359
1776
|
/**
|
|
1360
1777
|
* The cookie path. Defaults to "/" when adding a cookie.
|
|
1361
1778
|
*
|
|
1362
1779
|
* @type {(string|undefined)}
|
|
1363
1780
|
*/
|
|
1364
|
-
Options.Cookie.prototype.path
|
|
1365
|
-
|
|
1781
|
+
Options.Cookie.prototype.path
|
|
1366
1782
|
|
|
1367
1783
|
/**
|
|
1368
1784
|
* The domain the cookie is visible to. Defaults to the current browsing
|
|
@@ -1370,8 +1786,7 @@ Options.Cookie.prototype.path;
|
|
|
1370
1786
|
*
|
|
1371
1787
|
* @type {(string|undefined)}
|
|
1372
1788
|
*/
|
|
1373
|
-
Options.Cookie.prototype.domain
|
|
1374
|
-
|
|
1789
|
+
Options.Cookie.prototype.domain
|
|
1375
1790
|
|
|
1376
1791
|
/**
|
|
1377
1792
|
* Whether the cookie is a secure cookie. Defaults to false when adding a new
|
|
@@ -1379,8 +1794,7 @@ Options.Cookie.prototype.domain;
|
|
|
1379
1794
|
*
|
|
1380
1795
|
* @type {(boolean|undefined)}
|
|
1381
1796
|
*/
|
|
1382
|
-
Options.Cookie.prototype.secure
|
|
1383
|
-
|
|
1797
|
+
Options.Cookie.prototype.secure
|
|
1384
1798
|
|
|
1385
1799
|
/**
|
|
1386
1800
|
* Whether the cookie is an HTTP only cookie. Defaults to false when adding a
|
|
@@ -1388,8 +1802,7 @@ Options.Cookie.prototype.secure;
|
|
|
1388
1802
|
*
|
|
1389
1803
|
* @type {(boolean|undefined)}
|
|
1390
1804
|
*/
|
|
1391
|
-
Options.Cookie.prototype.httpOnly
|
|
1392
|
-
|
|
1805
|
+
Options.Cookie.prototype.httpOnly
|
|
1393
1806
|
|
|
1394
1807
|
/**
|
|
1395
1808
|
* When the cookie expires.
|
|
@@ -1402,19 +1815,18 @@ Options.Cookie.prototype.httpOnly;
|
|
|
1402
1815
|
*
|
|
1403
1816
|
* @type {(!Date|number|undefined)}
|
|
1404
1817
|
*/
|
|
1405
|
-
Options.Cookie.prototype.expiry
|
|
1406
|
-
|
|
1818
|
+
Options.Cookie.prototype.expiry
|
|
1407
1819
|
|
|
1408
1820
|
/**
|
|
1409
1821
|
* When the cookie applies to a SameSite policy.
|
|
1410
1822
|
*
|
|
1411
1823
|
* When {@linkplain Options#addCookie() adding a cookie}, this may be specified
|
|
1412
|
-
* as a {@link string} object which is
|
|
1824
|
+
* as a {@link string} object which is one of 'Lax', 'Strict' or 'None'.
|
|
1413
1825
|
*
|
|
1414
1826
|
*
|
|
1415
|
-
* @type {(
|
|
1827
|
+
* @type {(string|undefined)}
|
|
1416
1828
|
*/
|
|
1417
|
-
Options.Cookie.prototype.sameSite
|
|
1829
|
+
Options.Cookie.prototype.sameSite
|
|
1418
1830
|
|
|
1419
1831
|
/**
|
|
1420
1832
|
* An interface for managing the current window.
|
|
@@ -1434,7 +1846,7 @@ class Window {
|
|
|
1434
1846
|
*/
|
|
1435
1847
|
constructor(driver) {
|
|
1436
1848
|
/** @private {!WebDriver} */
|
|
1437
|
-
this.driver_ = driver
|
|
1849
|
+
this.driver_ = driver
|
|
1438
1850
|
}
|
|
1439
1851
|
|
|
1440
1852
|
/**
|
|
@@ -1447,20 +1859,25 @@ class Window {
|
|
|
1447
1859
|
async getRect() {
|
|
1448
1860
|
try {
|
|
1449
1861
|
return await this.driver_.execute(
|
|
1450
|
-
|
|
1862
|
+
new command.Command(command.Name.GET_WINDOW_RECT)
|
|
1863
|
+
)
|
|
1451
1864
|
} catch (ex) {
|
|
1452
1865
|
if (ex instanceof error.UnknownCommandError) {
|
|
1453
|
-
let {width, height} =
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1866
|
+
let { width, height } = await this.driver_.execute(
|
|
1867
|
+
new command.Command(command.Name.GET_WINDOW_SIZE).setParameter(
|
|
1868
|
+
'windowHandle',
|
|
1869
|
+
'current'
|
|
1870
|
+
)
|
|
1871
|
+
)
|
|
1872
|
+
let { x, y } = await this.driver_.execute(
|
|
1873
|
+
new command.Command(command.Name.GET_WINDOW_POSITION).setParameter(
|
|
1874
|
+
'windowHandle',
|
|
1875
|
+
'current'
|
|
1876
|
+
)
|
|
1877
|
+
)
|
|
1878
|
+
return { x, y, width, height }
|
|
1462
1879
|
}
|
|
1463
|
-
throw ex
|
|
1880
|
+
throw ex
|
|
1464
1881
|
}
|
|
1465
1882
|
}
|
|
1466
1883
|
|
|
@@ -1475,34 +1892,41 @@ class Window {
|
|
|
1475
1892
|
* height: (number|undefined)}} options
|
|
1476
1893
|
* The desired window size and position.
|
|
1477
1894
|
* @return {!Promise<{x: number, y: number, width: number, height: number}>}
|
|
1478
|
-
* A promise that will resolve to the current
|
|
1895
|
+
* A promise that will resolve to the current window's updated window
|
|
1479
1896
|
* rect.
|
|
1480
1897
|
*/
|
|
1481
|
-
async setRect({x, y, width, height}) {
|
|
1898
|
+
async setRect({ x, y, width, height }) {
|
|
1482
1899
|
try {
|
|
1483
1900
|
return await this.driver_.execute(
|
|
1484
|
-
|
|
1485
|
-
|
|
1901
|
+
new command.Command(command.Name.SET_WINDOW_RECT).setParameters({
|
|
1902
|
+
x,
|
|
1903
|
+
y,
|
|
1904
|
+
width,
|
|
1905
|
+
height,
|
|
1906
|
+
})
|
|
1907
|
+
)
|
|
1486
1908
|
} catch (ex) {
|
|
1487
1909
|
if (ex instanceof error.UnknownCommandError) {
|
|
1488
1910
|
if (typeof x === 'number' && typeof y === 'number') {
|
|
1489
1911
|
await this.driver_.execute(
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1912
|
+
new command.Command(command.Name.SET_WINDOW_POSITION)
|
|
1913
|
+
.setParameter('windowHandle', 'current')
|
|
1914
|
+
.setParameter('x', x)
|
|
1915
|
+
.setParameter('y', y)
|
|
1916
|
+
)
|
|
1494
1917
|
}
|
|
1495
1918
|
|
|
1496
|
-
if (typeof
|
|
1919
|
+
if (typeof width === 'number' && typeof height === 'number') {
|
|
1497
1920
|
await this.driver_.execute(
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1921
|
+
new command.Command(command.Name.SET_WINDOW_SIZE)
|
|
1922
|
+
.setParameter('windowHandle', 'current')
|
|
1923
|
+
.setParameter('width', width)
|
|
1924
|
+
.setParameter('height', height)
|
|
1925
|
+
)
|
|
1502
1926
|
}
|
|
1503
|
-
return this.getRect()
|
|
1927
|
+
return this.getRect()
|
|
1504
1928
|
}
|
|
1505
|
-
throw ex
|
|
1929
|
+
throw ex
|
|
1506
1930
|
}
|
|
1507
1931
|
}
|
|
1508
1932
|
|
|
@@ -1516,13 +1940,16 @@ class Window {
|
|
|
1516
1940
|
*/
|
|
1517
1941
|
maximize() {
|
|
1518
1942
|
return this.driver_.execute(
|
|
1519
|
-
|
|
1520
|
-
|
|
1943
|
+
new command.Command(command.Name.MAXIMIZE_WINDOW).setParameter(
|
|
1944
|
+
'windowHandle',
|
|
1945
|
+
'current'
|
|
1946
|
+
)
|
|
1947
|
+
)
|
|
1521
1948
|
}
|
|
1522
1949
|
|
|
1523
1950
|
/**
|
|
1524
1951
|
* Minimizes the current window. The exact behavior of this command is
|
|
1525
|
-
* specific to individual window managers, but
|
|
1952
|
+
* specific to individual window managers, but typically involves hiding
|
|
1526
1953
|
* the window in the system tray.
|
|
1527
1954
|
*
|
|
1528
1955
|
* @return {!Promise<void>} A promise that will be resolved when the command
|
|
@@ -1530,7 +1957,8 @@ class Window {
|
|
|
1530
1957
|
*/
|
|
1531
1958
|
minimize() {
|
|
1532
1959
|
return this.driver_.execute(
|
|
1533
|
-
|
|
1960
|
+
new command.Command(command.Name.MINIMIZE_WINDOW)
|
|
1961
|
+
)
|
|
1534
1962
|
}
|
|
1535
1963
|
|
|
1536
1964
|
/**
|
|
@@ -1545,11 +1973,11 @@ class Window {
|
|
|
1545
1973
|
*/
|
|
1546
1974
|
fullscreen() {
|
|
1547
1975
|
return this.driver_.execute(
|
|
1548
|
-
|
|
1976
|
+
new command.Command(command.Name.FULLSCREEN_WINDOW)
|
|
1977
|
+
)
|
|
1549
1978
|
}
|
|
1550
1979
|
}
|
|
1551
1980
|
|
|
1552
|
-
|
|
1553
1981
|
/**
|
|
1554
1982
|
* Interface for managing WebDriver log records.
|
|
1555
1983
|
*
|
|
@@ -1568,7 +1996,7 @@ class Logs {
|
|
|
1568
1996
|
*/
|
|
1569
1997
|
constructor(driver) {
|
|
1570
1998
|
/** @private {!WebDriver} */
|
|
1571
|
-
this.driver_ = driver
|
|
1999
|
+
this.driver_ = driver
|
|
1572
2000
|
}
|
|
1573
2001
|
|
|
1574
2002
|
/**
|
|
@@ -1585,19 +2013,23 @@ class Logs {
|
|
|
1585
2013
|
* type.
|
|
1586
2014
|
*/
|
|
1587
2015
|
get(type) {
|
|
1588
|
-
let cmd = new command.Command(command.Name.GET_LOG).
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
2016
|
+
let cmd = new command.Command(command.Name.GET_LOG).setParameter(
|
|
2017
|
+
'type',
|
|
2018
|
+
type
|
|
2019
|
+
)
|
|
2020
|
+
return this.driver_.execute(cmd).then(function (entries) {
|
|
2021
|
+
return entries.map(function (entry) {
|
|
2022
|
+
if (!(entry instanceof logging.Entry)) {
|
|
2023
|
+
return new logging.Entry(
|
|
2024
|
+
entry['level'],
|
|
2025
|
+
entry['message'],
|
|
2026
|
+
entry['timestamp'],
|
|
2027
|
+
entry['type']
|
|
2028
|
+
)
|
|
2029
|
+
}
|
|
2030
|
+
return entry
|
|
2031
|
+
})
|
|
2032
|
+
})
|
|
1601
2033
|
}
|
|
1602
2034
|
|
|
1603
2035
|
/**
|
|
@@ -1607,11 +2039,11 @@ class Logs {
|
|
|
1607
2039
|
*/
|
|
1608
2040
|
getAvailableLogTypes() {
|
|
1609
2041
|
return this.driver_.execute(
|
|
1610
|
-
|
|
2042
|
+
new command.Command(command.Name.GET_AVAILABLE_LOG_TYPES)
|
|
2043
|
+
)
|
|
1611
2044
|
}
|
|
1612
2045
|
}
|
|
1613
2046
|
|
|
1614
|
-
|
|
1615
2047
|
/**
|
|
1616
2048
|
* An interface for changing the focus of the driver to another frame or window.
|
|
1617
2049
|
*
|
|
@@ -1629,7 +2061,7 @@ class TargetLocator {
|
|
|
1629
2061
|
*/
|
|
1630
2062
|
constructor(driver) {
|
|
1631
2063
|
/** @private {!WebDriver} */
|
|
1632
|
-
this.driver_ = driver
|
|
2064
|
+
this.driver_ = driver
|
|
1633
2065
|
}
|
|
1634
2066
|
|
|
1635
2067
|
/**
|
|
@@ -1641,8 +2073,9 @@ class TargetLocator {
|
|
|
1641
2073
|
*/
|
|
1642
2074
|
activeElement() {
|
|
1643
2075
|
var id = this.driver_.execute(
|
|
1644
|
-
|
|
1645
|
-
|
|
2076
|
+
new command.Command(command.Name.GET_ACTIVE_ELEMENT)
|
|
2077
|
+
)
|
|
2078
|
+
return new WebElementPromise(this.driver_, id)
|
|
1646
2079
|
}
|
|
1647
2080
|
|
|
1648
2081
|
/**
|
|
@@ -1654,8 +2087,8 @@ class TargetLocator {
|
|
|
1654
2087
|
*/
|
|
1655
2088
|
defaultContent() {
|
|
1656
2089
|
return this.driver_.execute(
|
|
1657
|
-
|
|
1658
|
-
|
|
2090
|
+
new command.Command(command.Name.SWITCH_TO_FRAME).setParameter('id', null)
|
|
2091
|
+
)
|
|
1659
2092
|
}
|
|
1660
2093
|
|
|
1661
2094
|
/**
|
|
@@ -1678,8 +2111,8 @@ class TargetLocator {
|
|
|
1678
2111
|
*/
|
|
1679
2112
|
frame(id) {
|
|
1680
2113
|
return this.driver_.execute(
|
|
1681
|
-
|
|
1682
|
-
|
|
2114
|
+
new command.Command(command.Name.SWITCH_TO_FRAME).setParameter('id', id)
|
|
2115
|
+
)
|
|
1683
2116
|
}
|
|
1684
2117
|
|
|
1685
2118
|
/**
|
|
@@ -1692,7 +2125,8 @@ class TargetLocator {
|
|
|
1692
2125
|
*/
|
|
1693
2126
|
parentFrame() {
|
|
1694
2127
|
return this.driver_.execute(
|
|
1695
|
-
|
|
2128
|
+
new command.Command(command.Name.SWITCH_TO_FRAME_PARENT)
|
|
2129
|
+
)
|
|
1696
2130
|
}
|
|
1697
2131
|
|
|
1698
2132
|
/**
|
|
@@ -1710,11 +2144,12 @@ class TargetLocator {
|
|
|
1710
2144
|
*/
|
|
1711
2145
|
window(nameOrHandle) {
|
|
1712
2146
|
return this.driver_.execute(
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
2147
|
+
new command.Command(command.Name.SWITCH_TO_WINDOW)
|
|
2148
|
+
// "name" supports the legacy drivers. "handle" is the W3C
|
|
2149
|
+
// compliant parameter.
|
|
2150
|
+
.setParameter('name', nameOrHandle)
|
|
2151
|
+
.setParameter('handle', nameOrHandle)
|
|
2152
|
+
)
|
|
1718
2153
|
}
|
|
1719
2154
|
|
|
1720
2155
|
/**
|
|
@@ -1730,12 +2165,16 @@ class TargetLocator {
|
|
|
1730
2165
|
*/
|
|
1731
2166
|
newWindow(typeHint) {
|
|
1732
2167
|
var driver = this.driver_
|
|
1733
|
-
return this.driver_
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
2168
|
+
return this.driver_
|
|
2169
|
+
.execute(
|
|
2170
|
+
new command.Command(command.Name.SWITCH_TO_NEW_WINDOW).setParameter(
|
|
2171
|
+
'type',
|
|
2172
|
+
typeHint
|
|
2173
|
+
)
|
|
2174
|
+
)
|
|
2175
|
+
.then(function (response) {
|
|
2176
|
+
return driver.switchTo().window(response.handle)
|
|
2177
|
+
})
|
|
1739
2178
|
}
|
|
1740
2179
|
|
|
1741
2180
|
/**
|
|
@@ -1748,25 +2187,26 @@ class TargetLocator {
|
|
|
1748
2187
|
*/
|
|
1749
2188
|
alert() {
|
|
1750
2189
|
var text = this.driver_.execute(
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
2190
|
+
new command.Command(command.Name.GET_ALERT_TEXT)
|
|
2191
|
+
)
|
|
2192
|
+
var driver = this.driver_
|
|
2193
|
+
return new AlertPromise(
|
|
2194
|
+
driver,
|
|
2195
|
+
text.then(function (text) {
|
|
2196
|
+
return new Alert(driver, text)
|
|
2197
|
+
})
|
|
2198
|
+
)
|
|
1756
2199
|
}
|
|
1757
2200
|
}
|
|
1758
2201
|
|
|
1759
|
-
|
|
1760
2202
|
//////////////////////////////////////////////////////////////////////////////
|
|
1761
2203
|
//
|
|
1762
2204
|
// WebElement
|
|
1763
2205
|
//
|
|
1764
2206
|
//////////////////////////////////////////////////////////////////////////////
|
|
1765
2207
|
|
|
1766
|
-
|
|
1767
|
-
const
|
|
1768
|
-
const ELEMENT_ID_KEY = 'element-6066-11e4-a52e-4f735466cecf';
|
|
1769
|
-
|
|
2208
|
+
const LEGACY_ELEMENT_ID_KEY = 'ELEMENT'
|
|
2209
|
+
const ELEMENT_ID_KEY = 'element-6066-11e4-a52e-4f735466cecf'
|
|
1770
2210
|
|
|
1771
2211
|
/**
|
|
1772
2212
|
* Represents a DOM element. WebElements can be found by searching from the
|
|
@@ -1786,10 +2226,10 @@ class WebElement {
|
|
|
1786
2226
|
*/
|
|
1787
2227
|
constructor(driver, id) {
|
|
1788
2228
|
/** @private {!WebDriver} */
|
|
1789
|
-
this.driver_ = driver
|
|
2229
|
+
this.driver_ = driver
|
|
1790
2230
|
|
|
1791
2231
|
/** @private {!Promise<string>} */
|
|
1792
|
-
this.id_ = Promise.resolve(id)
|
|
2232
|
+
this.id_ = Promise.resolve(id)
|
|
1793
2233
|
}
|
|
1794
2234
|
|
|
1795
2235
|
/**
|
|
@@ -1799,8 +2239,8 @@ class WebElement {
|
|
|
1799
2239
|
*/
|
|
1800
2240
|
static buildId(id, noLegacy = false) {
|
|
1801
2241
|
return noLegacy
|
|
1802
|
-
|
|
1803
|
-
|
|
2242
|
+
? { [ELEMENT_ID_KEY]: id }
|
|
2243
|
+
: { [ELEMENT_ID_KEY]: id, [LEGACY_ELEMENT_ID_KEY]: id }
|
|
1804
2244
|
}
|
|
1805
2245
|
|
|
1806
2246
|
/**
|
|
@@ -1813,12 +2253,12 @@ class WebElement {
|
|
|
1813
2253
|
static extractId(obj) {
|
|
1814
2254
|
if (obj && typeof obj === 'object') {
|
|
1815
2255
|
if (typeof obj[ELEMENT_ID_KEY] === 'string') {
|
|
1816
|
-
return obj[ELEMENT_ID_KEY]
|
|
2256
|
+
return obj[ELEMENT_ID_KEY]
|
|
1817
2257
|
} else if (typeof obj[LEGACY_ELEMENT_ID_KEY] === 'string') {
|
|
1818
|
-
return obj[LEGACY_ELEMENT_ID_KEY]
|
|
2258
|
+
return obj[LEGACY_ELEMENT_ID_KEY]
|
|
1819
2259
|
}
|
|
1820
2260
|
}
|
|
1821
|
-
throw new TypeError('object is not a WebElement ID')
|
|
2261
|
+
throw new TypeError('object is not a WebElement ID')
|
|
1822
2262
|
}
|
|
1823
2263
|
|
|
1824
2264
|
/**
|
|
@@ -1826,9 +2266,12 @@ class WebElement {
|
|
|
1826
2266
|
* @return {boolean} whether the object is a valid encoded WebElement ID.
|
|
1827
2267
|
*/
|
|
1828
2268
|
static isId(obj) {
|
|
1829
|
-
return
|
|
1830
|
-
|
|
1831
|
-
|
|
2269
|
+
return (
|
|
2270
|
+
obj &&
|
|
2271
|
+
typeof obj === 'object' &&
|
|
2272
|
+
(typeof obj[ELEMENT_ID_KEY] === 'string' ||
|
|
2273
|
+
typeof obj[LEGACY_ELEMENT_ID_KEY] === 'string')
|
|
2274
|
+
)
|
|
1832
2275
|
}
|
|
1833
2276
|
|
|
1834
2277
|
/**
|
|
@@ -1841,15 +2284,14 @@ class WebElement {
|
|
|
1841
2284
|
*/
|
|
1842
2285
|
static async equals(a, b) {
|
|
1843
2286
|
if (a === b) {
|
|
1844
|
-
return true
|
|
2287
|
+
return true
|
|
1845
2288
|
}
|
|
1846
|
-
return a.driver_.executeScript(
|
|
1847
|
-
'return arguments[0] === arguments[1]', a, b);
|
|
2289
|
+
return a.driver_.executeScript('return arguments[0] === arguments[1]', a, b)
|
|
1848
2290
|
}
|
|
1849
2291
|
|
|
1850
2292
|
/** @return {!WebDriver} The parent driver for this instance. */
|
|
1851
2293
|
getDriver() {
|
|
1852
|
-
return this.driver_
|
|
2294
|
+
return this.driver_
|
|
1853
2295
|
}
|
|
1854
2296
|
|
|
1855
2297
|
/**
|
|
@@ -1857,14 +2299,14 @@ class WebElement {
|
|
|
1857
2299
|
* the server-assigned opaque ID assigned to this element.
|
|
1858
2300
|
*/
|
|
1859
2301
|
getId() {
|
|
1860
|
-
return this.id_
|
|
2302
|
+
return this.id_
|
|
1861
2303
|
}
|
|
1862
2304
|
|
|
1863
2305
|
/**
|
|
1864
2306
|
* @return {!Object} Returns the serialized representation of this WebElement.
|
|
1865
2307
|
*/
|
|
1866
2308
|
[Symbols.serialize]() {
|
|
1867
|
-
return this.getId().then(WebElement.buildId)
|
|
2309
|
+
return this.getId().then(WebElement.buildId)
|
|
1868
2310
|
}
|
|
1869
2311
|
|
|
1870
2312
|
/**
|
|
@@ -1879,8 +2321,8 @@ class WebElement {
|
|
|
1879
2321
|
* @private
|
|
1880
2322
|
*/
|
|
1881
2323
|
execute_(command) {
|
|
1882
|
-
command.setParameter('id', this)
|
|
1883
|
-
return this.driver_.execute(command)
|
|
2324
|
+
command.setParameter('id', this)
|
|
2325
|
+
return this.driver_.execute(command)
|
|
1884
2326
|
}
|
|
1885
2327
|
|
|
1886
2328
|
/**
|
|
@@ -1918,18 +2360,17 @@ class WebElement {
|
|
|
1918
2360
|
* element will be invalidated and all scheduled commands aborted.
|
|
1919
2361
|
*/
|
|
1920
2362
|
findElement(locator) {
|
|
1921
|
-
locator = by.checkedLocator(locator)
|
|
1922
|
-
let id
|
|
2363
|
+
locator = by.checkedLocator(locator)
|
|
2364
|
+
let id
|
|
1923
2365
|
if (typeof locator === 'function') {
|
|
1924
|
-
id = this.driver_.findElementInternal_(locator, this)
|
|
2366
|
+
id = this.driver_.findElementInternal_(locator, this)
|
|
1925
2367
|
} else {
|
|
1926
|
-
let cmd = new command.Command(
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
id = this.execute_(cmd);
|
|
2368
|
+
let cmd = new command.Command(command.Name.FIND_CHILD_ELEMENT)
|
|
2369
|
+
.setParameter('using', locator.using)
|
|
2370
|
+
.setParameter('value', locator.value)
|
|
2371
|
+
id = this.execute_(cmd)
|
|
1931
2372
|
}
|
|
1932
|
-
return new WebElementPromise(this.driver_, id)
|
|
2373
|
+
return new WebElementPromise(this.driver_, id)
|
|
1933
2374
|
}
|
|
1934
2375
|
|
|
1935
2376
|
/**
|
|
@@ -1942,16 +2383,15 @@ class WebElement {
|
|
|
1942
2383
|
* array of WebElements.
|
|
1943
2384
|
*/
|
|
1944
2385
|
async findElements(locator) {
|
|
1945
|
-
locator = by.checkedLocator(locator)
|
|
1946
|
-
let id;
|
|
2386
|
+
locator = by.checkedLocator(locator)
|
|
1947
2387
|
if (typeof locator === 'function') {
|
|
1948
|
-
return this.driver_.findElementsInternal_(locator, this)
|
|
2388
|
+
return this.driver_.findElementsInternal_(locator, this)
|
|
1949
2389
|
} else {
|
|
1950
2390
|
let cmd = new command.Command(command.Name.FIND_CHILD_ELEMENTS)
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
let result = await this.execute_(cmd)
|
|
1954
|
-
return Array.isArray(result) ? result : []
|
|
2391
|
+
.setParameter('using', locator.using)
|
|
2392
|
+
.setParameter('value', locator.value)
|
|
2393
|
+
let result = await this.execute_(cmd)
|
|
2394
|
+
return Array.isArray(result) ? result : []
|
|
1955
2395
|
}
|
|
1956
2396
|
}
|
|
1957
2397
|
|
|
@@ -1962,7 +2402,7 @@ class WebElement {
|
|
|
1962
2402
|
* command has completed.
|
|
1963
2403
|
*/
|
|
1964
2404
|
click() {
|
|
1965
|
-
return this.execute_(new command.Command(command.Name.CLICK_ELEMENT))
|
|
2405
|
+
return this.execute_(new command.Command(command.Name.CLICK_ELEMENT))
|
|
1966
2406
|
}
|
|
1967
2407
|
|
|
1968
2408
|
/**
|
|
@@ -2021,34 +2461,37 @@ class WebElement {
|
|
|
2021
2461
|
* have been typed.
|
|
2022
2462
|
*/
|
|
2023
2463
|
async sendKeys(...args) {
|
|
2024
|
-
let keys = []
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2464
|
+
let keys = []
|
|
2465
|
+
; (await Promise.all(args)).forEach((key) => {
|
|
2466
|
+
let type = typeof key
|
|
2467
|
+
if (type === 'number') {
|
|
2468
|
+
key = String(key)
|
|
2469
|
+
} else if (type !== 'string') {
|
|
2470
|
+
throw TypeError('each key must be a number of string; got ' + type)
|
|
2471
|
+
}
|
|
2032
2472
|
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2473
|
+
// The W3C protocol requires keys to be specified as an array where
|
|
2474
|
+
// each element is a single key.
|
|
2475
|
+
keys.push(...key.split(''))
|
|
2476
|
+
})
|
|
2037
2477
|
|
|
2038
2478
|
if (!this.driver_.fileDetector_) {
|
|
2039
2479
|
return this.execute_(
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2480
|
+
new command.Command(command.Name.SEND_KEYS_TO_ELEMENT)
|
|
2481
|
+
.setParameter('text', keys.join(''))
|
|
2482
|
+
.setParameter('value', keys)
|
|
2483
|
+
)
|
|
2043
2484
|
}
|
|
2044
2485
|
|
|
2045
|
-
keys =
|
|
2046
|
-
|
|
2047
|
-
|
|
2486
|
+
keys = await this.driver_.fileDetector_.handleFile(
|
|
2487
|
+
this.driver_,
|
|
2488
|
+
keys.join('')
|
|
2489
|
+
)
|
|
2048
2490
|
return this.execute_(
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2491
|
+
new command.Command(command.Name.SEND_KEYS_TO_ELEMENT)
|
|
2492
|
+
.setParameter('text', keys)
|
|
2493
|
+
.setParameter('value', keys.split(''))
|
|
2494
|
+
)
|
|
2052
2495
|
}
|
|
2053
2496
|
|
|
2054
2497
|
/**
|
|
@@ -2058,8 +2501,7 @@ class WebElement {
|
|
|
2058
2501
|
* element's tag name.
|
|
2059
2502
|
*/
|
|
2060
2503
|
getTagName() {
|
|
2061
|
-
return this.execute_(
|
|
2062
|
-
new command.Command(command.Name.GET_ELEMENT_TAG_NAME));
|
|
2504
|
+
return this.execute_(new command.Command(command.Name.GET_ELEMENT_TAG_NAME))
|
|
2063
2505
|
}
|
|
2064
2506
|
|
|
2065
2507
|
/**
|
|
@@ -2077,10 +2519,10 @@ class WebElement {
|
|
|
2077
2519
|
* requested CSS value.
|
|
2078
2520
|
*/
|
|
2079
2521
|
getCssValue(cssStyleProperty) {
|
|
2080
|
-
var name = command.Name.GET_ELEMENT_VALUE_OF_CSS_PROPERTY
|
|
2522
|
+
var name = command.Name.GET_ELEMENT_VALUE_OF_CSS_PROPERTY
|
|
2081
2523
|
return this.execute_(
|
|
2082
|
-
|
|
2083
|
-
|
|
2524
|
+
new command.Command(name).setParameter('propertyName', cssStyleProperty)
|
|
2525
|
+
)
|
|
2084
2526
|
}
|
|
2085
2527
|
|
|
2086
2528
|
/**
|
|
@@ -2114,8 +2556,11 @@ class WebElement {
|
|
|
2114
2556
|
*/
|
|
2115
2557
|
getAttribute(attributeName) {
|
|
2116
2558
|
return this.execute_(
|
|
2117
|
-
|
|
2118
|
-
|
|
2559
|
+
new command.Command(command.Name.GET_ELEMENT_ATTRIBUTE).setParameter(
|
|
2560
|
+
'name',
|
|
2561
|
+
attributeName
|
|
2562
|
+
)
|
|
2563
|
+
)
|
|
2119
2564
|
}
|
|
2120
2565
|
|
|
2121
2566
|
/**
|
|
@@ -2126,7 +2571,11 @@ class WebElement {
|
|
|
2126
2571
|
*/
|
|
2127
2572
|
getProperty(propertyName) {
|
|
2128
2573
|
return this.execute_(
|
|
2129
|
-
|
|
2574
|
+
new command.Command(command.Name.GET_ELEMENT_PROPERTY).setParameter(
|
|
2575
|
+
'name',
|
|
2576
|
+
propertyName
|
|
2577
|
+
)
|
|
2578
|
+
)
|
|
2130
2579
|
}
|
|
2131
2580
|
|
|
2132
2581
|
/**
|
|
@@ -2137,9 +2586,28 @@ class WebElement {
|
|
|
2137
2586
|
* resolved with the element's visible text.
|
|
2138
2587
|
*/
|
|
2139
2588
|
getText() {
|
|
2140
|
-
return this.execute_(new command.Command(command.Name.GET_ELEMENT_TEXT))
|
|
2589
|
+
return this.execute_(new command.Command(command.Name.GET_ELEMENT_TEXT))
|
|
2590
|
+
}
|
|
2591
|
+
|
|
2592
|
+
/**
|
|
2593
|
+
* Get the computed WAI-ARIA role of element.
|
|
2594
|
+
*
|
|
2595
|
+
* @return {!Promise<string>} A promise that will be
|
|
2596
|
+
* resolved with the element's computed role.
|
|
2597
|
+
*/
|
|
2598
|
+
getAriaRole() {
|
|
2599
|
+
return this.execute_(new command.Command(command.Name.GET_COMPUTED_ROLE))
|
|
2141
2600
|
}
|
|
2142
2601
|
|
|
2602
|
+
/**
|
|
2603
|
+
* Get the computed WAI-ARIA label of element.
|
|
2604
|
+
*
|
|
2605
|
+
* @return {!Promise<string>} A promise that will be
|
|
2606
|
+
* resolved with the element's computed label.
|
|
2607
|
+
*/
|
|
2608
|
+
getAccessibleName() {
|
|
2609
|
+
return this.execute_(new command.Command(command.Name.GET_COMPUTED_LABEL))
|
|
2610
|
+
}
|
|
2143
2611
|
/**
|
|
2144
2612
|
* Returns an object describing an element's location, in pixels relative to
|
|
2145
2613
|
* the document element, and the element's size in pixels.
|
|
@@ -2150,16 +2618,17 @@ class WebElement {
|
|
|
2150
2618
|
async getRect() {
|
|
2151
2619
|
try {
|
|
2152
2620
|
return await this.execute_(
|
|
2153
|
-
|
|
2621
|
+
new command.Command(command.Name.GET_ELEMENT_RECT)
|
|
2622
|
+
)
|
|
2154
2623
|
} catch (err) {
|
|
2155
2624
|
if (err instanceof error.UnknownCommandError) {
|
|
2156
|
-
const {width, height} =
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
const {x, y} =
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
return {x, y, width, height}
|
|
2625
|
+
const { width, height } = await this.execute_(
|
|
2626
|
+
new command.Command(command.Name.GET_ELEMENT_SIZE)
|
|
2627
|
+
)
|
|
2628
|
+
const { x, y } = await this.execute_(
|
|
2629
|
+
new command.Command(command.Name.GET_ELEMENT_LOCATION)
|
|
2630
|
+
)
|
|
2631
|
+
return { x, y, width, height }
|
|
2163
2632
|
}
|
|
2164
2633
|
}
|
|
2165
2634
|
}
|
|
@@ -2172,7 +2641,7 @@ class WebElement {
|
|
|
2172
2641
|
* resolved with whether this element is currently enabled.
|
|
2173
2642
|
*/
|
|
2174
2643
|
isEnabled() {
|
|
2175
|
-
return this.execute_(new command.Command(command.Name.IS_ELEMENT_ENABLED))
|
|
2644
|
+
return this.execute_(new command.Command(command.Name.IS_ELEMENT_ENABLED))
|
|
2176
2645
|
}
|
|
2177
2646
|
|
|
2178
2647
|
/**
|
|
@@ -2182,8 +2651,7 @@ class WebElement {
|
|
|
2182
2651
|
* resolved with whether this element is currently selected.
|
|
2183
2652
|
*/
|
|
2184
2653
|
isSelected() {
|
|
2185
|
-
return this.execute_(
|
|
2186
|
-
new command.Command(command.Name.IS_ELEMENT_SELECTED));
|
|
2654
|
+
return this.execute_(new command.Command(command.Name.IS_ELEMENT_SELECTED))
|
|
2187
2655
|
}
|
|
2188
2656
|
|
|
2189
2657
|
/**
|
|
@@ -2195,7 +2663,7 @@ class WebElement {
|
|
|
2195
2663
|
* when the form has been submitted.
|
|
2196
2664
|
*/
|
|
2197
2665
|
submit() {
|
|
2198
|
-
return this.execute_(new command.Command(command.Name.SUBMIT_ELEMENT))
|
|
2666
|
+
return this.execute_(new command.Command(command.Name.SUBMIT_ELEMENT))
|
|
2199
2667
|
}
|
|
2200
2668
|
|
|
2201
2669
|
/**
|
|
@@ -2207,7 +2675,7 @@ class WebElement {
|
|
|
2207
2675
|
* when the element has been cleared.
|
|
2208
2676
|
*/
|
|
2209
2677
|
clear() {
|
|
2210
|
-
return this.execute_(new command.Command(command.Name.CLEAR_ELEMENT))
|
|
2678
|
+
return this.execute_(new command.Command(command.Name.CLEAR_ELEMENT))
|
|
2211
2679
|
}
|
|
2212
2680
|
|
|
2213
2681
|
/**
|
|
@@ -2217,8 +2685,7 @@ class WebElement {
|
|
|
2217
2685
|
* resolved with whether this element is currently visible on the page.
|
|
2218
2686
|
*/
|
|
2219
2687
|
isDisplayed() {
|
|
2220
|
-
return this.execute_(
|
|
2221
|
-
new command.Command(command.Name.IS_ELEMENT_DISPLAYED));
|
|
2688
|
+
return this.execute_(new command.Command(command.Name.IS_ELEMENT_DISPLAYED))
|
|
2222
2689
|
}
|
|
2223
2690
|
|
|
2224
2691
|
/**
|
|
@@ -2233,12 +2700,14 @@ class WebElement {
|
|
|
2233
2700
|
*/
|
|
2234
2701
|
takeScreenshot(scroll = false) {
|
|
2235
2702
|
return this.execute_(
|
|
2236
|
-
|
|
2237
|
-
|
|
2703
|
+
new command.Command(command.Name.TAKE_ELEMENT_SCREENSHOT).setParameter(
|
|
2704
|
+
'scroll',
|
|
2705
|
+
scroll
|
|
2706
|
+
)
|
|
2707
|
+
)
|
|
2238
2708
|
}
|
|
2239
2709
|
}
|
|
2240
2710
|
|
|
2241
|
-
|
|
2242
2711
|
/**
|
|
2243
2712
|
* WebElementPromise is a promise that will be fulfilled with a WebElement.
|
|
2244
2713
|
* This serves as a forward proxy on WebElement, allowing calls to be
|
|
@@ -2262,35 +2731,33 @@ class WebElementPromise extends WebElement {
|
|
|
2262
2731
|
* that will resolve to the promised element.
|
|
2263
2732
|
*/
|
|
2264
2733
|
constructor(driver, el) {
|
|
2265
|
-
super(driver, 'unused')
|
|
2734
|
+
super(driver, 'unused')
|
|
2266
2735
|
|
|
2267
2736
|
/** @override */
|
|
2268
|
-
this.then = el.then.bind(el)
|
|
2737
|
+
this.then = el.then.bind(el)
|
|
2269
2738
|
|
|
2270
2739
|
/** @override */
|
|
2271
|
-
this.catch = el.catch.bind(el)
|
|
2740
|
+
this.catch = el.catch.bind(el)
|
|
2272
2741
|
|
|
2273
2742
|
/**
|
|
2274
2743
|
* Defers returning the element ID until the wrapped WebElement has been
|
|
2275
2744
|
* resolved.
|
|
2276
2745
|
* @override
|
|
2277
2746
|
*/
|
|
2278
|
-
this.getId = function() {
|
|
2279
|
-
return el.then(function(el) {
|
|
2280
|
-
return el.getId()
|
|
2281
|
-
})
|
|
2282
|
-
}
|
|
2747
|
+
this.getId = function () {
|
|
2748
|
+
return el.then(function (el) {
|
|
2749
|
+
return el.getId()
|
|
2750
|
+
})
|
|
2751
|
+
}
|
|
2283
2752
|
}
|
|
2284
2753
|
}
|
|
2285
2754
|
|
|
2286
|
-
|
|
2287
2755
|
//////////////////////////////////////////////////////////////////////////////
|
|
2288
2756
|
//
|
|
2289
2757
|
// Alert
|
|
2290
2758
|
//
|
|
2291
2759
|
//////////////////////////////////////////////////////////////////////////////
|
|
2292
2760
|
|
|
2293
|
-
|
|
2294
2761
|
/**
|
|
2295
2762
|
* Represents a modal dialog such as {@code alert}, {@code confirm}, or
|
|
2296
2763
|
* {@code prompt}. Provides functions to retrieve the message displayed with
|
|
@@ -2305,10 +2772,10 @@ class Alert {
|
|
|
2305
2772
|
*/
|
|
2306
2773
|
constructor(driver, text) {
|
|
2307
2774
|
/** @private {!WebDriver} */
|
|
2308
|
-
this.driver_ = driver
|
|
2775
|
+
this.driver_ = driver
|
|
2309
2776
|
|
|
2310
2777
|
/** @private {!Promise<string>} */
|
|
2311
|
-
this.text_ = Promise.resolve(text)
|
|
2778
|
+
this.text_ = Promise.resolve(text)
|
|
2312
2779
|
}
|
|
2313
2780
|
|
|
2314
2781
|
/**
|
|
@@ -2319,7 +2786,7 @@ class Alert {
|
|
|
2319
2786
|
* resolved to the text displayed with this alert.
|
|
2320
2787
|
*/
|
|
2321
2788
|
getText() {
|
|
2322
|
-
return this.text_
|
|
2789
|
+
return this.text_
|
|
2323
2790
|
}
|
|
2324
2791
|
|
|
2325
2792
|
/**
|
|
@@ -2329,8 +2796,7 @@ class Alert {
|
|
|
2329
2796
|
* when this command has completed.
|
|
2330
2797
|
*/
|
|
2331
2798
|
accept() {
|
|
2332
|
-
return this.driver_.execute(
|
|
2333
|
-
new command.Command(command.Name.ACCEPT_ALERT));
|
|
2799
|
+
return this.driver_.execute(new command.Command(command.Name.ACCEPT_ALERT))
|
|
2334
2800
|
}
|
|
2335
2801
|
|
|
2336
2802
|
/**
|
|
@@ -2340,8 +2806,7 @@ class Alert {
|
|
|
2340
2806
|
* when this command has completed.
|
|
2341
2807
|
*/
|
|
2342
2808
|
dismiss() {
|
|
2343
|
-
return this.driver_.execute(
|
|
2344
|
-
new command.Command(command.Name.DISMISS_ALERT));
|
|
2809
|
+
return this.driver_.execute(new command.Command(command.Name.DISMISS_ALERT))
|
|
2345
2810
|
}
|
|
2346
2811
|
|
|
2347
2812
|
/**
|
|
@@ -2355,12 +2820,14 @@ class Alert {
|
|
|
2355
2820
|
*/
|
|
2356
2821
|
sendKeys(text) {
|
|
2357
2822
|
return this.driver_.execute(
|
|
2358
|
-
|
|
2359
|
-
|
|
2823
|
+
new command.Command(command.Name.SET_ALERT_TEXT).setParameter(
|
|
2824
|
+
'text',
|
|
2825
|
+
text
|
|
2826
|
+
)
|
|
2827
|
+
)
|
|
2360
2828
|
}
|
|
2361
2829
|
}
|
|
2362
2830
|
|
|
2363
|
-
|
|
2364
2831
|
/**
|
|
2365
2832
|
* AlertPromise is a promise that will be fulfilled with an Alert. This promise
|
|
2366
2833
|
* serves as a forward proxy on an Alert, allowing calls to be scheduled
|
|
@@ -2383,60 +2850,58 @@ class AlertPromise extends Alert {
|
|
|
2383
2850
|
* that will be fulfilled with the promised alert.
|
|
2384
2851
|
*/
|
|
2385
2852
|
constructor(driver, alert) {
|
|
2386
|
-
super(driver, 'unused')
|
|
2853
|
+
super(driver, 'unused')
|
|
2387
2854
|
|
|
2388
2855
|
/** @override */
|
|
2389
|
-
this.then = alert.then.bind(alert)
|
|
2856
|
+
this.then = alert.then.bind(alert)
|
|
2390
2857
|
|
|
2391
2858
|
/** @override */
|
|
2392
|
-
this.catch = alert.catch.bind(alert)
|
|
2859
|
+
this.catch = alert.catch.bind(alert)
|
|
2393
2860
|
|
|
2394
2861
|
/**
|
|
2395
2862
|
* Defer returning text until the promised alert has been resolved.
|
|
2396
2863
|
* @override
|
|
2397
2864
|
*/
|
|
2398
|
-
this.getText = function() {
|
|
2399
|
-
return alert.then(function(alert) {
|
|
2400
|
-
return alert.getText()
|
|
2401
|
-
})
|
|
2402
|
-
}
|
|
2865
|
+
this.getText = function () {
|
|
2866
|
+
return alert.then(function (alert) {
|
|
2867
|
+
return alert.getText()
|
|
2868
|
+
})
|
|
2869
|
+
}
|
|
2403
2870
|
|
|
2404
2871
|
/**
|
|
2405
2872
|
* Defers action until the alert has been located.
|
|
2406
2873
|
* @override
|
|
2407
2874
|
*/
|
|
2408
|
-
this.accept = function() {
|
|
2409
|
-
return alert.then(function(alert) {
|
|
2410
|
-
return alert.accept()
|
|
2411
|
-
})
|
|
2412
|
-
}
|
|
2875
|
+
this.accept = function () {
|
|
2876
|
+
return alert.then(function (alert) {
|
|
2877
|
+
return alert.accept()
|
|
2878
|
+
})
|
|
2879
|
+
}
|
|
2413
2880
|
|
|
2414
2881
|
/**
|
|
2415
2882
|
* Defers action until the alert has been located.
|
|
2416
2883
|
* @override
|
|
2417
2884
|
*/
|
|
2418
|
-
this.dismiss = function() {
|
|
2419
|
-
return alert.then(function(alert) {
|
|
2420
|
-
return alert.dismiss()
|
|
2421
|
-
})
|
|
2422
|
-
}
|
|
2885
|
+
this.dismiss = function () {
|
|
2886
|
+
return alert.then(function (alert) {
|
|
2887
|
+
return alert.dismiss()
|
|
2888
|
+
})
|
|
2889
|
+
}
|
|
2423
2890
|
|
|
2424
2891
|
/**
|
|
2425
2892
|
* Defers action until the alert has been located.
|
|
2426
2893
|
* @override
|
|
2427
2894
|
*/
|
|
2428
|
-
this.sendKeys = function(text) {
|
|
2429
|
-
return alert.then(function(alert) {
|
|
2430
|
-
return alert.sendKeys(text)
|
|
2431
|
-
})
|
|
2432
|
-
}
|
|
2895
|
+
this.sendKeys = function (text) {
|
|
2896
|
+
return alert.then(function (alert) {
|
|
2897
|
+
return alert.sendKeys(text)
|
|
2898
|
+
})
|
|
2899
|
+
}
|
|
2433
2900
|
}
|
|
2434
2901
|
}
|
|
2435
2902
|
|
|
2436
|
-
|
|
2437
2903
|
// PUBLIC API
|
|
2438
2904
|
|
|
2439
|
-
|
|
2440
2905
|
module.exports = {
|
|
2441
2906
|
Alert,
|
|
2442
2907
|
AlertPromise,
|
|
@@ -2450,5 +2915,5 @@ module.exports = {
|
|
|
2450
2915
|
WebElement,
|
|
2451
2916
|
WebElementCondition,
|
|
2452
2917
|
WebElementPromise,
|
|
2453
|
-
Window
|
|
2454
|
-
}
|
|
2918
|
+
Window,
|
|
2919
|
+
}
|