selenium-webdriver 3.6.0 → 4.0.0-alpha.1

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.
Files changed (97) hide show
  1. package/CHANGES.md +181 -0
  2. package/README.md +25 -27
  3. package/chrome.js +113 -127
  4. package/edge.js +42 -117
  5. package/example/chrome_android.js +8 -8
  6. package/example/chrome_mobile_emulation.js +8 -8
  7. package/example/firefox_channels.js +22 -18
  8. package/example/google_search_test.js +39 -26
  9. package/example/logging.js +39 -6
  10. package/firefox.js +769 -0
  11. package/http/index.js +41 -4
  12. package/http/util.js +11 -6
  13. package/ie.js +56 -97
  14. package/index.js +178 -114
  15. package/jasmine.json +11 -0
  16. package/lib/actions.js +68 -63
  17. package/lib/by.js +1 -1
  18. package/lib/capabilities.js +255 -192
  19. package/lib/command.js +26 -50
  20. package/lib/error.js +85 -44
  21. package/lib/http.js +133 -110
  22. package/lib/input.js +1044 -8
  23. package/lib/promise.js +222 -3323
  24. package/lib/proxy.js +134 -39
  25. package/lib/test/bootstrap_jasmine.js +28 -0
  26. package/lib/test/data/actions/click.html +24 -0
  27. package/lib/test/data/actions/drag.html +77 -0
  28. package/lib/test/data/actions/record_click.html +21 -0
  29. package/lib/test/data/chrome/download.html +2 -0
  30. package/lib/test/data/inputs.html +42 -0
  31. package/lib/test/data/selectPage.html +12 -0
  32. package/lib/test/data/simpleTest.html +5 -0
  33. package/lib/test/data/upload_invisible.html +45 -0
  34. package/lib/test/fileserver.js +23 -19
  35. package/lib/test/index.js +30 -212
  36. package/lib/test/resources.js +0 -1
  37. package/lib/webdriver.js +675 -936
  38. package/net/index.js +21 -25
  39. package/net/portprober.js +51 -68
  40. package/package.json +5 -3
  41. package/remote/index.js +5 -19
  42. package/safari.js +41 -128
  43. package/test/actions_test.js +173 -18
  44. package/test/{session_test.js → builder_test.js} +44 -37
  45. package/test/chrome/devtools_test.js +93 -0
  46. package/test/chrome/options_test.js +48 -154
  47. package/test/chrome/service_test.js +7 -7
  48. package/test/cookie_test.js +77 -63
  49. package/test/element_finding_test.js +206 -201
  50. package/test/execute_script_test.js +115 -114
  51. package/test/fingerprint_test.js +16 -15
  52. package/test/firefox_test.js +251 -0
  53. package/test/http/http_test.js +0 -1
  54. package/test/http/util_test.js +2 -2
  55. package/test/io/zip_test.js +6 -7
  56. package/test/lib/error_test.js +34 -7
  57. package/test/lib/http_test.js +8 -128
  58. package/test/lib/input_test.js +1379 -0
  59. package/test/lib/promise_test.js +473 -908
  60. package/test/lib/webdriver_test.js +296 -868
  61. package/test/logging_test.js +37 -43
  62. package/test/page_loading_test.js +71 -81
  63. package/test/proxy_test.js +64 -72
  64. package/test/rect_test.js +14 -25
  65. package/test/remote_test.js +10 -29
  66. package/test/safari_test.js +7 -71
  67. package/test/stale_element_test.js +20 -23
  68. package/test/tag_name_test.js +10 -9
  69. package/test/upload_test.js +27 -35
  70. package/test/window_test.js +72 -85
  71. package/testing/index.js +386 -314
  72. package/.npmignore +0 -2
  73. package/example/async_await_test.js +0 -69
  74. package/example/google_search_generator.js +0 -47
  75. package/example/parallel_flows.js +0 -51
  76. package/firefox/binary.js +0 -347
  77. package/firefox/extension.js +0 -224
  78. package/firefox/index.js +0 -576
  79. package/firefox/profile.js +0 -311
  80. package/lib/events.js +0 -210
  81. package/lib/test/data/firefox/jetpack-sample.xpi +0 -0
  82. package/lib/test/data/firefox/sample.xpi +0 -0
  83. package/lib/test/promise.js +0 -79
  84. package/opera.js +0 -405
  85. package/phantomjs.js +0 -282
  86. package/test/firefox/extension_test.js +0 -120
  87. package/test/firefox/firefox_test.js +0 -244
  88. package/test/firefox/profile_test.js +0 -140
  89. package/test/lib/events_test.js +0 -177
  90. package/test/lib/promise_aplus_test.js +0 -78
  91. package/test/lib/promise_error_test.js +0 -884
  92. package/test/lib/promise_flow_test.js +0 -2288
  93. package/test/lib/promise_generator_test.js +0 -310
  94. package/test/phantomjs/execute_phantomjs_test.js +0 -59
  95. package/test/testing/assert_test.js +0 -373
  96. package/test/testing/index_test.js +0 -224
  97. package/testing/assert.js +0 -378
