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/by.js
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
// specific language governing permissions and limitations
|
|
16
16
|
// under the License.
|
|
17
17
|
|
|
18
|
-
'use strict'
|
|
18
|
+
'use strict'
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* @fileoverview Factory methods for the supported locator strategies.
|
|
@@ -43,8 +43,7 @@
|
|
|
43
43
|
* {tagName: string}|
|
|
44
44
|
* {xpath: string})}
|
|
45
45
|
*/
|
|
46
|
-
var ByHash
|
|
47
|
-
|
|
46
|
+
var ByHash // eslint-disable-line
|
|
48
47
|
|
|
49
48
|
/**
|
|
50
49
|
* Error thrown if an invalid character is encountered while escaping a CSS
|
|
@@ -53,12 +52,11 @@ var ByHash;
|
|
|
53
52
|
*/
|
|
54
53
|
class InvalidCharacterError extends Error {
|
|
55
54
|
constructor() {
|
|
56
|
-
super()
|
|
57
|
-
this.name = this.constructor.name
|
|
55
|
+
super()
|
|
56
|
+
this.name = this.constructor.name
|
|
58
57
|
}
|
|
59
58
|
}
|
|
60
59
|
|
|
61
|
-
|
|
62
60
|
/**
|
|
63
61
|
* Escapes a CSS string.
|
|
64
62
|
* @param {string} css the string to escape.
|
|
@@ -69,46 +67,49 @@ class InvalidCharacterError extends Error {
|
|
|
69
67
|
*/
|
|
70
68
|
function escapeCss(css) {
|
|
71
69
|
if (typeof css !== 'string') {
|
|
72
|
-
throw new TypeError('input must be a string')
|
|
70
|
+
throw new TypeError('input must be a string')
|
|
73
71
|
}
|
|
74
|
-
let ret = ''
|
|
75
|
-
const n = css.length
|
|
76
|
-
for (let i = 0; i
|
|
77
|
-
const c = css.charCodeAt(i)
|
|
72
|
+
let ret = ''
|
|
73
|
+
const n = css.length
|
|
74
|
+
for (let i = 0; i < n; i++) {
|
|
75
|
+
const c = css.charCodeAt(i)
|
|
78
76
|
if (c == 0x0) {
|
|
79
|
-
throw new InvalidCharacterError()
|
|
77
|
+
throw new InvalidCharacterError()
|
|
80
78
|
}
|
|
81
79
|
|
|
82
|
-
if (
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
80
|
+
if (
|
|
81
|
+
(c >= 0x0001 && c <= 0x001f) ||
|
|
82
|
+
c == 0x007f ||
|
|
83
|
+
(i == 0 && c >= 0x0030 && c <= 0x0039) ||
|
|
84
|
+
(i == 1 && c >= 0x0030 && c <= 0x0039 && css.charCodeAt(0) == 0x002d)
|
|
85
|
+
) {
|
|
86
|
+
ret += '\\' + c.toString(16) + ' '
|
|
87
|
+
continue
|
|
89
88
|
}
|
|
90
89
|
|
|
91
|
-
if (i == 0 && c ==
|
|
92
|
-
ret += '\\' + css.charAt(i)
|
|
93
|
-
continue
|
|
90
|
+
if (i == 0 && c == 0x002d && n == 1) {
|
|
91
|
+
ret += '\\' + css.charAt(i)
|
|
92
|
+
continue
|
|
94
93
|
}
|
|
95
94
|
|
|
96
|
-
if (
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
95
|
+
if (
|
|
96
|
+
c >= 0x0080 ||
|
|
97
|
+
c == 0x002d || // -
|
|
98
|
+
c == 0x005f || // _
|
|
99
|
+
(c >= 0x0030 && c <= 0x0039) || // [0-9]
|
|
100
|
+
(c >= 0x0041 && c <= 0x005a) || // [A-Z]
|
|
101
|
+
(c >= 0x0061 && c <= 0x007a)
|
|
102
|
+
) {
|
|
103
|
+
// [a-z]
|
|
104
|
+
ret += css.charAt(i)
|
|
105
|
+
continue
|
|
104
106
|
}
|
|
105
107
|
|
|
106
|
-
ret += '\\' + css.charAt(i)
|
|
108
|
+
ret += '\\' + css.charAt(i)
|
|
107
109
|
}
|
|
108
|
-
return ret
|
|
110
|
+
return ret
|
|
109
111
|
}
|
|
110
112
|
|
|
111
|
-
|
|
112
113
|
/**
|
|
113
114
|
* Describes a mechanism for locating an element on the page.
|
|
114
115
|
* @final
|
|
@@ -120,10 +121,10 @@ class By {
|
|
|
120
121
|
*/
|
|
121
122
|
constructor(using, value) {
|
|
122
123
|
/** @type {string} */
|
|
123
|
-
this.using = using
|
|
124
|
+
this.using = using
|
|
124
125
|
|
|
125
126
|
/** @type {string} */
|
|
126
|
-
this.value = value
|
|
127
|
+
this.value = value
|
|
127
128
|
}
|
|
128
129
|
|
|
129
130
|
/**
|
|
@@ -135,10 +136,11 @@ class By {
|
|
|
135
136
|
* @see http://www.w3.org/TR/CSS2/selector.html#class-html
|
|
136
137
|
*/
|
|
137
138
|
static className(name) {
|
|
138
|
-
let names = name
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
139
|
+
let names = name
|
|
140
|
+
.split(/\s+/g)
|
|
141
|
+
.filter((s) => s.length > 0)
|
|
142
|
+
.map((s) => escapeCss(s))
|
|
143
|
+
return By.css('.' + names.join('.'))
|
|
142
144
|
}
|
|
143
145
|
|
|
144
146
|
/**
|
|
@@ -149,7 +151,7 @@ class By {
|
|
|
149
151
|
* @see http://www.w3.org/TR/CSS2/selector.html
|
|
150
152
|
*/
|
|
151
153
|
static css(selector) {
|
|
152
|
-
return new By('css selector', selector)
|
|
154
|
+
return new By('css selector', selector)
|
|
153
155
|
}
|
|
154
156
|
|
|
155
157
|
/**
|
|
@@ -160,7 +162,7 @@ class By {
|
|
|
160
162
|
* @return {!By} The new locator.
|
|
161
163
|
*/
|
|
162
164
|
static id(id) {
|
|
163
|
-
return By.css('*[id="' + escapeCss(id) + '"]')
|
|
165
|
+
return By.css('*[id="' + escapeCss(id) + '"]')
|
|
164
166
|
}
|
|
165
167
|
|
|
166
168
|
/**
|
|
@@ -172,7 +174,7 @@ class By {
|
|
|
172
174
|
* @return {!By} The new locator.
|
|
173
175
|
*/
|
|
174
176
|
static linkText(text) {
|
|
175
|
-
return new By('link text', text)
|
|
177
|
+
return new By('link text', text)
|
|
176
178
|
}
|
|
177
179
|
|
|
178
180
|
/**
|
|
@@ -188,11 +190,12 @@ class By {
|
|
|
188
190
|
* @return {function(!./webdriver.WebDriver): !Promise}
|
|
189
191
|
* A new JavaScript-based locator function.
|
|
190
192
|
*/
|
|
191
|
-
static js(script, var_args) {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
193
|
+
static js(script, var_args) { // eslint-disable-line
|
|
194
|
+
// eslint-disable-line
|
|
195
|
+
let args = Array.prototype.slice.call(arguments, 0)
|
|
196
|
+
return function (driver) {
|
|
197
|
+
return driver.executeScript.apply(driver, args)
|
|
198
|
+
}
|
|
196
199
|
}
|
|
197
200
|
|
|
198
201
|
/**
|
|
@@ -202,7 +205,7 @@ class By {
|
|
|
202
205
|
* @return {!By} The new locator.
|
|
203
206
|
*/
|
|
204
207
|
static name(name) {
|
|
205
|
-
return By.css('*[name="' + escapeCss(name) + '"]')
|
|
208
|
+
return By.css('*[name="' + escapeCss(name) + '"]')
|
|
206
209
|
}
|
|
207
210
|
|
|
208
211
|
/**
|
|
@@ -214,7 +217,7 @@ class By {
|
|
|
214
217
|
* @return {!By} The new locator.
|
|
215
218
|
*/
|
|
216
219
|
static partialLinkText(text) {
|
|
217
|
-
return new By('partial link text', text)
|
|
220
|
+
return new By('partial link text', text)
|
|
218
221
|
}
|
|
219
222
|
|
|
220
223
|
/**
|
|
@@ -222,10 +225,9 @@ class By {
|
|
|
222
225
|
*
|
|
223
226
|
* @param {string} name The tag name to search for.
|
|
224
227
|
* @return {!By} The new locator.
|
|
225
|
-
* @deprecated Use {@link By.css() By.css(tagName)} instead.
|
|
226
228
|
*/
|
|
227
229
|
static tagName(name) {
|
|
228
|
-
return By.css(name)
|
|
230
|
+
return By.css(name)
|
|
229
231
|
}
|
|
230
232
|
|
|
231
233
|
/**
|
|
@@ -240,16 +242,136 @@ class By {
|
|
|
240
242
|
* @see http://www.w3.org/TR/xpath/
|
|
241
243
|
*/
|
|
242
244
|
static xpath(xpath) {
|
|
243
|
-
return new By('xpath', xpath)
|
|
245
|
+
return new By('xpath', xpath)
|
|
244
246
|
}
|
|
245
247
|
|
|
246
248
|
/** @override */
|
|
247
249
|
toString() {
|
|
248
250
|
// The static By.name() overrides this.constructor.name. Shame...
|
|
249
|
-
return `By(${this.using}, ${this.value})
|
|
251
|
+
return `By(${this.using}, ${this.value})`
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
toObject() {
|
|
255
|
+
const tmp = {}
|
|
256
|
+
tmp[this.using] = this.value
|
|
257
|
+
return tmp
|
|
250
258
|
}
|
|
251
259
|
}
|
|
252
260
|
|
|
261
|
+
function withTagName(tagName) {
|
|
262
|
+
return new RelativeBy(tagName)
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Describes a mechanism for locating an element relative to others
|
|
267
|
+
* on the page.
|
|
268
|
+
* @final
|
|
269
|
+
*/
|
|
270
|
+
class RelativeBy {
|
|
271
|
+
/**
|
|
272
|
+
* @param {string} tagName
|
|
273
|
+
* @param {Array<Object>} filters
|
|
274
|
+
*/
|
|
275
|
+
constructor(tagName, filters = null) {
|
|
276
|
+
this.root = tagName
|
|
277
|
+
this.filters = filters || []
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Look for elements above the root element passed in
|
|
282
|
+
* @param {string|WebElement} locatorOrElement
|
|
283
|
+
* @return {!RelativeBy} Return this object
|
|
284
|
+
*/
|
|
285
|
+
above(locatorOrElement) {
|
|
286
|
+
this.filters.push({
|
|
287
|
+
kind: 'above',
|
|
288
|
+
args: [this.getLocator(locatorOrElement)],
|
|
289
|
+
})
|
|
290
|
+
return this
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Look for elements below the root element passed in
|
|
295
|
+
* @param {string|WebElement} locatorOrElement
|
|
296
|
+
* @return {!RelativeBy} Return this object
|
|
297
|
+
*/
|
|
298
|
+
below(locatorOrElement) {
|
|
299
|
+
this.filters.push({
|
|
300
|
+
kind: 'below',
|
|
301
|
+
args: [this.getLocator(locatorOrElement)],
|
|
302
|
+
})
|
|
303
|
+
return this
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Look for elements left the root element passed in
|
|
308
|
+
* @param {string|WebElement} locatorOrElement
|
|
309
|
+
* @return {!RelativeBy} Return this object
|
|
310
|
+
*/
|
|
311
|
+
toLeftOf(locatorOrElement) {
|
|
312
|
+
this.filters.push({
|
|
313
|
+
kind: 'left',
|
|
314
|
+
args: [this.getLocator(locatorOrElement)],
|
|
315
|
+
})
|
|
316
|
+
return this
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Look for elements right the root element passed in
|
|
321
|
+
* @param {string|WebElement} locatorOrElement
|
|
322
|
+
* @return {!RelativeBy} Return this object
|
|
323
|
+
*/
|
|
324
|
+
toRightOf(locatorOrElement) {
|
|
325
|
+
this.filters.push({
|
|
326
|
+
kind: 'right',
|
|
327
|
+
args: [this.getLocator(locatorOrElement)],
|
|
328
|
+
})
|
|
329
|
+
return this
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Look for elements near the root element passed in
|
|
334
|
+
* @param {string|WebElement} locatorOrElement
|
|
335
|
+
* @return {!RelativeBy} Return this object
|
|
336
|
+
*/
|
|
337
|
+
near(locatorOrElement) {
|
|
338
|
+
this.filters.push({
|
|
339
|
+
kind: 'near',
|
|
340
|
+
args: [this.getLocator(locatorOrElement)],
|
|
341
|
+
})
|
|
342
|
+
return this
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Returns a marshalled version of the {@link RelativeBy}
|
|
347
|
+
* @return {!Object} Object representation of a {@link WebElement}
|
|
348
|
+
* that will be used in {@link #findElements}.
|
|
349
|
+
*/
|
|
350
|
+
marshall() {
|
|
351
|
+
return {
|
|
352
|
+
relative: {
|
|
353
|
+
root: { 'css selector': this.root },
|
|
354
|
+
filters: this.filters,
|
|
355
|
+
},
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
getLocator(locatorOrElement) {
|
|
360
|
+
let toFind
|
|
361
|
+
if (locatorOrElement instanceof By) {
|
|
362
|
+
toFind = locatorOrElement.toObject()
|
|
363
|
+
} else {
|
|
364
|
+
toFind = locatorOrElement
|
|
365
|
+
}
|
|
366
|
+
return toFind
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/** @override */
|
|
370
|
+
toString() {
|
|
371
|
+
// The static By.name() overrides this.constructor.name. Shame...
|
|
372
|
+
return `RelativeBy(${JSON.stringify(this.marshall())})`
|
|
373
|
+
}
|
|
374
|
+
}
|
|
253
375
|
|
|
254
376
|
/**
|
|
255
377
|
* Checks if a value is a valid locator.
|
|
@@ -260,29 +382,34 @@ class By {
|
|
|
260
382
|
*/
|
|
261
383
|
function check(locator) {
|
|
262
384
|
if (locator instanceof By || typeof locator === 'function') {
|
|
263
|
-
return locator
|
|
385
|
+
return locator
|
|
264
386
|
}
|
|
265
387
|
|
|
266
|
-
if (
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
388
|
+
if (
|
|
389
|
+
locator &&
|
|
390
|
+
typeof locator === 'object' &&
|
|
391
|
+
typeof locator.using === 'string' &&
|
|
392
|
+
typeof locator.value === 'string'
|
|
393
|
+
) {
|
|
394
|
+
return new By(locator.using, locator.value)
|
|
271
395
|
}
|
|
272
396
|
|
|
273
397
|
for (let key in locator) {
|
|
274
|
-
if (
|
|
275
|
-
|
|
398
|
+
if (
|
|
399
|
+
Object.prototype.hasOwnProperty.call(locator, key) &&
|
|
400
|
+
Object.prototype.hasOwnProperty.call(By, key)
|
|
401
|
+
) {
|
|
402
|
+
return By[key](locator[key])
|
|
276
403
|
}
|
|
277
404
|
}
|
|
278
|
-
throw new TypeError('Invalid locator')
|
|
405
|
+
throw new TypeError('Invalid locator')
|
|
279
406
|
}
|
|
280
407
|
|
|
281
|
-
|
|
282
|
-
|
|
283
408
|
// PUBLIC API
|
|
284
409
|
|
|
285
410
|
module.exports = {
|
|
286
411
|
By: By,
|
|
412
|
+
RelativeBy: RelativeBy,
|
|
413
|
+
withTagName: withTagName,
|
|
287
414
|
checkedLocator: check,
|
|
288
|
-
}
|
|
415
|
+
}
|