selenium-webdriver 3.1.0 → 3.6.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 (65) hide show
  1. package/CHANGES.md +112 -0
  2. package/NOTICE +1 -1
  3. package/README.md +5 -11
  4. package/chrome.js +122 -33
  5. package/edge.js +2 -2
  6. package/example/async_await_test.js +69 -0
  7. package/example/chrome_android.js +2 -3
  8. package/example/chrome_mobile_emulation.js +3 -4
  9. package/example/firefox_channels.js +3 -3
  10. package/example/google_search.js +3 -3
  11. package/example/google_search_generator.js +2 -5
  12. package/example/google_search_test.js +5 -6
  13. package/example/headless.js +55 -0
  14. package/example/logging.js +3 -3
  15. package/example/parallel_flows.js +4 -7
  16. package/firefox/binary.js +3 -0
  17. package/firefox/extension.js +118 -81
  18. package/firefox/index.js +117 -263
  19. package/firefox/profile.js +18 -137
  20. package/ie.js +2 -2
  21. package/index.js +4 -1
  22. package/io/index.js +59 -0
  23. package/io/zip.js +214 -0
  24. package/lib/atoms/get-attribute.js +9 -0
  25. package/lib/atoms/is-displayed.js +73 -78
  26. package/lib/by.js +8 -0
  27. package/lib/capabilities.js +61 -22
  28. package/lib/command.js +2 -0
  29. package/lib/error.js +32 -2
  30. package/lib/http.js +53 -44
  31. package/lib/promise.js +72 -25
  32. package/lib/test/data/click_tests/disabled_element.html +12 -0
  33. package/lib/test/data/content-editable.html +10 -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/scrolling_tests/page_with_partially_hidden_element.html +14 -0
  38. package/lib/test/data/single_text_input.html +12 -0
  39. package/lib/test/index.js +4 -36
  40. package/lib/webdriver.js +147 -55
  41. package/net/portprober.js +1 -1
  42. package/opera.js +1 -1
  43. package/package.json +2 -2
  44. package/phantomjs.js +2 -2
  45. package/remote/index.js +21 -14
  46. package/safari.js +2 -2
  47. package/test/firefox/extension_test.js +41 -17
  48. package/test/firefox/firefox_test.js +37 -19
  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 +21 -1
  55. package/test/lib/http_test.js +11 -3
  56. package/test/lib/webdriver_test.js +107 -3
  57. package/test/page_loading_test.js +0 -6
  58. package/test/remote_test.js +3 -3
  59. package/test/session_test.js +68 -23
  60. package/testing/index.js +2 -3
  61. package/lib/atoms/getAttribute.js +0 -12
  62. package/lib/firefox/amd64/libnoblur64.so +0 -0
  63. package/lib/firefox/i386/libnoblur.so +0 -0
  64. package/lib/firefox/webdriver.json +0 -69
  65. package/lib/firefox/webdriver.xpi +0 -0
@@ -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,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Page with partially hidden element</title>
5
+ </head>
6
+ <body>
7
+ <div style="width:200px; height: 200px; overflow: auto;">
8
+ <div style="height: 175px; width: 240px;">Placeholder</div>
9
+ <div>
10
+ <button type="button" style="height: 40px; box-sizing: border-box" id="btn" onclick="window.location='target_page.html'">Click me!</button>
11
+ </div>
12
+ </div>
13
+ </body>
14
+ </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
@@ -31,9 +31,6 @@ var build = require('./build'),
31
31
  fileserver = require('./fileserver');
32
32
 
33
33
 
