selenium-webdriver 3.0.1 → 3.5.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.
Files changed (67) hide show
  1. package/CHANGES.md +92 -0
  2. package/NOTICE +1 -1
  3. package/README.md +11 -14
  4. package/chrome.js +125 -36
  5. package/edge.js +3 -3
  6. package/example/async_await_test.js +68 -0
  7. package/example/chrome_headless.js +47 -0
  8. package/example/chrome_mobile_emulation.js +1 -1
  9. package/example/firefox_channels.js +73 -0
  10. package/example/google_search_test.js +1 -1
  11. package/firefox/binary.js +114 -57
  12. package/firefox/extension.js +118 -81
  13. package/firefox/index.js +67 -135
  14. package/firefox/profile.js +13 -49
  15. package/ie.js +2 -2
  16. package/index.js +6 -3
  17. package/io/index.js +59 -0
  18. package/io/zip.js +214 -0
  19. package/lib/README +2 -3
  20. package/lib/actions.js +4 -4
  21. package/lib/atoms/getAttribute.js +9 -11
  22. package/lib/atoms/is-displayed.js +102 -0
  23. package/lib/by.js +9 -1
  24. package/lib/capabilities.js +5 -5
  25. package/lib/command.js +2 -0
  26. package/lib/error.js +29 -4
  27. package/lib/events.js +1 -1
  28. package/lib/firefox/webdriver.json +2 -1
  29. package/lib/http.js +84 -69
  30. package/lib/input.js +1 -1
  31. package/lib/promise.js +205 -81
  32. package/lib/symbols.js +1 -1
  33. package/lib/test/data/click_tests/disabled_element.html +12 -0
  34. package/lib/test/data/firefox/webextension.xpi +0 -0
  35. package/lib/test/data/key_logger.html +34 -0
  36. package/lib/test/data/nestedElements.html +10 -1
  37. package/lib/test/data/single_text_input.html +12 -0
  38. package/lib/test/index.js +9 -35
  39. package/lib/until.js +1 -1
  40. package/lib/webdriver.js +130 -34
  41. package/net/portprober.js +1 -1
  42. package/opera.js +2 -2
  43. package/package.json +2 -2
  44. package/phantomjs.js +2 -2
  45. package/remote/index.js +17 -11
  46. package/safari.js +47 -8
  47. package/test/firefox/extension_test.js +41 -17
  48. package/test/firefox/firefox_test.js +70 -23
  49. package/test/firefox/profile_test.js +14 -59
  50. package/test/http/http_test.js +18 -0
  51. package/test/{io_test.js → io/io_test.js} +40 -1
  52. package/test/io/zip_test.js +128 -0
  53. package/test/lib/by_test.js +21 -0
  54. package/test/lib/error_test.js +20 -1
  55. package/test/lib/http_test.js +41 -2
  56. package/test/lib/promise_test.js +19 -0
  57. package/test/lib/until_test.js +28 -13
  58. package/test/lib/webdriver_test.js +107 -3
  59. package/test/page_loading_test.js +0 -6
  60. package/test/rect_test.js +60 -0
  61. package/test/remote_test.js +3 -3
  62. package/test/session_test.js +68 -23
  63. package/testing/index.js +16 -5
  64. package/lib/atoms/isDisplayed.js +0 -106
  65. package/lib/firefox/amd64/libnoblur64.so +0 -0
  66. package/lib/firefox/i386/libnoblur.so +0 -0
  67. package/lib/firefox/webdriver.xpi +0 -0
