selenium-webdriver 3.0.0 → 3.0.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.
package/CHANGES.md CHANGED
@@ -1,3 +1,16 @@
1
+ ## v3.0.1
2
+
3
+ * More API adjustments to align with native Promises
4
+ - Deprecated `promise.fulfilled(value)`, use `promise.Promise#resolve(value)`
5
+ - Deprecated `promise.rejected(reason)`, use `promise.Promise#reject(reason)`
6
+ * When a `wait()` condition times out, the returned promise will now be
7
+ rejected with an `error.TimeoutError` instead of a generic `Error` object.
8
+ * `WebDriver#wait()` will now throw a TypeError if an invalid wait condition is
9
+ provided.
10
+ * Properly catch unhandled promise rejections with an action sequence (only
11
+ impacts when the promise manager is disabled).
12
+
13
+
1
14
  ## v3.0.0
2
15
 
3
16
  * (__NOTICE__) The minimum supported version of Node is now 6.9.0 LTS
package/lib/actions.js CHANGED
@@ -120,9 +120,10 @@ class ActionSequence {
120
120
  let actions = this.actions_.concat();
121
121
  let driver = this.driver_;
122
122
  return driver.controlFlow().execute(function() {
123
- actions.forEach(function(action) {
124
- driver.schedule(action.command, action.description);
123
+ let results = actions.map(action => {
124
+ return driver.schedule(action.command, action.description);
125
125
  });
126
+ return Promise.all(results);
126
127
  }, 'ActionSequence.perform');
127
128
  }
128
129
 
@@ -431,9 +432,10 @@ class TouchSequence {
431
432
  let actions = this.actions_.concat();
432
433
  let driver = this.driver_;
433
434
  return driver.controlFlow().execute(function() {
434
- actions.forEach(function(action) {
435
- driver.schedule(action.command, action.description);
435
+ let results = actions.map(action => {
436
+ return driver.schedule(action.command, action.description);
436
437
  });
438
+ return Promise.all(results);
437
439
  }, 'TouchSequence.perform');
438
440
  }
439
441
 
Binary file
package/lib/promise.js CHANGED
@@ -628,6 +628,7 @@
628
628
 
629
629
  'use strict';
630
630
 
631
+ const error = require('./error');
631
632
  const events = require('./events');
632
633
  const logging = require('./logging');
633
634
 
@@ -1073,6 +1074,30 @@ class ManagedPromise {
1073
1074
  }
1074
1075
  }
1075
1076
 
1077
+ /**
1078
+ * Creates a promise that is immediately resolved with the given value.
1079
+ *
1080
+ * @param {T=} opt_value The value to resolve.
1081
+ * @return {!ManagedPromise<T>} A promise resolved with the given value.
1082
+ * @template T
1083
+ */
1084
+ static resolve(opt_value) {
1085
+ if (opt_value instanceof ManagedPromise) {
1086
+ return opt_value;
1087
+ }
1088
+ return new ManagedPromise(resolve => resolve(opt_value));
1089
+ }
1090
+
1091
+ /**
1092
+ * Creates a promise that is immediately rejected with the given reason.
1093
+ *
1094
+ * @param {*=} opt_reason The rejection reason.
1095
+ * @return {!ManagedPromise<?>} A new rejected promise.
1096
+ */
1097
+ static reject(opt_reason) {
1098
+ return new ManagedPromise((_, reject) => reject(opt_reason));
1099
+ }
1100
+
1076
1101
  /** @override */
1077
1102
  toString() {
1078
1103
  return 'ManagedPromise::' + getUid(this) +
@@ -1475,15 +1500,11 @@ function defer() {
1475
1500
  * Creates a promise that has been resolved with the given value.
1476
1501
  * @param {T=} opt_value The resolved value.
1477
1502
  * @return {!ManagedPromise<T>} The resolved promise.
1503
+ * @deprecated Use {@link ManagedPromise#resolve Promise.resolve(value)}.
1478
1504
  * @template T
1479
1505
  */
1480
1506
  function fulfilled(opt_value) {
1481
- if (opt_value instanceof ManagedPromise) {
1482
- return opt_value;
1483
- }
1484
- return new ManagedPromise(function(fulfill) {
1485
- fulfill(opt_value);
1486
- });
1507
+ return ManagedPromise.resolve(opt_value);
1487
1508
  }
1488
1509
 
1489
1510
 
@@ -1491,16 +1512,11 @@ function fulfilled(opt_value) {
1491
1512
  * Creates a promise that has been rejected with the given reason.
1492
1513
  * @param {*=} opt_reason The rejection reason; may be any value, but is
1493
1514
  * usually an Error or a string.
1494
- * @return {!ManagedPromise<T>} The rejected promise.
1495
- * @template T
1515
+ * @return {!ManagedPromise<?>} The rejected promise.
1516
+ * @deprecated Use {@link ManagedPromise#reject Promise.reject(reason)}.
1496
1517
  */
1497
1518
  function rejected(opt_reason) {
1498
- if (opt_reason instanceof ManagedPromise) {
1499
- return opt_reason;
1500
- }
1501
- return new ManagedPromise(function(_, reject) {
1502
- reject(opt_reason);
1503
- });
1519
+ return ManagedPromise.reject(opt_reason);
1504
1520
  }
1505
1521
 
1506
1522
 
@@ -2045,9 +2061,11 @@ function scheduleWait(scheduler, condition, opt_timeout, opt_message) {
2045
2061
  let start = Date.now();
2046
2062
  let timer = setTimeout(function() {
2047
2063
  timer = null;
2048
- reject(Error((opt_message ? opt_message + '\n' : '') +
2049
- 'Timed out waiting for promise to resolve after ' +
2050
- (Date.now() - start) + 'ms'));
2064
+ reject(
2065
+ new error.TimeoutError(
2066
+ (opt_message ? opt_message + '\n' : '')
2067
+ + 'Timed out waiting for promise to resolve after '
2068
+ + (Date.now() - start) + 'ms'));
2051
2069
  }, timeout);
2052
2070
 
2053
2071
  /** @type {Thenable} */(condition).then(
@@ -2085,8 +2103,10 @@ function scheduleWait(scheduler, condition, opt_timeout, opt_message) {
2085
2103
  if (!!value) {
2086
2104
  fulfill(value);
2087
2105
  } else if (timeout && elapsed >= timeout) {
2088
- reject(new Error((opt_message ? opt_message + '\n' : '') +
2089
- 'Wait timed out after ' + elapsed + 'ms'));
2106
+ reject(
2107
+ new error.TimeoutError(
2108
+ (opt_message ? opt_message + '\n' : '')
2109
+ + `Wait timed out after ${elapsed}ms`));
2090
2110
  } else {
2091
2111
  // Do not use asyncRun here because we need a non-micro yield
2092
2112
  // here so the UI thread is given a chance when running in a
package/lib/webdriver.js CHANGED
@@ -497,6 +497,7 @@ class IWebDriver {
497
497
  * function, or rejected if the condition times out. If the input
498
498
  * input condition is an instance of a {@link WebElementCondition},
499
499
  * the returned value will be a {@link WebElementPromise}.
500
+ * @throws {TypeError} if the provided `condition` is not a valid type.
500
501
  * @template T
501
502
  */
502
503
  wait(condition, opt_timeout, opt_message) {}
@@ -932,6 +933,12 @@ class WebDriver {
932
933
  fn = condition.fn;
933
934
  }
934
935
 
936
+ if (typeof fn !== 'function') {
937
+ throw TypeError(
938
+ 'Wait condition must be a promise-like object, function, or a '
939
+ + 'Condition object');
940
+ }
941
+
935
942
  var driver = this;
936
943
  var result = this.flow_.wait(function() {
937
944
  if (promise.isGenerator(fn)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "selenium-webdriver",
3
- "version": "3.0.0",
3
+ "version": "3.0.1",
4
4
  "description": "The official WebDriver JavaScript bindings from the Selenium project",
5
5
  "license": "Apache-2.0",
6
6
  "keywords": [
@@ -22,6 +22,7 @@ const fail = assert.fail;
22
22
  const sinon = require('sinon');
23
23
 
24
24
  const testutil = require('./testutil');
25
+ const {TimeoutError} = require('../../lib/error');
25
26
  const promise = require('../../lib/promise');
26
27
  const {enablePromiseManager} = require('../../lib/test/promise');
27
28
 
@@ -1133,6 +1134,7 @@ describe('promise control flow', function() {
1133
1134
  default:
1134
1135
  fail('unexpected polling count: ' + count);
1135
1136
  }
1137
+ assert.ok(e instanceof TimeoutError, 'Unexpected error: ' + e);
1136
1138
  assert.ok(
1137
1139
  /^counting to 3\nWait timed out after \d+ms$/.test(e.message));
1138
1140
  });
@@ -1190,6 +1192,7 @@ describe('promise control flow', function() {
1190
1192
  it('promiseThatDoesNotResolveBeforeTimeout', function() {
1191
1193
  var d = promise.defer();
1192
1194
  flow.wait(d.promise, 5).then(fail, function(e) {
1195
+ assert.ok(e instanceof TimeoutError, 'Unexpected error: ' + e);
1193
1196
  assert.ok(
1194
1197
  /Timed out waiting for promise to resolve after \d+ms/
1195
1198
  .test(e.message),
@@ -30,6 +30,7 @@ const logging = require('../../lib/logging');
30
30
  const Session = require('../../lib/session').Session;
31
31
  const promise = require('../../lib/promise');
32
32
  const {enablePromiseManager, promiseManagerSuite} = require('../../lib/test/promise');
33
+ const until = require('../../lib/until');
33
34
  const Alert = require('../../lib/webdriver').Alert;
34
35
  const AlertPromise = require('../../lib/webdriver').AlertPromise;
35
36
  const UnhandledAlertError = require('../../lib/webdriver').UnhandledAlertError;
@@ -1549,43 +1550,26 @@ describe('WebDriver', function() {
1549
1550
  });
1550
1551
 
1551
1552
  describe('waiting', function() {
1552
- it('waitSucceeds', function() {
1553
- let executor = new FakeExecutor().
1554
- expect(CName.FIND_ELEMENTS,
1555
- {using: 'css selector', value: '*[id="foo"]'}).
1556
- andReturnSuccess([]).
1557
- times(2).
1558
- expect(CName.FIND_ELEMENTS,
1559
- {using: 'css selector', value: '*[id="foo"]'}).
1560
- andReturnSuccess([WebElement.buildId('bar')]).
1561
- end();
1562
-
1563
- var driver = executor.createDriver();
1564
- driver.wait(function() {
1565
- return driver.findElements(By.id('foo')).then(els => els.length > 0);
1566
- }, 200);
1567
- return waitForIdle();
1568
- });
1569
-
1570
- it('waitTimesout_timeoutCaught', function() {
1571
- let executor = new FakeExecutor().
1572
- expect(CName.FIND_ELEMENTS,
1573
- {using: 'css selector', value: '*[id="foo"]'}).
1574
- andReturnSuccess([]).
1575
- anyTimes().
1576
- end();
1553
+ describe('supports custom wait functions', function() {
1554
+ it('waitSucceeds', function() {
1555
+ let executor = new FakeExecutor().
1556
+ expect(CName.FIND_ELEMENTS,
1557
+ {using: 'css selector', value: '*[id="foo"]'}).
1558
+ andReturnSuccess([]).
1559
+ times(2).
1560
+ expect(CName.FIND_ELEMENTS,
1561
+ {using: 'css selector', value: '*[id="foo"]'}).
1562
+ andReturnSuccess([WebElement.buildId('bar')]).
1563
+ end();
1577
1564
 
1578
- var driver = executor.createDriver();
1579
- return driver.wait(function() {
1580
- return driver.findElements(By.id('foo')).then(els => els.length > 0);
1581
- }, 25).then(fail, function(e) {
1582
- assert.equal('Wait timed out after ',
1583
- e.message.substring(0, 'Wait timed out after '.length));
1565
+ var driver = executor.createDriver();
1566
+ driver.wait(function() {
1567
+ return driver.findElements(By.id('foo')).then(els => els.length > 0);
1568
+ }, 200);
1569
+ return waitForIdle();
1584
1570
  });
1585
- });
1586
1571
 
1587
- enablePromiseManager(() => {
1588
- it('waitTimesout_timeoutNotCaught', function() {
1572
+ it('waitTimesout_timeoutCaught', function() {
1589
1573
  let executor = new FakeExecutor().
1590
1574
  expect(CName.FIND_ELEMENTS,
1591
1575
  {using: 'css selector', value: '*[id="foo"]'}).
@@ -1594,14 +1578,94 @@ describe('WebDriver', function() {
1594
1578
  end();
1595
1579
 
1596
1580
  var driver = executor.createDriver();
1597
- driver.wait(function() {
1581
+ return driver.wait(function() {
1598
1582
  return driver.findElements(By.id('foo')).then(els => els.length > 0);
1599
- }, 25);
1600
- return waitForAbort().then(function(e) {
1583
+ }, 25).then(fail, function(e) {
1601
1584
  assert.equal('Wait timed out after ',
1602
1585
  e.message.substring(0, 'Wait timed out after '.length));
1603
1586
  });
1604
1587
  });
1588
+
1589
+ enablePromiseManager(() => {
1590
+ it('waitTimesout_timeoutNotCaught', function() {
1591
+ let executor = new FakeExecutor().
1592
+ expect(CName.FIND_ELEMENTS,
1593
+ {using: 'css selector', value: '*[id="foo"]'}).
1594
+ andReturnSuccess([]).
1595
+ anyTimes().
1596
+ end();
1597
+
1598
+ var driver = executor.createDriver();
1599
+ driver.wait(function() {
1600
+ return driver.findElements(By.id('foo')).then(els => els.length > 0);
1601
+ }, 25);
1602
+ return waitForAbort().then(function(e) {
1603
+ assert.equal('Wait timed out after ',
1604
+ e.message.substring(0, 'Wait timed out after '.length));
1605
+ });
1606
+ });
1607
+ });
1608
+ });
1609
+
1610
+ describe('supports condition objects', function() {
1611
+ it('wait succeeds', function() {
1612
+ let executor = new FakeExecutor()
1613
+ .expect(CName.FIND_ELEMENTS,
1614
+ {using: 'css selector', value: '*[id="foo"]'})
1615
+ .andReturnSuccess([])
1616
+ .times(2)
1617
+ .expect(CName.FIND_ELEMENTS,
1618
+ {using: 'css selector', value: '*[id="foo"]'})
1619
+ .andReturnSuccess([WebElement.buildId('bar')])
1620
+ .end();
1621
+
1622
+ let driver = executor.createDriver();
1623
+ return driver.wait(until.elementLocated(By.id('foo')), 200);
1624
+ });
1625
+
1626
+ it('wait times out', function() {
1627
+ let executor = new FakeExecutor()
1628
+ .expect(CName.FIND_ELEMENTS,
1629
+ {using: 'css selector', value: '*[id="foo"]'})
1630
+ .andReturnSuccess([])
1631
+ .anyTimes()
1632
+ .end();
1633
+
1634
+ let driver = executor.createDriver();
1635
+ return driver.wait(until.elementLocated(By.id('foo')), 5)
1636
+ .then(fail, err => assert.ok(err instanceof error.TimeoutError));
1637
+ });
1638
+ });
1639
+
1640
+ describe('supports promise objects', function() {
1641
+ it('wait succeeds', function() {
1642
+ let promise = new Promise(resolve => {
1643
+ setTimeout(() => resolve(1), 10);
1644
+ });
1645
+
1646
+ let driver = new FakeExecutor().createDriver();
1647
+ return driver.wait(promise, 200).then(v => assert.equal(v, 1));
1648
+ });
1649
+
1650
+ it('wait times out', function() {
1651
+ let promise = new Promise(resolve => {/* never resolves */});
1652
+
1653
+ let driver = new FakeExecutor().createDriver();
1654
+ return driver.wait(promise, 5)
1655
+ .then(fail, err => assert.ok(err instanceof error.TimeoutError));
1656
+ });
1657
+
1658
+ it('wait fails if promise is rejected', function() {
1659
+ let err = Error('boom');
1660
+ let driver = new FakeExecutor().createDriver();
1661
+ return driver.wait(Promise.reject(err), 5)
1662
+ .then(fail, e => assert.strictEqual(e, err));
1663
+ });
1664
+ });
1665
+
1666
+ it('fails if not supported condition type provided', function() {
1667
+ let driver = new FakeExecutor().createDriver();
1668
+ assert.throws(() => driver.wait({}, 5), TypeError);
1605
1669
  });
1606
1670
  });
1607
1671
 
@@ -1773,7 +1837,7 @@ describe('WebDriver', function() {
1773
1837
 
1774
1838
  describe('actions()', function() {
1775
1839
  it('failsIfInitialDriverCreationFailed', function() {
1776
- let session = Promise.reject(new StubError);
1840
+ let session = Promise.reject(new StubError('no session for you'));
1777
1841
  let driver = new FakeExecutor().createDriver(session);
1778
1842
  driver.getSession().catch(function() {});
1779
1843
  return driver.