34
- const LEGACY_FIREFOX = 'legacy-' + webdriver.Browser.FIREFOX;
35
-
36
-
37
34
  /**
38
35
  * Browsers with native support.
39
36
  * @type {!Array.<webdriver.Browser>}
@@ -42,7 +39,6 @@ var NATIVE_BROWSERS = [
42
39
  webdriver.Browser.CHROME,
43
40
  webdriver.Browser.EDGE,
44
41
  webdriver.Browser.FIREFOX,
45
- LEGACY_FIREFOX,
46
42
  webdriver.Browser.IE,
47
43
  webdriver.Browser.OPERA,
48
44
  webdriver.Browser.PHANTOM_JS,
@@ -50,10 +46,10 @@ var NATIVE_BROWSERS = [
50
46
  ];
51
47
 
52
48
 
49
+ var noBuild = /^1|true$/i.test(process.env['SELENIUM_NO_BUILD']);
53
50
  var serverJar = process.env['SELENIUM_SERVER_JAR'];
54
51
  var remoteUrl = process.env['SELENIUM_REMOTE_URL'];
55
52
  var useLoopback = process.env['SELENIUM_USE_LOOP_BACK'] == '1';
56
- var noMarionette = /^0|false$/i.test(process.env['SELENIUM_GECKODRIVER']);
57
53
  var startServer = !!serverJar && !remoteUrl;
58
54
  var nativeRun = !serverJar && !remoteUrl;
59
55
 
@@ -75,9 +71,6 @@ var browsersToTest = (function() {
75
71
  if (parts[0] === 'edge') {
76
72
  parts[0] = webdriver.Browser.EDGE;
77
73
  }
78
- if (noMarionette && parts[0] === webdriver.Browser.FIREFOX) {
79
- parts[0] = LEGACY_FIREFOX;
80
- }
81
74
  return parts.join(':');
82
75
  });
83
76
 
@@ -87,10 +80,6 @@ var browsersToTest = (function() {
87
80
  parts[0] = webdriver.Browser.IE;
88
81
  }
89
82
 
90
- if (parts[0] === LEGACY_FIREFOX) {
91
- return;
92
- }
93
-
94
83
  if (NATIVE_BROWSERS.indexOf(parts[0]) == -1 && !permitRemoteBrowsers) {
95
84
  throw Error('Browser ' + parts[0] + ' requires a WebDriver server and ' +
96
85
  'neither the SELENIUM_REMOTE_URL nor the SELENIUM_SERVER_JAR ' +
@@ -156,10 +145,6 @@ function TestEnvironment(browserName, server) {
156
145
  return server || remoteUrl;
157
146
  };
158
147
 
159
- this.isMarionette = function() {
160
- return !noMarionette;
161
- };
162
-
163
148
  this.browsers = function(var_args) {
164
149
  var browsersToIgnore = Array.prototype.slice.apply(arguments, [0]);
165
150
  return browsers(browserName, browsersToIgnore);
@@ -170,15 +155,7 @@ function TestEnvironment(browserName, server) {
170
155
  var realBuild = builder.build;
171
156
 
172
157
  builder.build = function() {
173
- var parts = browserName.split(/:/, 3);
174
-
175
- if (parts[0] === LEGACY_FIREFOX) {
176
- var options = builder.getFirefoxOptions() || new firefox.Options();
177
- options.useGeckoDriver(false);
178
- builder.setFirefoxOptions(options);
179
-
180
- parts[0] = webdriver.Browser.FIREFOX;
181
- }
158
+ let parts = browserName.split(/:/, 3);
182
159
 
183
160
  builder.forBrowser(parts[0], parts[1], parts[2]);
184
161
  if (server) {
@@ -225,10 +202,10 @@ function suite(fn, opt_options) {
225
202
  try {
226
203
 
227
204
  before(function() {
228
- if (isDevMode) {
205
+ if (isDevMode && !noBuild) {
229
206
  return build.of(
230
207
  '//javascript/atoms/fragments:is-displayed',
231
- '//javascript/webdriver/atoms:getAttribute')
208
+ '//javascript/webdriver/atoms:get-attribute')
232
209
  .onlyOnce().go();
233
210
  }
234
211
  });
@@ -243,15 +220,6 @@ function suite(fn, opt_options) {
243
220
  browsers.forEach(function(browser) {
244
221
  describe('[' + browser + ']', function() {
245
222
 
246
- if (isDevMode && nativeRun) {
247
- if (browser === LEGACY_FIREFOX) {
248
- before(function() {
249
- return build.of('//javascript/firefox-driver:webdriver')
250
- .onlyOnce().go();
251
- });
252
- }
253
- }
254
-
255
223
  var serverToUse = null;
256
224
 
257
225
  if (!!serverJar && !remoteUrl) {
package/lib/webdriver.js CHANGED
@@ -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
 
@@ -782,8 +774,7 @@ class WebDriver {
782
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 */
@@ -1054,13 +1045,15 @@ class WebDriver {
1054
1045
  let cmd = new command.Command(command.Name.FIND_ELEMENTS).
1055
1046
  setParameter('using', locator.using).
1056
1047
  setParameter('value', locator.value);
1057
- let res = this.schedule(cmd, 'WebDriver.findElements(' + locator + ')');
1058
- return res.catch(function(e) {
1059
- if (e instanceof error.NoSuchElementError) {
1060
- return [];
1061
- }
1062
- throw e;
1063
- });
1048
+ return this.schedule(cmd, 'WebDriver.findElements(' + locator + ')')
1049
+ .then(
1050
+ (res) => Array.isArray(res) ? res : [],
1051
+ (e) => {
1052
+ if (e instanceof error.NoSuchElementError) {
1053
+ return [];
1054
+ }
1055
+ throw e;
1056
+ });
1064
1057
  }