package/lib/symbols.js CHANGED
@@ -30,7 +30,7 @@ module.exports = {
30
30
  * available, the serialize method will return a promise that will be resolved
31
31
  * with the serialized form.
32
32
  *
33
- * Note that the described method is analgous to objects that define a
33
+ * Note that the described method is analogous to objects that define a
34
34
  * `toJSON()` method, except the serialized result may be a promise, or
35
35
  * another object with a promised property.
36
36
  */
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Clicking on a disabled element</title>
5
+ </head>
6
+ <body>
7
+ <h1>See below</h1>
8
+ <form action="POST">
9
+ <input name="disabled" disabled="disabled" />
10
+ </form>
11
+ </body>
12
+ </html>
@@ -0,0 +1,34 @@
1
+ <?xml version="1.0"?>
2
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
4
+ <head>
5
+ <title>Testing Key Events</title>
6
+ <script type="text/javascript">
7
+ function appendMessage(message) {
8
+ document.getElementById('resultParagraph').innerHTML += message + " ";
9
+ }
10
+ </script>
11
+ </head>
12
+ <body>
13
+ <div id="resultContainer" height="30">&nbsp;
14
+ <div id="result" style="width:300;height:60">
15
+ <p id="resultParagraph">&nbsp;</p>
16
+ </div>
17
+ </div>
18
+
19
+ <div>
20
+ <form action="resultPage.html" id="on-form">
21
+ <input id="theworks"
22
+ onfocus="appendMessage('focus')"
23
+ onkeydown="appendMessage('keydown')"
24
+ onkeypress="appendMessage('keypress')"
25
+ onkeyup="appendMessage('keyup')"
26
+ onblur="appendMessage('blur')"
27
+ onchange="appendMessage('change')"
28
+ />
29
+ </form>
30
+ </div>
31
+ </body>
32
+ </html>
33
+
34
+
@@ -5,6 +5,15 @@
5
5
  <div id="test_id_div">
6
6
  <p id="test_id">inside</p>
7
7
  </div>
8
+ <div id="test_special_chars">
9
+ <p id="white space">space</p>
10
+ <p id="css#.chars">css escapes</p>
11
+ </div>
12
+ <div id="test_special_chars_2">
13
+ <p id="white space">second copy for testing plural findElements</p>
14
+ <p id="css#.chars">second copy</p>
15
+ </div>
16
+
8
17
  <form method="get" action="resultPage.html" name="form1" style="display: block">
9
18
  Here's a checkbox: <input type="checkbox" id="checky" name="checky" value="furrfu"/><br/>
10
19
  <select name="selectomatic" id="1">
@@ -152,4 +161,4 @@
152
161
  <span class="oneother">But not me</span>
153
162
  </div>
154
163
  </body>
155
- </html>
164
+ </html>
@@ -0,0 +1,12 @@
1
+ <html>
2
+ <head>
3
+ <title>BasicKeyboardInterfaceTest</title>
4
+ </head>
5
+ <body>
6
+ <form action="#">
7
+ <input type="text" id="textInput" />
8
+ </form>
9
+ </body>
10
+ </html>
11
+
12
+
package/lib/test/index.js CHANGED
@@ -24,15 +24,13 @@ var build = require('./build'),
24
24
  webdriver = require('../../'),
25
25
  flow = webdriver.promise.controlFlow(),
26
26
  firefox = require('../../firefox'),
27
+ logging = require('../../lib/logging'),
27
28
  safari = require('../../safari'),
28
29
  remote = require('../../remote'),
29
30
  testing = require('../../testing'),
30
31
  fileserver = require('./fileserver');
31
32
 
32
33
 
33
- const LEGACY_FIREFOX = 'legacy-' + webdriver.Browser.FIREFOX;
34
-
35
-
36
34
  /**
37
35
  * Browsers with native support.
38
36
  * @type {!Array.<webdriver.Browser>}
@@ -41,7 +39,6 @@ var NATIVE_BROWSERS = [
41
39
  webdriver.Browser.CHROME,
42
40
  webdriver.Browser.EDGE,
43
41
  webdriver.Browser.FIREFOX,
44
- LEGACY_FIREFOX,
45
42
  webdriver.Browser.IE,
46
43
  webdriver.Browser.OPERA,
47
44
  webdriver.Browser.PHANTOM_JS,
@@ -49,13 +46,18 @@ var NATIVE_BROWSERS = [
49
46
  ];
50
47
 
51
48
 
49
+ var noBuild = /^1|true$/i.test(process.env['SELENIUM_NO_BUILD']);
52
50
  var serverJar = process.env['SELENIUM_SERVER_JAR'];
53
51
  var remoteUrl = process.env['SELENIUM_REMOTE_URL'];
54
52
  var useLoopback = process.env['SELENIUM_USE_LOOP_BACK'] == '1';
55
- var noMarionette = /^0|false$/i.test(process.env['SELENIUM_GECKODRIVER']);
56
53
  var startServer = !!serverJar && !remoteUrl;
57
54
  var nativeRun = !serverJar && !remoteUrl;
58
55
 
56
+ if (/^1|true$/i.test(process.env['SELENIUM_VERBOSE'])) {
57
+ logging.installConsoleHandler();
58
+ logging.getLogger('webdriver.http').setLevel(logging.Level.ALL);
59
+ }
60
+
59
61
  var browsersToTest = (function() {
60
62
  var permitRemoteBrowsers = !!remoteUrl || !!serverJar;
61
63
  var permitUnknownBrowsers = !nativeRun;
@@ -69,9 +71,6 @@ var browsersToTest = (function() {
69
71
  if (parts[0] === 'edge') {
70
72
  parts[0] = webdriver.Browser.EDGE;
71
73
  }
72
- if (noMarionette && parts[0] === webdriver.Browser.FIREFOX) {
73
- parts[0] = LEGACY_FIREFOX;
74
- }
75
74
  return parts.join(':');
76
75
  });
77
76
 
@@ -81,10 +80,6 @@ var browsersToTest = (function() {
81
80
  parts[0] = webdriver.Browser.IE;
82
81
  }
83
82
 
84
- if (parts[0] === LEGACY_FIREFOX) {
85
- return;
86
- }
87
-
88
83
  if (NATIVE_BROWSERS.indexOf(parts[0]) == -1 && !permitRemoteBrowsers) {
89
84
  throw Error('Browser ' + parts[0] + ' requires a WebDriver server and ' +
90
85
  'neither the SELENIUM_REMOTE_URL nor the SELENIUM_SERVER_JAR ' +
@@ -150,10 +145,6 @@ function TestEnvironment(browserName, server) {
150
145
  return server || remoteUrl;
151
146
  };
152
147
 
153
- this.isMarionette = function() {
154
- return !noMarionette;
155
- };
156
-
157
148
  this.browsers = function(var_args) {
158
149
  var browsersToIgnore = Array.prototype.slice.apply(arguments, [0]);
159
150
  return browsers(browserName, browsersToIgnore);
@@ -164,15 +155,7 @@ function TestEnvironment(browserName, server) {
164
155
  var realBuild = builder.build;
165
156
 
166
157
  builder.build = function() {
167
- var parts = browserName.split(/:/, 3);
168
-
169
- if (parts[0] === LEGACY_FIREFOX) {
170
- var options = builder.getFirefoxOptions() || new firefox.Options();
171
- options.useGeckoDriver(false);
172
- builder.setFirefoxOptions(options);
173
-
174
- parts[0] = webdriver.Browser.FIREFOX;
175
- }
158
+ let parts = browserName.split(/:/, 3);
176
159
 
177
160
  builder.forBrowser(parts[0], parts[1], parts[2]);
178
161
  if (server) {
@@ -219,7 +202,7 @@ function suite(fn, opt_options) {
219
202
  try {
220
203
 
221
204
  before(function() {
222
- if (isDevMode) {
205
+ if (isDevMode && !noBuild) {
223
206
  return build.of(
224
207
  '//javascript/atoms/fragments:is-displayed',
225
208
  '//javascript/webdriver/atoms:getAttribute')
@@ -237,15 +220,6 @@ function suite(fn, opt_options) {
237
220
  browsers.forEach(function(browser) {
238
221
  describe('[' + browser + ']', function() {
239
222
 
240
- if (isDevMode && nativeRun) {
241
- if (browser === LEGACY_FIREFOX) {
242
- before(function() {
243
- return build.of('//javascript/firefox-driver:webdriver')
244
- .onlyOnce().go();
245
- });
246
- }
247
- }
248
-
249
223
  var serverToUse = null;
250
224
 
251
225
  if (!!serverJar && !remoteUrl) {
package/lib/until.js CHANGED
@@ -72,7 +72,7 @@ const webdriver = require('./webdriver'),
72
72
  exports.ableToSwitchToFrame = function ableToSwitchToFrame(frame) {
73
73
  var condition;
74
74
  if (typeof frame === 'number' || frame instanceof webdriver.WebElement) {
75
- condition = attemptToSwitchFrames;
75
+ condition = driver => attemptToSwitchFrames(driver, frame);
76
76
  } else {
77
77
  condition = function(driver) {
78
78
  let locator = /** @type {!(By|Function)} */(frame);
package/lib/webdriver.js CHANGED
@@ -457,12 +457,12 @@ class IWebDriver {
457
457
  * while evaluating the condition, they will be allowed to propagate. In the
458
458
  * event a condition returns a {@link promise.Promise promise}, the polling
459
459
  * loop will wait for it to be resolved and use the resolved value for whether
460
- * the condition has been satisified. Note the resolution time for a promise
460
+ * the condition has been satisfied. Note the resolution time for a promise
461
461
  * is factored into whether a wait has timed out.
462
462
  *
463
463
  * Note, if the provided condition is a {@link WebElementCondition}, then
464
464
  * the wait will return a {@link WebElementPromise} that will resolve to the
465
- * element that satisified the condition.
465
+ * element that satisfied the condition.
466
466
  *
467
467
  * _Example:_ waiting up to 10 seconds for an element to be present on the
468
468
  * page.
@@ -750,20 +750,12 @@ class WebDriver {
750
750
  * commands should execute under, including the initial session creation.
751
751
  * Defaults to the {@link promise.controlFlow() currently active}
752
752
  * control flow.
753
- * @param {(function(new: WebDriver,
754
- * !IThenable<!Session>,
755
- * !command.Executor,
756
- * promise.ControlFlow=))=} opt_ctor
757
- * A reference to the constructor of the specific type of WebDriver client
758
- * to instantiate. Will create a vanilla {@linkplain WebDriver} instance
759
- * if a constructor is not provided.
760
753
  * @param {(function(this: void): ?)=} opt_onQuit A callback to invoke when
761
754
  * the newly created session is terminated. This should be used to clean
762
755
  * up any resources associated with the session.
763
756
  * @return {!WebDriver} The driver for the newly created session.
764
757
  */
765
- static createSession(
766
- executor, capabilities, opt_flow, opt_ctor, opt_onQuit) {
758
+ static createSession(executor, capabilities, opt_flow, opt_onQuit) {
767
759
  let flow = opt_flow || promise.controlFlow();
768
760
  let cmd = new command.Command(command.Name.NEW_SESSION);
769
761
 
@@ -779,11 +771,10 @@ class WebDriver {
779
771
  'WebDriver.createSession()');
780
772
  if (typeof opt_onQuit === 'function') {
781
773
  session = session.catch(err => {
782
- return Promise.resolve(opt_onQuit.call(void 0)).then(_ => {throw err});
774
+ return Promise.resolve(opt_onQuit.call(void 0)).then(_ => {throw err;});
783
775
  });
784
776
  }
785
- const ctor = opt_ctor || WebDriver;
786
- return new ctor(session, executor, flow, opt_onQuit);
777
+ return new this(session, executor, flow, opt_onQuit);
787
778
  }
788
779
 
789
780
  /** @override */
@@ -850,7 +841,7 @@ class WebDriver {
850
841
  new command.Command(command.Name.QUIT),
851
842
  'WebDriver.quit()');
852
843
  // Delete our session ID when the quit command finishes; this will allow us
853
- // to throw an error when attemnpting to use a driver post-quit.
844
+ // to throw an error when attempting to use a driver post-quit.
854
845
  return /** @type {!promise.Thenable} */(promise.finally(result, () => {
855
846
  this.session_ = this.flow_.promise((_, reject) => {
856
847
  reject(new error.NoSuchSessionError(
@@ -1181,7 +1172,7 @@ class Navigation {
1181
1172
  /**
1182
1173
  * Provides methods for managing browser and driver state.
1183
1174
  *
1184
- * This class should never be instantiated directly. Insead, obtain an instance
1175
+ * This class should never be instantiated directly. Instead, obtain an instance
1185
1176
  * with {@linkplain WebDriver#manage() webdriver.manage()}.
1186
1177
  */
1187
1178
  class Options {
@@ -1326,6 +1317,91 @@ class Options {
1326
1317
  });
1327
1318
  }
1328
1319
 
1320
+ /**
1321
+ * Schedules a command to fetch the timeouts currently configured for the
1322
+ * current session.
1323
+ *
1324
+ * @return {!promise.Thenable<{script: number,
1325
+ * pageLoad: number,
1326
+ * implicit: number}>} A promise that will be
1327
+ * resolved with the timeouts currently configured for the current
1328
+ * session.
1329
+ * @see #setTimeouts()
1330
+ */
1331
+ getTimeouts() {
1332
+ return this.driver_.schedule(
1333
+ new command.Command(command.Name.GET_TIMEOUT),
1334
+ `WebDriver.manage().getTimeouts()`)
1335
+ }
1336
+
1337
+ /**
1338
+ * Schedules a command to set timeout durations associated with the current
1339
+ * session.
1340
+ *
1341
+ * The following timeouts are supported (all timeouts are specified in
1342
+ * milliseconds):
1343
+ *
1344
+ * - `implicit` specifies the maximum amount of time to wait for an element
1345
+ * locator to succeed when {@linkplain WebDriver#findElement locating}
1346
+ * {@linkplain WebDriver#findElements elements} on the page.
1347
+ * Defaults to 0 milliseconds.
1348
+ *
1349
+ * - `pageLoad` specifies the maximum amount of time to wait for a page to
1350
+ * finishing loading. Defaults to 300000 milliseconds.
1351
+ *
1352
+ * - `script` specifies the maximum amount of time to wait for an
1353
+ * {@linkplain WebDriver#executeScript evaluated script} to run. If set to
1354
+ * `null`, the script timeout will be indefinite.
1355
+ * Defaults to 30000 milliseconds.
1356
+ *
1357
+ * @param {{script: (number|null|undefined),
1358
+ * pageLoad: (number|null|undefined),
1359
+ * implicit: (number|null|undefined)}} conf
1360
+ * The desired timeout configuration.
1361
+ * @return {!promise.Thenable<void>} A promise that will be resolved when the
1362
+ * timeouts have been set.
1363
+ * @throws {!TypeError} if an invalid options object is provided.
1364
+ * @see #getTimeouts()
1365
+ * @see <https://w3c.github.io/webdriver/webdriver-spec.html#dfn-set-timeouts>
1366
+ */
1367
+ setTimeouts({script, pageLoad, implicit} = {}) {
1368
+ let cmd = new command.Command(command.Name.SET_TIMEOUT);
1369
+
1370
+ let valid = false;
1371
+ function setParam(key, value) {
1372
+ if (value === null || typeof value === 'number') {
1373
+ valid = true;
1374
+ cmd.setParameter(key, value);
1375
+ } else if (typeof value !== 'undefined') {
1376
+ throw TypeError(
1377
+ 'invalid timeouts configuration:'
1378
+ + ` expected "${key}" to be a number, got ${typeof value}`);
1379
+ }
1380
+ }
1381
+ setParam('implicit', implicit);
1382
+ setParam('pageLoad', pageLoad);
1383
+ setParam('script', script);
1384
+
1385
+ if (valid) {
1386
+ return this.driver_.schedule(cmd, `WebDriver.manage().setTimeouts()`)
1387
+ .catch(() => {
1388
+ // Fallback to the legacy method.
1389
+ let cmds = [];
1390
+ if (typeof script === 'number') {
1391
+ cmds.push(legacyTimeout(this.driver_, 'script', script));
1392
+ }
1393
+ if (typeof implicit === 'number') {
1394
+ cmds.push(legacyTimeout(this.driver_, 'implicit', implicit));
1395
+ }
1396
+ if (typeof pageLoad === 'number') {
1397
+ cmds.push(legacyTimeout(this.driver_, 'page load', pageLoad));
1398
+ }
1399
+ return Promise.all(cmds);
1400
+ });
1401
+ }
1402
+ throw TypeError('no timeouts specified');
1403
+ }
1404
+
1329
1405
  /**
1330
1406
  * @return {!Logs} The interface for managing driver
1331
1407
  * logs.
@@ -1336,6 +1412,7 @@ class Options {
1336
1412
 
1337
1413
  /**
1338
1414
  * @return {!Timeouts} The interface for managing driver timeouts.
1415
+ * @deprecated Use {@link #setTimeouts()} instead.
1339
1416
  */
1340
1417
  timeouts() {
1341
1418
  return new Timeouts(this.driver_);
@@ -1350,6 +1427,22 @@ class Options {
1350
1427
  }
1351
1428
 
1352
1429
 
1430
+ /**
1431
+ * @param {!WebDriver} driver
1432
+ * @param {string} type
1433
+ * @param {number} ms
1434
+ * @return {!promise.Thenable<void>}
1435
+ */
1436
+ function legacyTimeout(driver, type, ms) {
1437
+ return driver.schedule(
1438
+ new command.Command(command.Name.SET_TIMEOUT)
1439
+ .setParameter('type', type)
1440
+ .setParameter('ms', ms),
1441
+ `WebDriver.manage().setTimeouts({${type}: ${ms}})`);
1442
+ }
1443
+
1444
+
1445
+
1353
1446
  /**
1354
1447
  * A record object describing a browser cookie.
1355
1448
  *
@@ -1427,11 +1520,14 @@ Options.Cookie.prototype.expiry;
1427
1520
  /**
1428
1521
  * An interface for managing timeout behavior for WebDriver instances.
1429
1522
  *
1430
- * This class should never be instantiated directly. Insead, obtain an instance
1523
+ * This class should never be instantiated directly. Instead, obtain an instance
1431
1524
  * with
1432
1525
  *
1433
1526
  * webdriver.manage().timeouts()
1434
1527
  *
1528
+ * @deprecated This has been deprecated in favor of
1529
+ * {@link Options#setTimeouts()}, which supports setting multiple timeouts
1530
+ * at once.
1435
1531
  * @see WebDriver#manage()
1436
1532
  * @see Options#timeouts()
1437
1533
  */
@@ -1465,9 +1561,11 @@ class Timeouts {
1465
1561
  * @param {number} ms The amount of time to wait, in milliseconds.
1466
1562
  * @return {!promise.Thenable<void>} A promise that will be resolved
1467
1563
  * when the implicit wait timeout has been set.
1564
+ * @deprecated Use {@link Options#setTimeouts()
1565
+ * driver.manage().setTimeouts({implicit: ms})}.
1468
1566
  */
1469
1567
  implicitlyWait(ms) {
1470
- return this._scheduleCommand(ms, 'implicit', 'implicitlyWait');
1568
+ return this.driver_.manage().setTimeouts({implicit: ms});
1471
1569
  }
1472
1570
 
1473
1571
  /**
@@ -1478,9 +1576,11 @@ class Timeouts {
1478
1576
  * @param {number} ms The amount of time to wait, in milliseconds.
1479
1577
  * @return {!promise.Thenable<void>} A promise that will be resolved
1480
1578
  * when the script timeout has been set.
1579
+ * @deprecated Use {@link Options#setTimeouts()
1580
+ * driver.manage().setTimeouts({script: ms})}.
1481
1581
  */
1482
1582
  setScriptTimeout(ms) {
1483
- return this._scheduleCommand(ms, 'script', 'setScriptTimeout');
1583
+ return this.driver_.manage().setTimeouts({script: ms});
1484
1584
  }
1485
1585
 
1486
1586
  /**
@@ -1491,17 +1591,11 @@ class Timeouts {
1491
1591
  * @param {number} ms The amount of time to wait, in milliseconds.
1492
1592
  * @return {!promise.Thenable<void>} A promise that will be resolved
1493
1593
  * when the timeout has been set.
1594
+ * @deprecated Use {@link Options#setTimeouts()
1595
+ * driver.manage().setTimeouts({pageLoad: ms})}.
1494
1596
  */
1495
1597
  pageLoadTimeout(ms) {
1496
- return this._scheduleCommand(ms, 'page load', 'pageLoadTimeout');
1497
- }
1498
-
1499
- _scheduleCommand(ms, timeoutIdentifier, timeoutName) {
1500
- return this.driver_.schedule(
1501
- new command.Command(command.Name.SET_TIMEOUT).
1502
- setParameter('type', timeoutIdentifier).
1503
- setParameter('ms', ms),
1504
- `WebDriver.manage().timeouts().${timeoutName}(${ms})`);
1598
+ return this.driver_.manage().setTimeouts({pageLoad: ms});
1505
1599
  }
1506
1600
  }
1507
1601
 
@@ -2009,7 +2103,7 @@ class WebElement {
2009
2103
  * this instance.
2010
2104
  *
2011
2105
  * Modifier keys (SHIFT, CONTROL, ALT, META) are stateful; once a modifier is
2012
- * processed in the keysequence, that key state is toggled until one of the
2106
+ * processed in the key sequence, that key state is toggled until one of the
2013
2107
  * following occurs:
2014
2108
  *
2015
2109
  * - The modifier key is encountered again in the sequence. At this point the
@@ -2028,13 +2122,13 @@ class WebElement {
2028
2122
  * Key.chord(Key.CONTROL, "a"),
2029
2123
  * "now text is");
2030
2124
  *
2031
- * - The end of the keysequence is encountered. When there are no more keys
2125
+ * - The end of the key sequence is encountered. When there are no more keys
2032
2126
  * to type, all depressed modifier keys are released (with accompanying
2033
2127
  * keyup events).
2034
2128
  *
2035
2129
  * If this element is a file input ({@code <input type="file">}), the
2036
2130
  * specified key sequence should specify the path to the file to attach to
2037
- * the element. This is analgous to the user clicking "Browse..." and entering
2131
+ * the element. This is analogous to the user clicking "Browse..." and entering
2038
2132
  * the path into the file select dialog.
2039
2133
  *
2040
2134
  * var form = driver.findElement(By.css('form'));
@@ -2050,7 +2144,7 @@ class WebElement {
2050
2144
  *
2051
2145
  * __Note:__ On browsers where native keyboard events are not supported
2052
2146
  * (e.g. Firefox on OS X), key events will be synthesized. Special
2053
- * punctionation keys will be synthesized according to a standard QWERTY en-us
2147
+ * punctuation keys will be synthesized according to a standard QWERTY en-us
2054
2148
  * keyboard layout.
2055
2149
  *
2056
2150
  * @param {...(number|string|!IThenable<(number|string)>)} var_args The
@@ -2083,6 +2177,7 @@ class WebElement {
2083
2177
  if (!this.driver_.fileDetector_) {
2084
2178
  return this.schedule_(
2085
2179
  new command.Command(command.Name.SEND_KEYS_TO_ELEMENT).
2180
+ setParameter('text', keys.then(keys => keys.join(''))).
2086
2181
  setParameter('value', keys),
2087
2182
  'WebElement.sendKeys()');
2088
2183
  }
@@ -2098,6 +2193,7 @@ class WebElement {
2098
2193
  }).then(function(keys) {
2099
2194
  return element.schedule_(
2100
2195
  new command.Command(command.Name.SEND_KEYS_TO_ELEMENT).
2196
+ setParameter('text', keys).
2101
2197
  setParameter('value', keys.split('')),
2102
2198
  'WebElement.sendKeys()');
2103
2199
  });
@@ -2214,7 +2310,7 @@ class WebElement {
2214
2310
 
2215
2311
  /**
2216
2312
  * Schedules a command to query whether the DOM element represented by this
2217
- * instance is enabled, as dicted by the {@code disabled} attribute.
2313
+ * instance is enabled, as dictated by the {@code disabled} attribute.
2218
2314
  * @return {!promise.Thenable<boolean>} A promise that will be
2219
2315
  * resolved with whether this element is currently enabled.
2220
2316
  */
@@ -2327,7 +2423,7 @@ class WebElementPromise extends WebElement {
2327
2423
  if (promise.CancellableThenable.isImplementation(el)) {
2328
2424
  /** @type {!promise.CancellableThenable} */(el).cancel(opt_reason);
2329
2425
  }
2330
- }
2426
+ };
2331
2427
 
2332
2428
  /** @override */
2333
2429
  this.then = el.then.bind(el);
package/net/portprober.js CHANGED
@@ -191,7 +191,7 @@ function findFreePort(opt_host) {
191
191
  } else {
192
192
  findPort();
193
193
  }
194
- });
194
+ }, findPort);
195
195
  }
196
196
  });
197
197
  });
package/opera.js CHANGED
@@ -62,7 +62,7 @@
62
62
  * var options = new opera.Options();
63
63
  * // configure browser options ...
64
64
  *
65
- * var driver = new opera.Driver(options, service);
65
+ * var driver = opera.Driver.createSession(options, service);
66
66
  *
67
67
  * Users should only instantiate the {@link Driver} class directly when they
68
68
  * need a custom driver service configuration (as shown above). For normal
@@ -383,7 +383,7 @@ class Driver extends webdriver.WebDriver {
383
383
  }
384
384
 
385
385
  return /** @type {!Driver} */(
386
- webdriver.WebDriver.createSession(executor, caps, opt_flow, this));
386
+ super.createSession(executor, caps, opt_flow));
387
387
  }
388
388
 
389
389
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "selenium-webdriver",
3
- "version": "3.0.1",
3
+ "version": "3.5.0",
4
4
  "description": "The official WebDriver JavaScript bindings from the Selenium project",
5
5
  "license": "Apache-2.0",
6
6
  "keywords": [
@@ -23,7 +23,7 @@
23
23
  "node": ">= 6.9.0"
24
24
  },
25
25
  "dependencies": {
26
- "adm-zip": "^0.4.7",
26
+ "jszip": "^3.1.3",
27
27
  "rimraf": "^2.5.4",
28
28
  "tmp": "0.0.30",
29
29
  "xml2js": "^0.4.17"
package/phantomjs.js CHANGED
@@ -217,8 +217,8 @@ class Driver extends webdriver.WebDriver {
217
217
  });
218
218
 
219
219
  var executor = createExecutor(service.start());
220
- return /** @type {!Driver} */(webdriver.WebDriver.createSession(
221
- executor, caps, opt_flow, this, () => service.kill()));
220
+ return /** @type {!Driver} */(super.createSession(
221
+ executor, caps, opt_flow, () => service.kill()));
222
222
  }
223
223
 
224
224
  /**
package/remote/index.js CHANGED
@@ -17,7 +17,6 @@
17
17
 
18
18
  'use strict';
19
19
 
20
- const AdmZip = require('adm-zip');
21
20
  const fs = require('fs');
22
21
  const path = require('path');
23
22
  const url = require('url');
@@ -26,6 +25,7 @@ const util = require('util');
26
25
  const httpUtil = require('../http/util');
27
26
  const io = require('../io');
28
27
  const exec = require('../io/exec');
28
+ const {Zip} = require('../io/zip');
29
29
  const cmd = require('../lib/command');
30
30
  const input = require('../lib/input');
31
31
  const promise = require('../lib/promise');
@@ -492,7 +492,12 @@ class SeleniumServer extends DriverService {
492
492
  return jvmArgs.concat('-jar', jar, '-port', port).concat(args);
493
493
  });
494
494
 
495
- super('java', {
495
+ let java = 'java';
496
+ if (process.env['JAVA_HOME']) {
497
+ java = path.join(process.env['JAVA_HOME'], 'bin/java');
498
+ }
499
+
500
+ super(java, {
496
501
  loopback: options.loopback,
497
502
  port: port,
498
503
  args: args,
@@ -570,15 +575,16 @@ class FileDetector extends input.FileDetector {
570
575
  return file; // Not a valid file, return original input.
571
576
  }
572
577
 
573
- var zip = new AdmZip();
574
- zip.addLocalFile(file);
575
- // Stored compression, see https://en.wikipedia.org/wiki/Zip_(file_format)
576
- zip.getEntries()[0].header.method = 0;
577
-
578
- var command = new cmd.Command(cmd.Name.UPLOAD_FILE)
579
- .setParameter('file', zip.toBuffer().toString('base64'));
580
- return driver.schedule(command,
581
- 'remote.FileDetector.handleFile(' + file + ')');
578
+ let zip = new Zip;
579
+ return zip.addFile(file)
580
+ .then(() => zip.toBuffer())
581
+ .then(buf => buf.toString('base64'))
582
+ .then(encodedZip => {
583
+ let command = new cmd.Command(cmd.Name.UPLOAD_FILE)
584
+ .setParameter('file', encodedZip);
585
+ return driver.schedule(command,
586
+ 'remote.FileDetector.handleFile(' + file + ')');
587
+ });
582
588
  }, function(err) {
583
589
  if (err.code === 'ENOENT') {
584
590
  return file; // Not a file; return original input.