package/http/index.js CHANGED
@@ -144,8 +144,9 @@ class HttpClient {
144
144
  * @param {function(!Error)} onError The function to call if the request fails.
145
145
  * @param {?string=} opt_data The data to send with the request.
146
146
  * @param {?RequestOptions=} opt_proxy The proxy server to use for the request.
147
+ * @param {number=} opt_retries The current number of retries.
147
148
  */
148
- function sendRequest(options, onOk, onError, opt_data, opt_proxy) {
149
+ function sendRequest(options, onOk, onError, opt_data, opt_proxy, opt_retries) {
149
150
  var hostname = options.hostname;
150
151
  var port = options.port;
151
152
 
@@ -161,7 +162,7 @@ function sendRequest(options, onOk, onError, opt_data, opt_proxy) {
161
162
  // An HTTP/1.1 proxy MUST ensure that any request message it forwards does
162
163
  // contain an appropriate Host header field that identifies the service
163
164
  // being requested by the proxy.
164
- let targetHost = options.hostname
165
+ let targetHost = options.hostname;
165
166
  if (options.port) {
166
167
  targetHost += ':' + options.port;
167
168
  }
@@ -226,9 +227,14 @@ function sendRequest(options, onOk, onError, opt_data, opt_proxy) {
226
227
  });
227
228
 
228
229
  request.on('error', function(e) {
229
- if (e.code === 'ECONNRESET') {
230
+ if (typeof opt_retries === 'undefined') {
231
+ opt_retries = 0;
232
+ }
233
+
234
+ if (shouldRetryRequest(opt_retries, e)) {
235
+ opt_retries += 1;
230
236
  setTimeout(function() {
231
- sendRequest(options, onOk, onError, opt_data, opt_proxy);
237
+ sendRequest(options, onOk, onError, opt_data, opt_proxy, opt_retries);
232
238
  }, 15);
233
239
  } else {
234
240
  var message = e.message;
@@ -247,6 +253,37 @@ function sendRequest(options, onOk, onError, opt_data, opt_proxy) {
247
253
  }
248
254
 
249
255
 
256
+ const MAX_RETRIES = 3;
257
+
258
+ /**
259
+ * A retry is sometimes needed on Windows where we may quickly run out of
260
+ * ephemeral ports. A more robust solution is bumping the MaxUserPort setting
261
+ * as described here: http://msdn.microsoft.com/en-us/library/aa560610%28v=bts.20%29.aspx
262
+ *
263
+ * @param {!number} retries
264
+ * @param {!Error} err
265
+ * @return {boolean}
266
+ */
267
+ function shouldRetryRequest(retries, err) {
268
+ return retries < MAX_RETRIES && isRetryableNetworkError(err);
269
+ }
270
+
271
+ /**
272
+ * @param {!Error} err
273
+ * @return {boolean}
274
+ */
275
+ function isRetryableNetworkError(err) {
276
+ if (err && err.code) {
277
+ return err.code === 'ECONNABORTED' ||
278
+ err.code === 'ECONNRESET' ||
279
+ err.code === 'EADDRINUSE' ||
280
+ err.code === 'EPIPE';
281
+ }
282
+
283
+ return false;
284
+ }
285
+
286
+
250
287
  // PUBLIC API
251
288
 
252
289
  exports.Executor = httpLib.Executor;
package/http/util.js CHANGED
@@ -26,8 +26,7 @@ const Executor = require('./index').Executor,
26
26
  HttpRequest = require('./index').Request,
27
27
  Command = require('../lib/command').Command,
28
28
  CommandName = require('../lib/command').Name,
29
- error = require('../lib/error'),
30
- promise = require('../lib/promise');
29
+ error = require('../lib/error');
31
30
 
32
31
 
33
32
 
@@ -45,6 +44,9 @@ function getStatus(url) {
45
44
  }
46
45
 
47
46
 
47
+ class CancellationError {}
48
+
49
+
48
50
  // PUBLIC API
49
51
 
50
52
 
@@ -57,13 +59,16 @@ function getStatus(url) {
57
59
  exports.getStatus = getStatus;
58
60
 
59
61
 
62
+ exports.CancellationError = CancellationError;
63
+
64
+
60
65
  /**
61
66
  * Waits for a WebDriver server to be healthy and accepting requests.
62
67
  * @param {string} url Base URL of the server to query.
63
68
  * @param {number} timeout How long to wait for the server.
64
69
  * @param {Promise=} opt_cancelToken A promise used as a cancellation signal:
65
70
  * if resolved before the server is ready, the wait will be terminated
66
- * early with a {@link promise.CancellationError}.
71
+ * early with a {@link CancellationError}.
67
72
  * @return {!Promise} A promise that will resolve when the server is ready, or
68
73
  * if the wait is cancelled.
69
74
  */
@@ -82,7 +87,7 @@ exports.waitForServer = function(url, timeout, opt_cancelToken) {
82
87
  };
83
88
 
84
89
  if (opt_cancelToken) {
85
- opt_cancelToken.then(_ => reject(new promise.CancellationError));
90
+ opt_cancelToken.then(_ => reject(new CancellationError));
86
91
  }
87
92
 
88
93
  checkServerStatus();
@@ -119,7 +124,7 @@ exports.waitForServer = function(url, timeout, opt_cancelToken) {
119
124
  * @param {number} timeout How long to wait, in milliseconds.
120
125
  * @param {Promise=} opt_cancelToken A promise used as a cancellation signal:
121
126
  * if resolved before the a 2xx response is received, the wait will be
122
- * terminated early with a {@link promise.CancellationError}.
127
+ * terminated early with a {@link CancellationError}.
123
128
  * @return {!Promise} A promise that will resolve when a 2xx is received from
124
129
  * the given URL, or if the wait is cancelled.
125
130
  */
@@ -140,7 +145,7 @@ exports.waitForUrl = function(url, timeout, opt_cancelToken) {
140
145
  };
141
146
 
142
147
  if (opt_cancelToken) {
143
- opt_cancelToken.then(_ => reject(new promise.CancellationError));
148
+ opt_cancelToken.then(_ => reject(new CancellationError));
144
149
  }
145
150
 
146
151
  testUrl();
package/ie.js CHANGED
@@ -27,16 +27,16 @@
27
27
 
28
28
  'use strict';
29
29
 
30
- const fs = require('fs'),
31
- util = require('util');
30
+ const fs = require('fs');
31
+ const util = require('util');
32
32
 
33
- const http = require('./http'),
34
- io = require('./io'),
35
- capabilities = require('./lib/capabilities'),
36
- promise = require('./lib/promise'),
37
- webdriver = require('./lib/webdriver'),
38
- portprober = require('./net/portprober'),
39
- remote = require('./remote');
33
+ const http = require('./http');
34
+ const io = require('./io');
35
+ const portprober = require('./net/portprober');
36
+ const promise = require('./lib/promise');
37
+ const remote = require('./remote');
38
+ const webdriver = require('./lib/webdriver');
39
+ const {Browser, Capabilities, Capability} = require('./lib/capabilities');
40
40
 
41
41
 
42
42
  const IEDRIVER_EXE = 'IEDriverServer.exe';
@@ -86,37 +86,14 @@ const Key = {
86
86
  /**
87
87
  * Class for managing IEDriver specific options.
88
88
  */
89
- class Options {
90
- constructor() {
91
- /** @private {!Object<(boolean|number|string|!Array<string>)>} */
92
- this.options_ = {};
93
-
94
- /** @private {(capabilities.ProxyConfig|null)} */
95
- this.proxy_ = null;
96
- }
97
-
89
+ class Options extends Capabilities {
98
90
  /**
99
- * Extracts the IEDriver specific options from the given capabilities
100
- * object.
101
- * @param {!capabilities.Capabilities} caps The capabilities object.
102
- * @return {!Options} The IEDriver options.
91
+ * @param {(Capabilities|Map<string, ?>|Object)=} other Another set of
92
+ * capabilities to initialize this instance from.
103
93
  */
104
- static fromCapabilities(caps) {
105
- var options = new Options();
106
- var map = options.options_;
107
-
108
- Object.keys(Key).forEach(function(key) {
109
- key = Key[key];
110
- if (caps.has(key)) {
111
- map[key] = caps.get(key);
112
- }
113
- });
114
-
115
- if (caps.has(capabilities.Capability.PROXY)) {
116
- options.setProxy(caps.get(capabilities.Capability.PROXY));
117
- }
118
-
119
- return options;
94
+ constructor(other = undefined) {
95
+ super(other);
96
+ this.setBrowserName(Browser.IE);
120
97
  }
121
98
 
122
99
  /**
@@ -132,7 +109,7 @@ class Options {
132
109
  * @return {!Options} A self reference.
133
110
  */
134
111
  introduceFlakinessByIgnoringProtectedModeSettings(ignoreSettings) {
135
- this.options_[Key.IGNORE_PROTECTED_MODE_SETTINGS] = !!ignoreSettings;
112
+ this.set(Key.IGNORE_PROTECTED_MODE_SETTINGS, !!ignoreSettings);
136
113
  return this;
137
114
  }
138
115
 
@@ -144,7 +121,7 @@ class Options {
144
121
  * @return {!Options} A self reference.
145
122
  */
146
123
  ignoreZoomSetting(ignore) {
147
- this.options_[Key.IGNORE_ZOOM_SETTING] = !!ignore;
124
+ this.set(Key.IGNORE_ZOOM_SETTING, !!ignore);
148
125
  return this;
149
126
  }
150
127
 
@@ -159,7 +136,7 @@ class Options {
159
136
  * @return {!Options} A self reference.
160
137
  */
161
138
  initialBrowserUrl(url) {
162
- this.options_[Key.INITIAL_BROWSER_URL] = url;
139
+ this.set(Key.INITIAL_BROWSER_URL, url);
163
140
  return this;
164
141
  }
165
142
 
@@ -172,7 +149,7 @@ class Options {
172
149
  * @return {!Options} A self reference.
173
150
  */
174
151
  enablePersistentHover(enable) {
175
- this.options_[Key.ENABLE_PERSISTENT_HOVER] = !!enable;
152
+ this.set(Key.ENABLE_PERSISTENT_HOVER, !!enable);
176
153
  return this;
177
154
  }
178
155
 
@@ -186,7 +163,7 @@ class Options {
186
163
  * @return {!Options} A self reference.
187
164
  */
188
165
  enableElementCacheCleanup(enable) {
189
- this.options_[Key.ENABLE_ELEMENT_CACHE_CLEANUP] = !!enable;
166
+ this.set(Key.ENABLE_ELEMENT_CACHE_CLEANUP, !!enable);
190
167
  return this;
191
168
  }
192
169
 
@@ -200,7 +177,7 @@ class Options {
200
177
  * @return {!Options} A self reference.
201
178
  */
202
179
  requireWindowFocus(require) {
203
- this.options_[Key.REQUIRE_WINDOW_FOCUS] = !!require;
180
+ this.set(Key.REQUIRE_WINDOW_FOCUS, !!require);
204
181
  return this;
205
182
  }
206
183
 
@@ -213,7 +190,7 @@ class Options {
213
190
  * @return {!Options} A self reference.
214
191
  */
215
192
  browserAttachTimeout(timeout) {
216
- this.options_[Key.BROWSER_ATTACH_TIMEOUT] = Math.max(timeout, 0);
193
+ this.set(Key.BROWSER_ATTACH_TIMEOUT, Math.max(timeout, 0));
217
194
  return this;
218
195
  }
219
196
 
@@ -227,7 +204,7 @@ class Options {
227
204
  * @return {!Options} A self reference.
228
205
  */
229
206
  forceCreateProcessApi(force) {
230
- this.options_[Key.FORCE_CREATE_PROCESS] = !!force;
207
+ this.set(Key.FORCE_CREATE_PROCESS, !!force);
231
208
  return this;
232
209
  }
233
210
 
@@ -235,13 +212,14 @@ class Options {
235
212
  * Specifies command-line switches to use when launching Internet Explorer.
236
213
  * This is only valid when used with {@link #forceCreateProcessApi}.
237
214
  *
238
- * @param {...(string|!Array.<string>)} var_args The arguments to add.
215
+ * @param {...(string|!Array.<string>)} args The arguments to add.
239
216
  * @return {!Options} A self reference.
240
217
  */
241
- addArguments(var_args) {
242
- var args = this.options_[Key.BROWSER_COMMAND_LINE_SWITCHES] || [];
243
- args = args.concat.apply(args, arguments);
244
- this.options_[Key.BROWSER_COMMAND_LINE_SWITCHES] = args;
218
+ addArguments(...args) {
219
+ let current = this.get(Key.BROWSER_COMMAND_LINE_SWITCHES) || [];
220
+ this.set(
221
+ Key.BROWSER_COMMAND_LINE_SWITCHES,
222
+ current.concat.apply(current, args));
245
223
  return this;
246
224
  }
247
225
 
@@ -254,7 +232,7 @@ class Options {
254
232
  * @return {!Options} A self reference.
255
233
  */
256
234
  usePerProcessProxy(enable) {
257
- this.options_[Key.USE_PER_PROCESS_PROXY] = !!enable;
235
+ this.set(Key.USE_PER_PROCESS_PROXY, !!enable);
258
236
  return this;
259
237
  }
260
238
 
@@ -268,7 +246,7 @@ class Options {
268
246
  * @return {!Options} A self reference.
269
247
  */
270
248
  ensureCleanSession(cleanSession) {
271
- this.options_[Key.ENSURE_CLEAN_SESSION] = !!cleanSession;
249
+ this.set(Key.ENSURE_CLEAN_SESSION, !!cleanSession);
272
250
  return this;
273
251
  }
274
252
 
@@ -278,7 +256,7 @@ class Options {
278
256
  * @return {!Options} A self reference.
279
257
  */
280
258
  setLogFile(file) {
281
- this.options_[Key.LOG_FILE] = file;
259
+ this.set(Key.LOG_FILE, file);
282
260
  return this;
283
261
  }
284
262
 
@@ -288,7 +266,7 @@ class Options {
288
266
  * @return {!Options} A self reference.
289
267
  */
290
268
  setLogLevel(level) {
291
- this.options_[Key.LOG_LEVEL] = level;
269
+ this.set(Key.LOG_LEVEL, level);
292
270
  return this;
293
271
  }
294
272
 
@@ -298,7 +276,7 @@ class Options {
298
276
  * @return {!Options} A self reference.
299
277
  */
300
278
  setHost(host) {
301
- this.options_[Key.HOST] = host;
279
+ this.set(Key.HOST, host);
302
280
  return this;
303
281
  }
304
282
 
@@ -308,7 +286,7 @@ class Options {
308
286
  * @return {!Options} A self reference.
309
287
  */
310
288
  setExtractPath(path) {
311
- this.options_[Key.EXTRACT_PATH] = path;
289
+ this.set(Key.EXTRACT_PATH, path);
312
290
  return this;
313
291
  }
314
292
 
@@ -318,37 +296,21 @@ class Options {
318
296
  * @return {!Options} A self reference.
319
297
  */
320
298
  silent(silent) {
321
- this.options_[Key.SILENT] = silent;
299
+ this.set(Key.SILENT, silent);
322
300
  return this;
323
301
  }
302
+ }
324
303
 
325
- /**
326
- * Sets the proxy settings for the new session.
327
- * @param {capabilities.ProxyConfig} proxy The proxy configuration to use.
328
- * @return {!Options} A self reference.
329
- */
330
- setProxy(proxy) {
331
- this.proxy_ = proxy;
332
- return this;
333
- }
334
304
 
335
- /**
336
- * Converts this options instance to a {@link capabilities.Capabilities}
337
- * object.
338
- * @param {capabilities.Capabilities=} opt_capabilities The capabilities to
339
- * merge these options into, if any.
340
- * @return {!capabilities.Capabilities} The capabilities.
341
- */
342
- toCapabilities(opt_capabilities) {
343
- var caps = opt_capabilities || capabilities.Capabilities.ie();
344
- if (this.proxy_) {
345
- caps.set(capabilities.Capability.PROXY, this.proxy_);
346
- }
347
- Object.keys(this.options_).forEach(function(key) {
348
- caps.set(key, this.options_[key]);
349
- }, this);
350
- return caps;
351
- }
305
+ /**
306
+ * _Synchronously_ attempts to locate the IE driver executable on the current
307
+ * system.
308
+ *
309
+ * @return {?string} the located executable, or `null`.
310
+ */
311
+ function locateSynchronously() {
312
+ return process.platform === 'win32'
313
+ ? io.findInPath(IEDRIVER_EXE, true) : null;
352
314
  }
353
315
 
354
316
 
@@ -360,7 +322,7 @@ function createServiceFromCapabilities(capabilities) {
360
322
  'WebDriver server?');
361
323
  }
362
324
 
363
- let exe = io.findInPath(IEDRIVER_EXE, true);
325
+ let exe = locateSynchronously();
364
326
  if (!exe || !fs.existsSync(exe)) {
365
327
  throw Error(
366
328
  `${IEDRIVER_EXE} could not be found on the current PATH. Please ` +
@@ -405,23 +367,18 @@ class Driver extends webdriver.WebDriver {
405
367
  /**
406
368
  * Creates a new session for Microsoft's Internet Explorer.
407
369
  *
408
- * @param {(capabilities.Capabilities|Options)=} opt_config The configuration
409
- * options.
410
- * @param {promise.ControlFlow=} opt_flow The control flow to use,
411
- * or {@code null} to use the currently active flow.
370
+ * @param {(Capabilities|Options)=} options The configuration options.
412
371
  * @return {!Driver} A new driver instance.
413
372
  */
414
- static createSession(opt_config, opt_flow) {
415
- var caps = opt_config instanceof Options ?
416
- opt_config.toCapabilities() :
417
- (opt_config || capabilities.Capabilities.ie());
373
+ static createSession(options) {
374
+ options = options || new Options();
418
375
 
419
- var service = createServiceFromCapabilities(caps);
420
- var client = service.start().then(url => new http.HttpClient(url));
421
- var executor = new http.Executor(client);
376
+ let service = createServiceFromCapabilities(options);
377
+ let client = service.start().then(url => new http.HttpClient(url));
378
+ let executor = new http.Executor(client);
422
379
 
423
380
  return /** @type {!Driver} */(super.createSession(
424
- executor, caps, opt_flow, () => service.kill()));
381
+ executor, options, () => service.kill()));
425
382
  }
426
383
 
427
384
  /**
@@ -439,3 +396,5 @@ class Driver extends webdriver.WebDriver {
439
396
  exports.Driver = Driver;
440
397
  exports.Options = Options;
441
398
  exports.Level = Level;
399
+ exports.locateSynchronously = locateSynchronously;
400
+