selenium-webdriver 4.0.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGES.md +18 -1
- package/chrome.js +4 -3
- package/chromium.js +43 -21
- package/devtools/CDPConnection.js +9 -4
- package/devtools/networkinterceptor.js +60 -61
- package/http/index.js +13 -14
- package/http/util.js +14 -20
- package/index.js +11 -11
- package/io/exec.js +1 -2
- package/io/index.js +47 -46
- package/lib/atoms/find-elements.js +2 -2
- package/lib/by.js +4 -5
- package/lib/capabilities.js +1 -1
- package/lib/command.js +5 -0
- package/lib/error.js +24 -0
- package/lib/http.js +10 -6
- package/lib/until.js +16 -14
- package/lib/webdriver.js +287 -97
- package/net/portprober.js +1 -1
- package/package.json +1 -2
- package/remote/index.js +1 -1
- package/safari.js +3 -3
- package/testing/index.js +11 -13
package/io/index.js
CHANGED
|
@@ -19,7 +19,6 @@
|
|
|
19
19
|
|
|
20
20
|
const fs = require('fs')
|
|
21
21
|
const path = require('path')
|
|
22
|
-
const rimraf = require('rimraf')
|
|
23
22
|
const tmp = require('tmp')
|
|
24
23
|
|
|
25
24
|
/**
|
|
@@ -52,24 +51,16 @@ function checkedCall(fn) {
|
|
|
52
51
|
* @return {!Promise} A promise to be resolved when the operation has
|
|
53
52
|
* completed.
|
|
54
53
|
*/
|
|
55
|
-
|
|
54
|
+
function rmDir(dirPath) {
|
|
56
55
|
return new Promise(function (fulfill, reject) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
return
|
|
66
|
-
}
|
|
67
|
-
reject(err)
|
|
68
|
-
} else {
|
|
69
|
-
fulfill()
|
|
70
|
-
}
|
|
71
|
-
})
|
|
72
|
-
}
|
|
56
|
+
fs.rm(dirPath, { recursive: true, maxRetries: 2 }, function (err) {
|
|
57
|
+
if (err && err.code === 'ENOENT') {
|
|
58
|
+
fulfill()
|
|
59
|
+
} else if (err) {
|
|
60
|
+
reject(err)
|
|
61
|
+
}
|
|
62
|
+
fulfill()
|
|
63
|
+
})
|
|
73
64
|
})
|
|
74
65
|
}
|
|
75
66
|
|
|
@@ -79,12 +70,12 @@ exports.rmDir = function (dirPath) {
|
|
|
79
70
|
* @param {string} dst The destination file.
|
|
80
71
|
* @return {!Promise<string>} A promise for the copied file's path.
|
|
81
72
|
*/
|
|
82
|
-
|
|
73
|
+
function copy(src, dst) {
|
|
83
74
|
return new Promise(function (fulfill, reject) {
|
|
84
|
-
|
|
75
|
+
const rs = fs.createReadStream(src)
|
|
85
76
|
rs.on('error', reject)
|
|
86
77
|
|
|
87
|
-
|
|
78
|
+
const ws = fs.createWriteStream(dst)
|
|
88
79
|
ws.on('error', reject)
|
|
89
80
|
ws.on('close', () => fulfill(dst))
|
|
90
81
|
|
|
@@ -102,20 +93,19 @@ exports.copy = function (src, dst) {
|
|
|
102
93
|
* @return {!Promise<string>} A promise for the destination
|
|
103
94
|
* directory's path once all files have been copied.
|
|
104
95
|
*/
|
|
105
|
-
|
|
106
|
-
|
|
96
|
+
function copyDir(src, dst, opt_exclude) {
|
|
97
|
+
let predicate = opt_exclude
|
|
107
98
|
if (opt_exclude && typeof opt_exclude !== 'function') {
|
|
108
99
|
predicate = function (p) {
|
|
109
100
|
return !opt_exclude.test(p)
|
|
110
101
|
}
|
|
111
102
|
}
|
|
112
103
|
|
|
113
|
-
// TODO(jleyba): Make this function completely async.
|
|
114
104
|
if (!fs.existsSync(dst)) {
|
|
115
105
|
fs.mkdirSync(dst)
|
|
116
106
|
}
|
|
117
107
|
|
|
118
|
-
|
|
108
|
+
let files = fs.readdirSync(src)
|
|
119
109
|
files = files.map(function (file) {
|
|
120
110
|
return path.join(src, file)
|
|
121
111
|
})
|
|
@@ -153,8 +143,7 @@ exports.exists = function (aPath) {
|
|
|
153
143
|
if (type !== 'string') {
|
|
154
144
|
reject(TypeError(`expected string path, but got ${type}`))
|
|
155
145
|
} else {
|
|
156
|
-
|
|
157
|
-
fs.exists(aPath, fulfill)
|
|
146
|
+
fulfill(fs.existsSync(aPath))
|
|
158
147
|
}
|
|
159
148
|
})
|
|
160
149
|
}
|
|
@@ -174,18 +163,16 @@ exports.stat = function stat(aPath) {
|
|
|
174
163
|
* @param {string} aPath The path to remove.
|
|
175
164
|
* @return {!Promise} A promise for when the file has been removed.
|
|
176
165
|
*/
|
|
177
|
-
|
|
166
|
+
function unlink(aPath) {
|
|
178
167
|
return new Promise(function (fulfill, reject) {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
}
|
|
188
|
-
})
|
|
168
|
+
const exists = fs.existsSync(aPath)
|
|
169
|
+
if (exists) {
|
|
170
|
+
fs.unlink(aPath, function (err) {
|
|
171
|
+
;(err && reject(err)) || fulfill()
|
|
172
|
+
})
|
|
173
|
+
} else {
|
|
174
|
+
fulfill()
|
|
175
|
+
}
|
|
189
176
|
})
|
|
190
177
|
}
|
|
191
178
|
|
|
@@ -193,7 +180,7 @@ exports.unlink = function (aPath) {
|
|
|
193
180
|
* @return {!Promise<string>} A promise for the path to a temporary directory.
|
|
194
181
|
* @see https://www.npmjs.org/package/tmp
|
|
195
182
|
*/
|
|
196
|
-
|
|
183
|
+
function tmpDir() {
|
|
197
184
|
return checkedCall((callback) => tmp.dir({ unsafeCleanup: true }, callback))
|
|
198
185
|
}
|
|
199
186
|
|
|
@@ -202,7 +189,7 @@ exports.tmpDir = function () {
|
|
|
202
189
|
* @return {!Promise<string>} A promise for the path to a temporary file.
|
|
203
190
|
* @see https://www.npmjs.org/package/tmp
|
|
204
191
|
*/
|
|
205
|
-
|
|
192
|
+
function tmpFile(opt_options) {
|
|
206
193
|
return checkedCall((callback) => {
|
|
207
194
|
/** check fixed in v > 0.2.1 if
|
|
208
195
|
* (typeof options === 'function') {
|
|
@@ -222,7 +209,7 @@ exports.tmpFile = function (opt_options) {
|
|
|
222
209
|
* @return {?string} Path to the located file, or {@code null} if it could
|
|
223
210
|
* not be found.
|
|
224
211
|
*/
|
|
225
|
-
|
|
212
|
+
function findInPath(file, opt_checkCwd) {
|
|
226
213
|
const dirs = []
|
|
227
214
|
if (opt_checkCwd) {
|
|
228
215
|
dirs.push(process.cwd())
|
|
@@ -249,7 +236,7 @@ exports.findInPath = function (file, opt_checkCwd) {
|
|
|
249
236
|
* @return {!Promise<!Buffer>} A promise that will resolve with a buffer of the
|
|
250
237
|
* file contents.
|
|
251
238
|
*/
|
|
252
|
-
|
|
239
|
+
function read(aPath) {
|
|
253
240
|
return checkedCall((callback) => fs.readFile(aPath, callback))
|
|
254
241
|
}
|
|
255
242
|
|
|
@@ -261,7 +248,7 @@ exports.read = function (aPath) {
|
|
|
261
248
|
* @return {!Promise} A promise that will resolve when the operation has
|
|
262
249
|
* completed.
|
|
263
250
|
*/
|
|
264
|
-
|
|
251
|
+
function write(aPath, data) {
|
|
265
252
|
return checkedCall((callback) => fs.writeFile(aPath, data, callback))
|
|
266
253
|
}
|
|
267
254
|
|
|
@@ -272,7 +259,7 @@ exports.write = function (aPath, data) {
|
|
|
272
259
|
* @return {!Promise<string>} A promise that will resolve with the path of the
|
|
273
260
|
* created directory.
|
|
274
261
|
*/
|
|
275
|
-
|
|
262
|
+
function mkdir(aPath) {
|
|
276
263
|
return checkedCall((callback) => {
|
|
277
264
|
fs.mkdir(aPath, undefined, (err) => {
|
|
278
265
|
if (err && err.code !== 'EEXIST') {
|
|
@@ -291,7 +278,7 @@ exports.mkdir = function (aPath) {
|
|
|
291
278
|
* @return {!Promise<string>} A promise that will resolve with the path of the
|
|
292
279
|
* created directory.
|
|
293
280
|
*/
|
|
294
|
-
|
|
281
|
+
function mkdirp(dir) {
|
|
295
282
|
return checkedCall((callback) => {
|
|
296
283
|
fs.mkdir(dir, undefined, (err) => {
|
|
297
284
|
if (!err) {
|
|
@@ -327,7 +314,7 @@ exports.mkdirp = function mkdirp(dir) {
|
|
|
327
314
|
* resolve with a list of entries seen. For each entry, the recorded path
|
|
328
315
|
* will be relative to `rootPath`.
|
|
329
316
|
*/
|
|
330
|
-
|
|
317
|
+
function walkDir(rootPath) {
|
|
331
318
|
const seen = []
|
|
332
319
|
return (function walk(dir) {
|
|
333
320
|
return checkedCall((callback) => fs.readdir(dir, callback)).then((files) =>
|
|
@@ -346,3 +333,17 @@ exports.walkDir = function (rootPath) {
|
|
|
346
333
|
)
|
|
347
334
|
})(rootPath).then(() => seen)
|
|
348
335
|
}
|
|
336
|
+
|
|
337
|
+
// PUBLIC API
|
|
338
|
+
module.exports.walkDir = walkDir
|
|
339
|
+
module.exports.rmDir = rmDir
|
|
340
|
+
module.exports.mkdirp = mkdirp
|
|
341
|
+
module.exports.mkdir = mkdir
|
|
342
|
+
module.exports.write = write
|
|
343
|
+
module.exports.read = read
|
|
344
|
+
module.exports.findInPath = findInPath
|
|
345
|
+
module.exports.tmpFile = tmpFile
|
|
346
|
+
module.exports.tmpDir = tmpDir
|
|
347
|
+
module.exports.unlink = unlink
|
|
348
|
+
module.exports.copy = copy
|
|
349
|
+
module.exports.copyDir = copyDir
|
|
@@ -109,8 +109,8 @@ function gd(a){var b=a.shape.toLowerCase();a=a.coords.split(",");if("rect"==b&&4
|
|
|
109
109
|
function hd(a){return a.replace(/^[^\S\xa0]+|[^\S\xa0]+$/g,"")}function id(a){var b=[];Yc?jd(a,b):kd(a,b);a=qa(b,hd);return hd(a.join("\n")).replace(/\xa0/g," ")}
|
|
110
110
|
function ld(a,b,c){if(S(a,"BR"))b.push("");else{var d=S(a,"TD"),e=V(a,"display"),f=!d&&!(0<=oa(md,e)),g=void 0!==a.previousElementSibling?a.previousElementSibling:gb(a.previousSibling);g=g?V(g,"display"):"";var h=V(a,"float")||V(a,"cssFloat")||V(a,"styleFloat");!f||"run-in"==g&&"none"==h||/^[\s\xa0]*$/.test(b[b.length-1]||"")||b.push("");var n=ed(a),u=null,p=null;n&&(u=V(a,"white-space"),p=V(a,"text-transform"));l(a.childNodes,function(G){c(G,b,n,u,p)});a=b[b.length-1]||"";!d&&"table-cell"!=e||!a||
|
|
111
111
|
za(a)||(b[b.length-1]+=" ");f&&"run-in"!=e&&!/^[\s\xa0]*$/.test(a)&&b.push("")}}function kd(a,b){ld(a,b,function(c,d,e,f,g){3==c.nodeType&&e?nd(c,d,f,g):S(c)&&kd(c,d)})}var md="inline inline-block inline-table none table-cell table-column table-column-group".split(" ");
|
|
112
|
-
function nd(a,b,c,d){a=a.nodeValue.replace(/[\u200b\u200e\u200f]/g,"");a=a.replace(/(\r\n|\r|\n)/g,"\n");if("normal"==c||"nowrap"==c)a=a.replace(/\n/g," ");a="pre"==c||"pre-wrap"==c?a.replace(/[ \f\t\v\u2028\u2029]/g,"\u00a0"):a.replace(/[ \f\t\v\u2028\u2029]+/g," ");"capitalize"==d?a=a.replace(/(^|[^\d\p{L}\p{S}])([\p{Ll}|\p{S}])/gu,function(e,f,g){return f+g.toUpperCase()}):"uppercase"==d?a=a.toUpperCase():"lowercase"==d&&(a=a.toLowerCase());c=b.pop()||"";za(c)&&0==a.lastIndexOf(" ",
|
|
113
|
-
b.push(c+a)}function dd(a){if(Mc){if("relative"==V(a,"position"))return 1;a=V(a,"filter");return(a=a.match(/^alpha\(opacity=(\d*)\)/)||a.match(/^progid:DXImageTransform.Microsoft.Alpha\(Opacity=(\d*)\)/))?Number(a[1])/100:1}return od(a)}function od(a){var b=1,c=V(a,"opacity");c&&(b=Number(c));(a=Zc(a))&&(b*=od(a));return b}
|
|
112
|
+
function nd(a,b,c,d){a=a.nodeValue.replace(/[\u200b\u200e\u200f]/g,"");a=a.replace(/(\r\n|\r|\n)/g,"\n");if("normal"==c||"nowrap"==c)a=a.replace(/\n/g," ");a="pre"==c||"pre-wrap"==c?a.replace(/[ \f\t\v\u2028\u2029]/g,"\u00a0"):a.replace(/[ \f\t\v\u2028\u2029]+/g," ");"capitalize"==d?a=a.replace(t?/(^|\s|\b)(\S)/g:/(^|[^\d\p{L}\p{S}])([\p{Ll}|\p{S}])/gu,function(e,f,g){return f+g.toUpperCase()}):"uppercase"==d?a=a.toUpperCase():"lowercase"==d&&(a=a.toLowerCase());c=b.pop()||"";za(c)&&0==a.lastIndexOf(" ",
|
|
113
|
+
0)&&(a=a.substr(1));b.push(c+a)}function dd(a){if(Mc){if("relative"==V(a,"position"))return 1;a=V(a,"filter");return(a=a.match(/^alpha\(opacity=(\d*)\)/)||a.match(/^progid:DXImageTransform.Microsoft.Alpha\(Opacity=(\d*)\)/))?Number(a[1])/100:1}return od(a)}function od(a){var b=1,c=V(a,"opacity");c&&(b=Number(c));(a=Zc(a))&&(b*=od(a));return b}
|
|
114
114
|
function pd(a,b,c,d,e){if(3==a.nodeType&&c)nd(a,b,d,e);else if(S(a))if(S(a,"CONTENT")||S(a,"SLOT")){for(var f=a;f.parentNode;)f=f.parentNode;f instanceof ShadowRoot?(a=S(a,"CONTENT")?a.getDistributedNodes():a.assignedNodes(),l(a,function(g){pd(g,b,c,d,e)})):jd(a,b)}else if(S(a,"SHADOW")){for(f=a;f.parentNode;)f=f.parentNode;if(f instanceof ShadowRoot&&(a=f))for(a=a.olderShadowRoot;a;)l(a.childNodes,function(g){pd(g,b,c,d,e)}),a=a.olderShadowRoot}else jd(a,b)}
|
|
115
115
|
function jd(a,b){a.shadowRoot&&l(a.shadowRoot.childNodes,function(c){pd(c,b,!0,null,null)});ld(a,b,function(c,d,e,f,g){var h=null;1==c.nodeType?h=c:3==c.nodeType&&(h=c);null!=h&&(null!=h.assignedSlot||h.getDestinationInsertionPoints&&0<h.getDestinationInsertionPoints().length)||pd(c,d,e,f,g)})};var qd={C:function(a,b){return!(!a.querySelectorAll||!a.querySelector)&&!/^\d.*/.test(b)},o:function(a,b){var c=eb(b),d="string"===typeof a?c.a.getElementById(a):a;return d?Uc(d,"id")==a&&b!=d&&hb(b,d)?d:ua(mb(c,"*"),function(e){return Uc(e,"id")==a&&b!=e&&hb(b,e)}):null},j:function(a,b){if(!a)return[];if(qd.C(b,a))try{return b.querySelectorAll("#"+qd.T(a))}catch(c){return[]}b=mb(eb(b),"*",null,b);return pa(b,function(c){return Uc(c,"id")==a})},T:function(a){return a.replace(/([\s'"\\#.:;,!?+<>=~*^$|%&@`{}\-\/\[\]\(\)])/g,
|
|
116
116
|
"\\$1")}};var Y={},rd={};Y.N=function(a,b,c){try{var d=Nc.j("a",b)}catch(e){d=mb(eb(b),"A",null,b)}return ua(d,function(e){e=id(e);e=e.replace(/^[\s]+|[\s]+$/g,"");return c&&-1!=e.indexOf(a)||e==a})};Y.K=function(a,b,c){try{var d=Nc.j("a",b)}catch(e){d=mb(eb(b),"A",null,b)}return pa(d,function(e){e=id(e);e=e.replace(/^[\s]+|[\s]+$/g,"");return c&&-1!=e.indexOf(a)||e==a})};Y.o=function(a,b){return Y.N(a,b,!1)};Y.j=function(a,b){return Y.K(a,b,!1)};rd.o=function(a,b){return Y.N(a,b,!0)};
|
package/lib/by.js
CHANGED
|
@@ -190,11 +190,9 @@ class By {
|
|
|
190
190
|
* @return {function(!./webdriver.WebDriver): !Promise}
|
|
191
191
|
* A new JavaScript-based locator function.
|
|
192
192
|
*/
|
|
193
|
-
static js(script, var_args) {
|
|
194
|
-
// eslint-disable-line
|
|
195
|
-
let args = Array.prototype.slice.call(arguments, 0)
|
|
193
|
+
static js(script, ...var_args) {
|
|
196
194
|
return function (driver) {
|
|
197
|
-
return driver.executeScript.
|
|
195
|
+
return driver.executeScript.call(driver, script, ...var_args)
|
|
198
196
|
}
|
|
199
197
|
}
|
|
200
198
|
|
|
@@ -277,7 +275,7 @@ function withTagName(tagName) {
|
|
|
277
275
|
* @returns {RelativeBy}
|
|
278
276
|
*/
|
|
279
277
|
function locateWith(by) {
|
|
280
|
-
return new RelativeBy(getLocator(by))
|
|
278
|
+
return new RelativeBy(getLocator(by))
|
|
281
279
|
}
|
|
282
280
|
|
|
283
281
|
function getLocator(locatorOrElement) {
|
|
@@ -431,4 +429,5 @@ module.exports = {
|
|
|
431
429
|
withTagName: withTagName,
|
|
432
430
|
locateWith: locateWith,
|
|
433
431
|
checkedLocator: check,
|
|
432
|
+
escapeCss: escapeCss
|
|
434
433
|
}
|
package/lib/capabilities.js
CHANGED
package/lib/command.js
CHANGED
|
@@ -168,6 +168,11 @@ const Name = {
|
|
|
168
168
|
GET_ALERT_TEXT: 'getAlertText',
|
|
169
169
|
SET_ALERT_TEXT: 'setAlertValue',
|
|
170
170
|
|
|
171
|
+
// Shadow DOM Commands
|
|
172
|
+
GET_SHADOW_ROOT: 'getShadowRoot',
|
|
173
|
+
FIND_ELEMENT_FROM_SHADOWROOT: 'findElementFromShadowRoot',
|
|
174
|
+
FIND_ELEMENTS_FROM_SHADOWROOT: 'findElementsFromShadowRoot',
|
|
175
|
+
|
|
171
176
|
GET_AVAILABLE_LOG_TYPES: 'getAvailableLogTypes',
|
|
172
177
|
GET_LOG: 'getLog',
|
|
173
178
|
GET_SESSION_LOGS: 'getSessionLogs',
|
package/lib/error.js
CHANGED
|
@@ -39,6 +39,16 @@ class WebDriverError extends Error {
|
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Indicates the shadow root is no longer attached to the DOM
|
|
44
|
+
*/
|
|
45
|
+
class DetachedShadowRootError extends WebDriverError {
|
|
46
|
+
/** @param {string=} opt_error the error message, if any. */
|
|
47
|
+
constructor(opt_error) {
|
|
48
|
+
super(opt_error)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
42
52
|
/**
|
|
43
53
|
* Indicates a {@linkplain ./webdriver.WebElement#click click command} could not
|
|
44
54
|
* completed because the click target is obscured by other elements on the
|
|
@@ -201,6 +211,16 @@ class NoSuchElementError extends WebDriverError {
|
|
|
201
211
|
}
|
|
202
212
|
}
|
|
203
213
|
|
|
214
|
+
/**
|
|
215
|
+
* A ShadowRoot could not be located on the element
|
|
216
|
+
*/
|
|
217
|
+
class NoSuchShadowRootError extends WebDriverError {
|
|
218
|
+
/** @param {string=} opt_error the error message, if any. */
|
|
219
|
+
constructor(opt_error) {
|
|
220
|
+
super(opt_error);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
204
224
|
/**
|
|
205
225
|
* A request to switch to a frame could not be satisfied because the frame
|
|
206
226
|
* could not be found.
|
|
@@ -420,6 +440,7 @@ const LEGACY_ERROR_CODE_TO_TYPE = new Map([
|
|
|
420
440
|
|
|
421
441
|
const ERROR_CODE_TO_TYPE = new Map([
|
|
422
442
|
['unknown error', WebDriverError],
|
|
443
|
+
['detached shadow root', DetachedShadowRootError],
|
|
423
444
|
['element click intercepted', ElementClickInterceptedError],
|
|
424
445
|
['element not interactable', ElementNotInteractableError],
|
|
425
446
|
['element not selectable', ElementNotSelectableError],
|
|
@@ -436,6 +457,7 @@ const ERROR_CODE_TO_TYPE = new Map([
|
|
|
436
457
|
['no such cookie', NoSuchCookieError],
|
|
437
458
|
['no such element', NoSuchElementError],
|
|
438
459
|
['no such frame', NoSuchFrameError],
|
|
460
|
+
['no such shadow root', NoSuchShadowRootError],
|
|
439
461
|
['no such window', NoSuchWindowError],
|
|
440
462
|
['script timeout', ScriptTimeoutError],
|
|
441
463
|
['session not created', SessionNotCreatedError],
|
|
@@ -569,6 +591,7 @@ module.exports = {
|
|
|
569
591
|
ErrorCode,
|
|
570
592
|
|
|
571
593
|
WebDriverError,
|
|
594
|
+
DetachedShadowRootError,
|
|
572
595
|
ElementClickInterceptedError,
|
|
573
596
|
ElementNotInteractableError,
|
|
574
597
|
ElementNotSelectableError,
|
|
@@ -584,6 +607,7 @@ module.exports = {
|
|
|
584
607
|
NoSuchCookieError,
|
|
585
608
|
NoSuchElementError,
|
|
586
609
|
NoSuchFrameError,
|
|
610
|
+
NoSuchShadowRootError,
|
|
587
611
|
NoSuchSessionError,
|
|
588
612
|
NoSuchWindowError,
|
|
589
613
|
ScriptTimeoutError,
|
package/lib/http.js
CHANGED
|
@@ -31,7 +31,7 @@ const error = require('./error')
|
|
|
31
31
|
const logging = require('./logging')
|
|
32
32
|
const promise = require('./promise')
|
|
33
33
|
const { Session } = require('./session')
|
|
34
|
-
const { WebElement } = require('./webdriver')
|
|
34
|
+
const { WebElement, ShadowRoot } = require('./webdriver')
|
|
35
35
|
|
|
36
36
|
const getAttribute = requireAtom(
|
|
37
37
|
'get-attribute.js',
|
|
@@ -63,8 +63,8 @@ function requireAtom(module, bazelTarget) {
|
|
|
63
63
|
console.log(ex2)
|
|
64
64
|
throw Error(
|
|
65
65
|
`Failed to import atoms module ${module}. If running in dev mode, you` +
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
` need to run \`bazel build ${bazelTarget}\` from the project` +
|
|
67
|
+
`root: ${ex}`
|
|
68
68
|
)
|
|
69
69
|
}
|
|
70
70
|
}
|
|
@@ -173,7 +173,7 @@ var CommandSpec // eslint-disable-line
|
|
|
173
173
|
/** @typedef {function(!cmd.Command): !cmd.Command} */
|
|
174
174
|
var CommandTransformer // eslint-disable-line
|
|
175
175
|
|
|
176
|
-
class InternalTypeError extends TypeError {}
|
|
176
|
+
class InternalTypeError extends TypeError { }
|
|
177
177
|
|
|
178
178
|
/**
|
|
179
179
|
* @param {!cmd.Command} command The initial command.
|
|
@@ -421,6 +421,10 @@ const W3C_COMMAND_MAP = new Map([
|
|
|
421
421
|
],
|
|
422
422
|
// print page.
|
|
423
423
|
[cmd.Name.PRINT_PAGE, post('/session/:sessionId/print')],
|
|
424
|
+
// Shadow Root
|
|
425
|
+
[cmd.Name.GET_SHADOW_ROOT, get('/session/:sessionId/element/:id/shadow')],
|
|
426
|
+
[cmd.Name.FIND_ELEMENT_FROM_SHADOWROOT, post('/session/:sessionId/shadow/:id/element')],
|
|
427
|
+
[cmd.Name.FIND_ELEMENTS_FROM_SHADOWROOT, post('/session/:sessionId/shadow/:id/elements')],
|
|
424
428
|
// Log extensions.
|
|
425
429
|
[cmd.Name.GET_LOG, post('/session/:sessionId/se/log')],
|
|
426
430
|
[cmd.Name.GET_AVAILABLE_LOG_TYPES, get('/session/:sessionId/se/log/types')],
|
|
@@ -441,7 +445,7 @@ class Client {
|
|
|
441
445
|
* @return {!Promise<Response>} A promise that will be fulfilled with the
|
|
442
446
|
* server's response.
|
|
443
447
|
*/
|
|
444
|
-
send(httpRequest) {} // eslint-disable-line
|
|
448
|
+
send(httpRequest) { } // eslint-disable-line
|
|
445
449
|
}
|
|
446
450
|
|
|
447
451
|
/**
|
|
@@ -584,7 +588,7 @@ class Executor {
|
|
|
584
588
|
// No implementations use the `capabilities` key yet...
|
|
585
589
|
let capabilities = value.capabilities || value.value
|
|
586
590
|
return new Session(
|
|
587
|
-
/** @type {{sessionId: string}} */
|
|
591
|
+
/** @type {{sessionId: string}} */(value).sessionId,
|
|
588
592
|
capabilities
|
|
589
593
|
)
|
|
590
594
|
}
|
package/lib/until.js
CHANGED
|
@@ -137,13 +137,14 @@ exports.alertIsPresent = function alertIsPresent() {
|
|
|
137
137
|
* @return {!Condition<boolean>} The new condition.
|
|
138
138
|
*/
|
|
139
139
|
exports.titleIs = function titleIs(title) {
|
|
140
|
-
return new Condition(
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
140
|
+
return new Condition(
|
|
141
|
+
'for title to be ' + JSON.stringify(title),
|
|
142
|
+
function (driver) {
|
|
143
|
+
return driver.getTitle().then(function (t) {
|
|
144
|
+
return t === title
|
|
145
|
+
})
|
|
146
|
+
}
|
|
147
|
+
)
|
|
147
148
|
}
|
|
148
149
|
|
|
149
150
|
/**
|
|
@@ -188,13 +189,14 @@ exports.titleMatches = function titleMatches(regex) {
|
|
|
188
189
|
* @return {!Condition<boolean>} The new condition.
|
|
189
190
|
*/
|
|
190
191
|
exports.urlIs = function urlIs(url) {
|
|
191
|
-
return new Condition(
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
192
|
+
return new Condition(
|
|
193
|
+
'for URL to be ' + JSON.stringify(url),
|
|
194
|
+
function (driver) {
|
|
195
|
+
return driver.getCurrentUrl().then(function (u) {
|
|
196
|
+
return u === url
|
|
197
|
+
})
|
|
198
|
+
}
|
|
199
|
+
)
|
|
198
200
|
}
|
|
199
201
|
|
|
200
202
|
/**
|