1065
1058
  }
1066
1059
 
@@ -1200,14 +1193,14 @@ class Options {
1200
1193
  * __Sample Usage:__
1201
1194
  *
1202
1195
  * // Set a basic cookie.
1203
- * driver.options().addCookie({name: 'foo', value: 'bar'});
1196
+ * driver.manage().addCookie({name: 'foo', value: 'bar'});
1204
1197
  *
1205
1198
  * // Set a cookie that expires in 10 minutes.
1206
1199
  * let expiry = new Date(Date.now() + (10 * 60 * 1000));
1207
- * driver.options().addCookie({name: 'foo', value: 'bar', expiry});
1200
+ * driver.manage().addCookie({name: 'foo', value: 'bar', expiry});
1208
1201
  *
1209
1202
  * // The cookie expiration may also be specified in seconds since epoch.
1210
- * driver.options().addCookie({
1203
+ * driver.manage().addCookie({
1211
1204
  * name: 'foo',
1212
1205
  * value: 'bar',
1213
1206
  * expiry: Math.floor(Date.now() / 1000)
@@ -1220,36 +1213,29 @@ class Options {
1220
1213
  * invalid.
1221
1214
  * @throws {TypeError} if `spec` is not a cookie object.
1222
1215
  */
1223
- addCookie(spec) {
1224
- if (!spec || typeof spec !== 'object') {
1225
- throw TypeError('addCookie called with non-cookie parameter');
1226
- }
1227
-
1216
+ addCookie({name, value, path, domain, secure, httpOnly, expiry}) {
1228
1217
  // We do not allow '=' or ';' in the name.
1229
- let name = spec.name;
1230
1218
  if (/[;=]/.test(name)) {
1231
1219
  throw new error.InvalidArgumentError(
1232
1220
  'Invalid cookie name "' + name + '"');
1233
1221
  }
1234
1222
 
1235
1223
  // We do not allow ';' in value.
1236
- let value = spec.value;
1237
1224
  if (/;/.test(value)) {
1238
1225
  throw new error.InvalidArgumentError(
1239
1226
  'Invalid cookie value "' + value + '"');
1240
1227
  }
1241
1228
 
1242
1229
  let cookieString = name + '=' + value +
1243
- (spec.domain ? ';domain=' + spec.domain : '') +
1244
- (spec.path ? ';path=' + spec.path : '') +
1245
- (spec.secure ? ';secure' : '');
1246
-
1247
- let expiry;
1248
- if (typeof spec.expiry === 'number') {
1249
- expiry = Math.floor(spec.expiry);
1250
- cookieString += ';expires=' + new Date(spec.expiry * 1000).toUTCString();
1251
- } else if (spec.expiry instanceof Date) {
1252
- let date = /** @type {!Date} */(spec.expiry);
1230
+ (domain ? ';domain=' + domain : '') +
1231
+ (path ? ';path=' + path : '') +
1232
+ (secure ? ';secure' : '');
1233
+
1234
+ if (typeof expiry === 'number') {
1235
+ expiry = Math.floor(expiry);
1236
+ cookieString += ';expires=' + new Date(expiry * 1000).toUTCString();
1237
+ } else if (expiry instanceof Date) {
1238
+ let date = /** @type {!Date} */(expiry);
1253
1239
  expiry = Math.floor(date.getTime() / 1000);
1254
1240
  cookieString += ';expires=' + date.toUTCString();
1255
1241
  }
@@ -1259,9 +1245,10 @@ class Options {
1259
1245
  setParameter('cookie', {
1260
1246
  'name': name,
1261
1247
  'value': value,
1262
- 'path': spec.path,
1263
- 'domain': spec.domain,
1264
- 'secure': !!spec.secure,
1248
+ 'path': path,
1249
+ 'domain': domain,
1250
+ 'secure': !!secure,
1251
+ 'httpOnly': !!httpOnly,
1265
1252
  'expiry': expiry
1266
1253
  }),
1267
1254
  'WebDriver.manage().addCookie(' + cookieString + ')');
@@ -1326,6 +1313,91 @@ class Options {
1326
1313
  });
1327
1314
  }
1328
1315
 
1316
+ /**
1317
+ * Schedules a command to fetch the timeouts currently configured for the
1318
+ * current session.
1319
+ *
1320
+ * @return {!promise.Thenable<{script: number,
1321
+ * pageLoad: number,
1322
+ * implicit: number}>} A promise that will be
1323
+ * resolved with the timeouts currently configured for the current
1324
+ * session.
1325
+ * @see #setTimeouts()
1326
+ */
1327
+ getTimeouts() {
1328
+ return this.driver_.schedule(
1329
+ new command.Command(command.Name.GET_TIMEOUT),
1330
+ `WebDriver.manage().getTimeouts()`)
1331
+ }
1332
+
1333
+ /**
1334
+ * Schedules a command to set timeout durations associated with the current
1335
+ * session.
1336
+ *
1337
+ * The following timeouts are supported (all timeouts are specified in
1338
+ * milliseconds):
1339
+ *
1340
+ * - `implicit` specifies the maximum amount of time to wait for an element
1341
+ * locator to succeed when {@linkplain WebDriver#findElement locating}
1342
+ * {@linkplain WebDriver#findElements elements} on the page.
1343
+ * Defaults to 0 milliseconds.
1344
+ *
1345
+ * - `pageLoad` specifies the maximum amount of time to wait for a page to
1346
+ * finishing loading. Defaults to 300000 milliseconds.
1347
+ *
1348
+ * - `script` specifies the maximum amount of time to wait for an
1349
+ * {@linkplain WebDriver#executeScript evaluated script} to run. If set to
1350
+ * `null`, the script timeout will be indefinite.
1351
+ * Defaults to 30000 milliseconds.
1352
+ *
1353
+ * @param {{script: (number|null|undefined),
1354
+ * pageLoad: (number|null|undefined),
1355
+ * implicit: (number|null|undefined)}} conf
1356
+ * The desired timeout configuration.
1357
+ * @return {!promise.Thenable<void>} A promise that will be resolved when the
1358
+ * timeouts have been set.
1359
+ * @throws {!TypeError} if an invalid options object is provided.
1360
+ * @see #getTimeouts()
1361
+ * @see <https://w3c.github.io/webdriver/webdriver-spec.html#dfn-set-timeouts>
1362
+ */
1363
+ setTimeouts({script, pageLoad, implicit} = {}) {
1364
+ let cmd = new command.Command(command.Name.SET_TIMEOUT);
1365
+
1366
+ let valid = false;
1367
+ function setParam(key, value) {
1368
+ if (value === null || typeof value === 'number') {
1369
+ valid = true;
1370
+ cmd.setParameter(key, value);
1371
+ } else if (typeof value !== 'undefined') {
1372
+ throw TypeError(
1373
+ 'invalid timeouts configuration:'
1374
+ + ` expected "${key}" to be a number, got ${typeof value}`);
1375
+ }
1376
+ }
1377
+ setParam('implicit', implicit);
1378
+ setParam('pageLoad', pageLoad);
1379
+ setParam('script', script);
1380
+
1381
+ if (valid) {
1382
+ return this.driver_.schedule(cmd, `WebDriver.manage().setTimeouts()`)
1383
+ .catch(() => {
1384
+ // Fallback to the legacy method.
1385
+ let cmds = [];
1386
+ if (typeof script === 'number') {
1387
+ cmds.push(legacyTimeout(this.driver_, 'script', script));
1388
+ }
1389
+ if (typeof implicit === 'number') {
1390
+ cmds.push(legacyTimeout(this.driver_, 'implicit', implicit));
1391
+ }
1392
+ if (typeof pageLoad === 'number') {
1393
+ cmds.push(legacyTimeout(this.driver_, 'page load', pageLoad));
1394
+ }
1395
+ return Promise.all(cmds);
1396
+ });
1397
+ }
1398
+ throw TypeError('no timeouts specified');
1399
+ }
1400
+
1329
1401
  /**
1330
1402
  * @return {!Logs} The interface for managing driver
1331
1403
  * logs.
@@ -1336,6 +1408,7 @@ class Options {
1336
1408
 
1337
1409
  /**
1338
1410
  * @return {!Timeouts} The interface for managing driver timeouts.
1411
+ * @deprecated Use {@link #setTimeouts()} instead.
1339
1412
  */
1340
1413
  timeouts() {
1341
1414
  return new Timeouts(this.driver_);
@@ -1350,6 +1423,22 @@ class Options {
1350
1423
  }
1351
1424
 
1352
1425
 
1426
+ /**
1427
+ * @param {!WebDriver} driver
1428
+ * @param {string} type
1429
+ * @param {number} ms
1430
+ * @return {!promise.Thenable<void>}
1431
+ */
1432
+ function legacyTimeout(driver, type, ms) {
1433
+ return driver.schedule(
1434
+ new command.Command(command.Name.SET_TIMEOUT)
1435
+ .setParameter('type', type)
1436
+ .setParameter('ms', ms),
1437
+ `WebDriver.manage().setTimeouts({${type}: ${ms}})`);
1438
+ }
1439
+
1440
+
1441
+
1353
1442
  /**
1354
1443
  * A record object describing a browser cookie.
1355
1444
  *
@@ -1413,8 +1502,7 @@ Options.Cookie.prototype.httpOnly;
1413
1502
  * When the cookie expires.
1414
1503
  *
1415
1504
  * When {@linkplain Options#addCookie() adding a cookie}, this may be specified
1416
- * in _seconds_ since Unix epoch (January 1, 1970). The expiry will default to
1417
- * 20 years in the future if omitted.
1505
+ * as a {@link Date} object, or in _seconds_ since Unix epoch (January 1, 1970).
1418
1506
  *
1419
1507
  * The expiry is always returned in seconds since epoch when
1420
1508
  * {@linkplain Options#getCookies() retrieving cookies} from the browser.
@@ -1432,6 +1520,9 @@ Options.Cookie.prototype.expiry;
1432
1520
  *
1433
1521
  * webdriver.manage().timeouts()
1434
1522
  *
1523
+ * @deprecated This has been deprecated in favor of
1524
+ * {@link Options#setTimeouts()}, which supports setting multiple timeouts
1525
+ * at once.
1435
1526
  * @see WebDriver#manage()
1436
1527
  * @see Options#timeouts()
1437
1528
  */
@@ -1465,9 +1556,11 @@ class Timeouts {
1465
1556
  * @param {number} ms The amount of time to wait, in milliseconds.
1466
1557
  * @return {!promise.Thenable<void>} A promise that will be resolved
1467
1558
  * when the implicit wait timeout has been set.
1559
+ * @deprecated Use {@link Options#setTimeouts()
1560
+ * driver.manage().setTimeouts({implicit: ms})}.
1468
1561
  */
1469
1562
  implicitlyWait(ms) {
1470
- return this._scheduleCommand(ms, 'implicit', 'implicitlyWait');
1563
+ return this.driver_.manage().setTimeouts({implicit: ms});
1471
1564
  }
1472
1565
 
1473
1566
  /**
@@ -1478,9 +1571,11 @@ class Timeouts {
1478
1571
  * @param {number} ms The amount of time to wait, in milliseconds.
1479
1572
  * @return {!promise.Thenable<void>} A promise that will be resolved
1480
1573
  * when the script timeout has been set.
1574
+ * @deprecated Use {@link Options#setTimeouts()
1575
+ * driver.manage().setTimeouts({script: ms})}.
1481
1576
  */
1482
1577
  setScriptTimeout(ms) {
1483
- return this._scheduleCommand(ms, 'script', 'setScriptTimeout');
1578
+ return this.driver_.manage().setTimeouts({script: ms});
1484
1579
  }
1485
1580
 
1486
1581
  /**
@@ -1491,17 +1586,11 @@ class Timeouts {
1491
1586
  * @param {number} ms The amount of time to wait, in milliseconds.
1492
1587
  * @return {!promise.Thenable<void>} A promise that will be resolved
1493
1588
  * when the timeout has been set.
1589
+ * @deprecated Use {@link Options#setTimeouts()
1590
+ * driver.manage().setTimeouts({pageLoad: ms})}.
1494
1591
  */
1495
1592
  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})`);
1593
+ return this.driver_.manage().setTimeouts({pageLoad: ms});
1505
1594
  }
1506
1595
  }
1507
1596
 
@@ -1989,7 +2078,8 @@ class WebElement {
1989
2078
  command.Name.FIND_CHILD_ELEMENTS).
1990
2079
  setParameter('using', locator.using).
1991
2080
  setParameter('value', locator.value);
1992
- return this.schedule_(cmd, 'WebElement.findElements(' + locator + ')');
2081
+ return this.schedule_(cmd, 'WebElement.findElements(' + locator + ')')
2082
+ .then(result => Array.isArray(result) ? result : []);
1993
2083
  }
1994
2084
  }
1995
2085
 
@@ -2083,6 +2173,7 @@ class WebElement {
2083
2173
  if (!this.driver_.fileDetector_) {
2084
2174
  return this.schedule_(
2085
2175
  new command.Command(command.Name.SEND_KEYS_TO_ELEMENT).
2176
+ setParameter('text', keys.then(keys => keys.join(''))).
2086
2177
  setParameter('value', keys),
2087
2178
  'WebElement.sendKeys()');
2088
2179
  }
@@ -2098,6 +2189,7 @@ class WebElement {
2098
2189
  }).then(function(keys) {
2099
2190
  return element.schedule_(
2100
2191
  new command.Command(command.Name.SEND_KEYS_TO_ELEMENT).
2192
+ setParameter('text', keys).
2101
2193
  setParameter('value', keys.split('')),
2102
2194
  'WebElement.sendKeys()');
2103
2195
  });
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
@@ -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.1.0",
3
+ "version": "3.6.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');
@@ -278,9 +278,10 @@ class DriverService {
278
278
  if (!this.address_ || !this.command_) {
279
279
  return Promise.resolve(); // Not currently running.
280
280
  }
281
- return this.command_.then(function(command) {
282
- command.kill('SIGTERM');
283
- });
281
+ let cmd = this.command_;
282
+ this.address_ = null;
283
+ this.command_ = null;
284
+ return cmd.then(c => c.kill('SIGTERM'));
284
285
  }
285
286
 
286
287
  /**
@@ -492,7 +493,12 @@ class SeleniumServer extends DriverService {
492
493
  return jvmArgs.concat('-jar', jar, '-port', port).concat(args);
493
494
  });
494
495
 
495
- super('java', {
496
+ let java = 'java';
497
+ if (process.env['JAVA_HOME']) {
498
+ java = path.join(process.env['JAVA_HOME'], 'bin/java');
499
+ }
500
+
501
+ super(java, {
496
502
  loopback: options.loopback,
497
503
  port: port,
498
504
  args: args,
@@ -570,15 +576,16 @@ class FileDetector extends input.FileDetector {
570
576
  return file; // Not a valid file, return original input.
571
577
  }
572
578
 
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 + ')');
579
+ let zip = new Zip;
580
+ return zip.addFile(file)
581
+ .then(() => zip.toBuffer())
582
+ .then(buf => buf.toString('base64'))
583
+ .then(encodedZip => {
584
+ let command = new cmd.Command(cmd.Name.UPLOAD_FILE)
585
+ .setParameter('file', encodedZip);
586
+ return driver.schedule(command,
587
+ 'remote.FileDetector.handleFile(' + file + ')');
588
+ });
582
589
  }, function(err) {
583
590
  if (err.code === 'ENOENT') {
584
591
  return file; // Not a file; return original input.
package/safari.js CHANGED
@@ -250,8 +250,8 @@ class Driver extends webdriver.WebDriver {
250
250
  let executor = new http.Executor(
251
251
  service.start().then(url => new http.HttpClient(url)));
252
252
 
253
- return /** @type {!Driver} */(webdriver.WebDriver.createSession(
254
- executor, caps, opt_flow, this, () => service.kill()));
253
+ return /** @type {!Driver} */(super.createSession(
254
+ executor, caps, opt_flow, () => service.kill()));
255
255
  }
256
256
  }
257
257