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.
- package/CHANGES.md +92 -0
- package/NOTICE +1 -1
- package/README.md +11 -14
- package/chrome.js +125 -36
- package/edge.js +3 -3
- package/example/async_await_test.js +68 -0
- package/example/chrome_headless.js +47 -0
- package/example/chrome_mobile_emulation.js +1 -1
- package/example/firefox_channels.js +73 -0
- package/example/google_search_test.js +1 -1
- package/firefox/binary.js +114 -57
- package/firefox/extension.js +118 -81
- package/firefox/index.js +67 -135
- package/firefox/profile.js +13 -49
- package/ie.js +2 -2
- package/index.js +6 -3
- package/io/index.js +59 -0
- package/io/zip.js +214 -0
- package/lib/README +2 -3
- package/lib/actions.js +4 -4
- package/lib/atoms/getAttribute.js +9 -11
- package/lib/atoms/is-displayed.js +102 -0
- package/lib/by.js +9 -1
- package/lib/capabilities.js +5 -5
- package/lib/command.js +2 -0
- package/lib/error.js +29 -4
- package/lib/events.js +1 -1
- package/lib/firefox/webdriver.json +2 -1
- package/lib/http.js +84 -69
- package/lib/input.js +1 -1
- package/lib/promise.js +205 -81
- package/lib/symbols.js +1 -1
- package/lib/test/data/click_tests/disabled_element.html +12 -0
- package/lib/test/data/firefox/webextension.xpi +0 -0
- package/lib/test/data/key_logger.html +34 -0
- package/lib/test/data/nestedElements.html +10 -1
- package/lib/test/data/single_text_input.html +12 -0
- package/lib/test/index.js +9 -35
- package/lib/until.js +1 -1
- package/lib/webdriver.js +130 -34
- package/net/portprober.js +1 -1
- package/opera.js +2 -2
- package/package.json +2 -2
- package/phantomjs.js +2 -2
- package/remote/index.js +17 -11
- package/safari.js +47 -8
- package/test/firefox/extension_test.js +41 -17
- package/test/firefox/firefox_test.js +70 -23
- package/test/firefox/profile_test.js +14 -59
- package/test/http/http_test.js +18 -0
- package/test/{io_test.js → io/io_test.js} +40 -1
- package/test/io/zip_test.js +128 -0
- package/test/lib/by_test.js +21 -0
- package/test/lib/error_test.js +20 -1
- package/test/lib/http_test.js +41 -2
- package/test/lib/promise_test.js +19 -0
- package/test/lib/until_test.js +28 -13
- package/test/lib/webdriver_test.js +107 -3
- package/test/page_loading_test.js +0 -6
- package/test/rect_test.js +60 -0
- package/test/remote_test.js +3 -3
- package/test/session_test.js +68 -23
- package/testing/index.js +16 -5
- package/lib/atoms/isDisplayed.js +0 -106
- package/lib/firefox/amd64/libnoblur64.so +0 -0
- package/lib/firefox/i386/libnoblur.so +0 -0
- package/lib/firefox/webdriver.xpi +0 -0
package/lib/promise.js
CHANGED
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
* > e => console.error('FAILURE: ' + e));
|
|
49
49
|
* > ```
|
|
50
50
|
* >
|
|
51
|
-
* > The
|
|
51
|
+
* > The motivation behind this change and full deprecation plan are documented
|
|
52
52
|
* > in [issue 2969](https://github.com/SeleniumHQ/selenium/issues/2969).
|
|
53
53
|
* >
|
|
54
54
|
* >
|
|
@@ -87,8 +87,7 @@
|
|
|
87
87
|
* The control flow is based on the concept of tasks and task queues. Tasks are
|
|
88
88
|
* functions that define the basic unit of work for the control flow to execute.
|
|
89
89
|
* Each task is scheduled via {@link ControlFlow#execute()}, which will return
|
|
90
|
-
* a {@link ManagedPromise
|
|
91
|
-
* result.
|
|
90
|
+
* a {@link ManagedPromise} that will be resolved with the task's result.
|
|
92
91
|
*
|
|
93
92
|
* A task queue contains all of the tasks scheduled within a single turn of the
|
|
94
93
|
* [JavaScript event loop][JSEL]. The control flow will create a new task queue
|
|
@@ -103,13 +102,13 @@
|
|
|
103
102
|
*
|
|
104
103
|
* Whenever the control flow creates a new task queue, it will automatically
|
|
105
104
|
* begin executing tasks in the next available turn of the event loop. This
|
|
106
|
-
* execution is scheduled
|
|
107
|
-
* `
|
|
105
|
+
* execution is [scheduled as a microtask][MicrotasksArticle] like e.g. a
|
|
106
|
+
* (native) `Promise.then()` callback.
|
|
108
107
|
*
|
|
109
108
|
* setTimeout(() => console.log('a'));
|
|
110
|
-
*
|
|
109
|
+
* Promise.resolve().then(() => console.log('b')); // A native promise.
|
|
111
110
|
* flow.execute(() => console.log('c'));
|
|
112
|
-
*
|
|
111
|
+
* Promise.resolve().then(() => console.log('d'));
|
|
113
112
|
* setTimeout(() => console.log('fin'));
|
|
114
113
|
* // b
|
|
115
114
|
* // c
|
|
@@ -118,13 +117,13 @@
|
|
|
118
117
|
* // fin
|
|
119
118
|
*
|
|
120
119
|
* In the example above, b/c/d is logged before a/fin because native promises
|
|
121
|
-
* and this module use "
|
|
122
|
-
* "
|
|
120
|
+
* and this module use "microtask" timers, which have a higher priority than
|
|
121
|
+
* "macrotasks" like `setTimeout`.
|
|
123
122
|
*
|
|
124
123
|
* ## Task Execution
|
|
125
124
|
*
|
|
126
|
-
* Upon creating a task queue, and whenever an
|
|
127
|
-
* the control flow will schedule a
|
|
125
|
+
* Upon creating a task queue, and whenever an existing queue completes a task,
|
|
126
|
+
* the control flow will schedule a microtask timer to process any scheduled
|
|
128
127
|
* tasks. This ensures no task is ever started within the same turn of the
|
|
129
128
|
* JavaScript event loop in which it was scheduled, nor is a task ever started
|
|
130
129
|
* within the same turn that another finishes.
|
|
@@ -140,13 +139,13 @@
|
|
|
140
139
|
* discarded and the task's promised result (previously returned by
|
|
141
140
|
* {@link ControlFlow#execute()}) is immediately rejected with the thrown
|
|
142
141
|
* error.
|
|
143
|
-
* 3. The task function returns
|
|
142
|
+
* 3. The task function returns successfully.
|
|
144
143
|
*
|
|
145
144
|
* If a task function created a new task queue, the control flow will wait for
|
|
146
145
|
* that queue to complete before processing the task result. If the queue
|
|
147
146
|
* completes without error, the flow will settle the task's promise with the
|
|
148
|
-
* value
|
|
149
|
-
* queue
|
|
147
|
+
* value originally returned by the task function. On the other hand, if the task
|
|
148
|
+
* queue terminates with an error, the task's promise will be rejected with that
|
|
150
149
|
* error.
|
|
151
150
|
*
|
|
152
151
|
* flow.execute(function() {
|
|
@@ -161,7 +160,7 @@
|
|
|
161
160
|
* ## ManagedPromise Integration
|
|
162
161
|
*
|
|
163
162
|
* In addition to the {@link ControlFlow} class, the promise module also exports
|
|
164
|
-
* a [
|
|
163
|
+
* a [Promises/A+] {@linkplain ManagedPromise implementation} that is deeply
|
|
165
164
|
* integrated with the ControlFlow. First and foremost, each promise
|
|
166
165
|
* {@linkplain ManagedPromise#then() callback} is scheduled with the
|
|
167
166
|
* control flow as a task. As a result, each callback is invoked in its own turn
|
|
@@ -328,7 +327,7 @@
|
|
|
328
327
|
* Even though a subtask's promised result will never resolve while the task
|
|
329
328
|
* function is on the stack, it will be treated as a promise resolved within the
|
|
330
329
|
* task. In all other scenarios, a task's promise behaves just like a normal
|
|
331
|
-
* promise. In the sample below, `C/D` is
|
|
330
|
+
* promise. In the sample below, `C/D` is logged before `B` because the
|
|
332
331
|
* resolution of `subtask1` interrupts the flow of the enclosing task. Within
|
|
333
332
|
* the final subtask, `E/F` is logged in order because `subtask1` is a resolved
|
|
334
333
|
* promise when that task runs.
|
|
@@ -467,17 +466,17 @@
|
|
|
467
466
|
*
|
|
468
467
|
* ES6 promises do not require users to handle a promise rejections. This can
|
|
469
468
|
* result in subtle bugs as the rejections are silently "swallowed" by the
|
|
470
|
-
*
|
|
469
|
+
* Promise class.
|
|
471
470
|
*
|
|
472
|
-
*
|
|
471
|
+
* Promise.reject(Error('boom'));
|
|
473
472
|
* // ... *crickets* ...
|
|
474
473
|
*
|
|
475
474
|
* Selenium's promise module, on the other hand, requires that every rejection
|
|
476
475
|
* be explicitly handled. When a {@linkplain ManagedPromise ManagedPromise} is
|
|
477
476
|
* rejected and no callbacks are defined on that promise, it is considered an
|
|
478
|
-
* _unhandled rejection_ and
|
|
477
|
+
* _unhandled rejection_ and reported to the active task queue. If the rejection
|
|
479
478
|
* remains unhandled after a single turn of the [event loop][JSEL] (scheduled
|
|
480
|
-
* with a
|
|
479
|
+
* with a microtask), it will propagate up the stack.
|
|
481
480
|
*
|
|
482
481
|
* ## Error Propagation
|
|
483
482
|
*
|
|
@@ -534,7 +533,7 @@
|
|
|
534
533
|
*
|
|
535
534
|
* When a subtask is discarded due to an unreported rejection in its parent
|
|
536
535
|
* frame, the existing callbacks on that task will never settle and the
|
|
537
|
-
* callbacks will not be invoked. If a new callback is attached
|
|
536
|
+
* callbacks will not be invoked. If a new callback is attached to the subtask
|
|
538
537
|
* _after_ it has been discarded, it is handled the same as adding a callback
|
|
539
538
|
* to a cancelled promise: the error-callback path is invoked. This behavior is
|
|
540
539
|
* intended to handle cases where the user saves a reference to a task promise,
|
|
@@ -582,9 +581,9 @@
|
|
|
582
581
|
*
|
|
583
582
|
* Bottom line: you __*must*__ handle rejected promises.
|
|
584
583
|
*
|
|
585
|
-
* #
|
|
584
|
+
* # Promises/A+ Compatibility
|
|
586
585
|
*
|
|
587
|
-
* This `promise` module is compliant with the [
|
|
586
|
+
* This `promise` module is compliant with the [Promises/A+] specification
|
|
588
587
|
* except for sections `2.2.6.1` and `2.2.6.2`:
|
|
589
588
|
*
|
|
590
589
|
* >
|
|
@@ -595,10 +594,10 @@
|
|
|
595
594
|
* > must execute in the order of their originating calls to `then`.
|
|
596
595
|
* >
|
|
597
596
|
*
|
|
598
|
-
* Specifically, the conformance tests
|
|
597
|
+
* Specifically, the conformance tests contain the following scenario (for
|
|
599
598
|
* brevity, only the fulfillment version is shown):
|
|
600
599
|
*
|
|
601
|
-
* var p1 =
|
|
600
|
+
* var p1 = Promise.resolve();
|
|
602
601
|
* p1.then(function() {
|
|
603
602
|
* console.log('A');
|
|
604
603
|
* p1.then(() => console.log('B'));
|
|
@@ -609,7 +608,7 @@
|
|
|
609
608
|
* // B
|
|
610
609
|
*
|
|
611
610
|
* Since the [ControlFlow](#scheduling_callbacks) executes promise callbacks as
|
|
612
|
-
* tasks, with this module, the result would be
|
|
611
|
+
* tasks, with this module, the result would be:
|
|
613
612
|
*
|
|
614
613
|
* var p2 = promise.fulfilled();
|
|
615
614
|
* p2.then(function() {
|
|
@@ -623,7 +622,8 @@
|
|
|
623
622
|
*
|
|
624
623
|
* [JSEL]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop
|
|
625
624
|
* [GF]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*
|
|
626
|
-
* [
|
|
625
|
+
* [Promises/A+]: https://promisesaplus.com/
|
|
626
|
+
* [MicrotasksArticle]: https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/
|
|
627
627
|
*/
|
|
628
628
|
|
|
629
629
|
'use strict';
|
|
@@ -667,7 +667,7 @@ function getUid(obj) {
|
|
|
667
667
|
|
|
668
668
|
|
|
669
669
|
/**
|
|
670
|
-
* Runs the given function after a
|
|
670
|
+
* Runs the given function after a microtask yield.
|
|
671
671
|
* @param {function()} fn The function to run.
|
|
672
672
|
*/
|
|
673
673
|
function asyncRun(fn) {
|
|
@@ -942,7 +942,7 @@ class Thenable {
|
|
|
942
942
|
|
|
943
943
|
/**
|
|
944
944
|
* Marker interface for objects that allow consumers to request the cancellation
|
|
945
|
-
* of a
|
|
945
|
+
* of a promise-based operation. A cancelled promise will be rejected with a
|
|
946
946
|
* {@link CancellationError}.
|
|
947
947
|
*
|
|
948
948
|
* This interface is considered package-private and should not be used outside
|
|
@@ -1003,6 +1003,9 @@ const PromiseState = {
|
|
|
1003
1003
|
*/
|
|
1004
1004
|
const ON_CANCEL_HANDLER = new WeakMap;
|
|
1005
1005
|
|
|
1006
|
+
const SKIP_LOG = Symbol('skip-log');
|
|
1007
|
+
const FLOW_LOG = logging.getLogger('promise.ControlFlow');
|
|
1008
|
+
|
|
1006
1009
|
|
|
1007
1010
|
/**
|
|
1008
1011
|
* Represents the eventual value of a completed operation. Each promise may be
|
|
@@ -1025,14 +1028,29 @@ class ManagedPromise {
|
|
|
1025
1028
|
* functions, one for fulfilling the promise and another for rejecting it.
|
|
1026
1029
|
* @param {ControlFlow=} opt_flow The control flow
|
|
1027
1030
|
* this instance was created under. Defaults to the currently active flow.
|
|
1031
|
+
* @param {?=} opt_skipLog An internal parameter used to skip logging the
|
|
1032
|
+
* creation of this promise. This parameter has no effect unless it is
|
|
1033
|
+
* strictly equal to an internal symbol. In other words, this parameter
|
|
1034
|
+
* is always ignored for external code.
|
|
1028
1035
|
*/
|
|
1029
|
-
constructor(resolver, opt_flow) {
|
|
1036
|
+
constructor(resolver, opt_flow, opt_skipLog) {
|
|
1030
1037
|
if (!usePromiseManager()) {
|
|
1031
1038
|
throw TypeError(
|
|
1032
1039
|
'Unable to create a managed promise instance: the promise manager has'
|
|
1033
1040
|
+ ' been disabled by the SELENIUM_PROMISE_MANAGER environment'
|
|
1034
1041
|
+ ' variable: ' + process.env['SELENIUM_PROMISE_MANAGER']);
|
|
1042
|
+
} else if (opt_skipLog !== SKIP_LOG) {
|
|
1043
|
+
FLOW_LOG.warning(() => {
|
|
1044
|
+
let e =
|
|
1045
|
+
captureStackTrace(
|
|
1046
|
+
'ManagedPromiseError',
|
|
1047
|
+
'Creating a new managed Promise. This call will fail when the'
|
|
1048
|
+
+ ' promise manager is disabled',
|
|
1049
|
+
ManagedPromise)
|
|
1050
|
+
return e.stack;
|
|
1051
|
+
});
|
|
1035
1052
|
}
|
|
1053
|
+
|
|
1036
1054
|
getUid(this);
|
|
1037
1055
|
|
|
1038
1056
|
/** @private {!ControlFlow} */
|
|
@@ -1308,7 +1326,7 @@ class ManagedPromise {
|
|
|
1308
1326
|
* @param {!Function} fn The function to use as the top of the stack when
|
|
1309
1327
|
* recording the callback's creation point.
|
|
1310
1328
|
* @return {!ManagedPromise<R>} A new promise which will be resolved with the
|
|
1311
|
-
*
|
|
1329
|
+
* result of the invoked callback.
|
|
1312
1330
|
* @template R
|
|
1313
1331
|
* @private
|
|
1314
1332
|
*/
|
|
@@ -1383,6 +1401,37 @@ function isPending(promise) {
|
|
|
1383
1401
|
}
|
|
1384
1402
|
|
|
1385
1403
|
|
|
1404
|
+
/**
|
|
1405
|
+
* Structural interface for a deferred promise resolver.
|
|
1406
|
+
* @record
|
|
1407
|
+
* @template T
|
|
1408
|
+
*/
|
|
1409
|
+
function Resolver() {}
|
|
1410
|
+
|
|
1411
|
+
|
|
1412
|
+
/**
|
|
1413
|
+
* The promised value for this resolver.
|
|
1414
|
+
* @type {!Thenable<T>}
|
|
1415
|
+
*/
|
|
1416
|
+
Resolver.prototype.promise;
|
|
1417
|
+
|
|
1418
|
+
|
|
1419
|
+
/**
|
|
1420
|
+
* Resolves the promised value with the given `value`.
|
|
1421
|
+
* @param {T|Thenable<T>} value
|
|
1422
|
+
* @return {void}
|
|
1423
|
+
*/
|
|
1424
|
+
Resolver.prototype.resolve;
|
|
1425
|
+
|
|
1426
|
+
|
|
1427
|
+
/**
|
|
1428
|
+
* Rejects the promised value with the given `reason`.
|
|
1429
|
+
* @param {*} reason
|
|
1430
|
+
* @return {void}
|
|
1431
|
+
*/
|
|
1432
|
+
Resolver.prototype.reject;
|
|
1433
|
+
|
|
1434
|
+
|
|
1386
1435
|
/**
|
|
1387
1436
|
* Represents a value that will be resolved at some point in the future. This
|
|
1388
1437
|
* class represents the protected "producer" half of a ManagedPromise - each Deferred
|
|
@@ -1395,20 +1444,25 @@ function isPending(promise) {
|
|
|
1395
1444
|
* {@link ControlFlow} as an unhandled failure.
|
|
1396
1445
|
*
|
|
1397
1446
|
* @template T
|
|
1447
|
+
* @implements {Resolver<T>}
|
|
1398
1448
|
*/
|
|
1399
1449
|
class Deferred {
|
|
1400
1450
|
/**
|
|
1401
1451
|
* @param {ControlFlow=} opt_flow The control flow this instance was
|
|
1402
1452
|
* created under. This should only be provided during unit tests.
|
|
1453
|
+
* @param {?=} opt_skipLog An internal parameter used to skip logging the
|
|
1454
|
+
* creation of this promise. This parameter has no effect unless it is
|
|
1455
|
+
* strictly equal to an internal symbol. In other words, this parameter
|
|
1456
|
+
* is always ignored for external code.
|
|
1403
1457
|
*/
|
|
1404
|
-
constructor(opt_flow) {
|
|
1458
|
+
constructor(opt_flow, opt_skipLog) {
|
|
1405
1459
|
var fulfill, reject;
|
|
1406
1460
|
|
|
1407
1461
|
/** @type {!ManagedPromise<T>} */
|
|
1408
1462
|
this.promise = new ManagedPromise(function(f, r) {
|
|
1409
1463
|
fulfill = f;
|
|
1410
1464
|
reject = r;
|
|
1411
|
-
}, opt_flow);
|
|
1465
|
+
}, opt_flow, opt_skipLog);
|
|
1412
1466
|
|
|
1413
1467
|
var self = this;
|
|
1414
1468
|
var checkNotSelf = function(value) {
|
|
@@ -1421,16 +1475,24 @@ class Deferred {
|
|
|
1421
1475
|
* Resolves this deferred with the given value. It is safe to call this as a
|
|
1422
1476
|
* normal function (with no bound "this").
|
|
1423
1477
|
* @param {(T|IThenable<T>|Thenable)=} opt_value The fulfilled value.
|
|
1478
|
+
* @const
|
|
1424
1479
|
*/
|
|
1425
|
-
this.
|
|
1480
|
+
this.resolve = function(opt_value) {
|
|
1426
1481
|
checkNotSelf(opt_value);
|
|
1427
1482
|
fulfill(opt_value);
|
|
1428
1483
|
};
|
|
1429
1484
|
|
|
1485
|
+
/**
|
|
1486
|
+
* An alias for {@link #resolve}.
|
|
1487
|
+
* @const
|
|
1488
|
+
*/
|
|
1489
|
+
this.fulfill = this.resolve;
|
|
1490
|
+
|
|
1430
1491
|
/**
|
|
1431
1492
|
* Rejects this promise with the given reason. It is safe to call this as a
|
|
1432
1493
|
* normal function (with no bound "this").
|
|
1433
1494
|
* @param {*=} opt_reason The rejection reason.
|
|
1495
|
+
* @const
|
|
1434
1496
|
*/
|
|
1435
1497
|
this.reject = function(opt_reason) {
|
|
1436
1498
|
checkNotSelf(opt_reason);
|
|
@@ -1487,36 +1549,76 @@ function delayed(ms) {
|
|
|
1487
1549
|
|
|
1488
1550
|
|
|
1489
1551
|
/**
|
|
1490
|
-
* Creates a new deferred
|
|
1491
|
-
*
|
|
1552
|
+
* Creates a new deferred resolver.
|
|
1553
|
+
*
|
|
1554
|
+
* If the promise manager is currently enabled, this function will return a
|
|
1555
|
+
* {@link Deferred} instance. Otherwise, it will return a resolver for a
|
|
1556
|
+
* {@linkplain NativePromise native promise}.
|
|
1557
|
+
*
|
|
1558
|
+
* @return {!Resolver<T>} A new deferred resolver.
|
|
1492
1559
|
* @template T
|
|
1493
1560
|
*/
|
|
1494
1561
|
function defer() {
|
|
1495
|
-
|
|
1562
|
+
if (usePromiseManager()) {
|
|
1563
|
+
return new Deferred();
|
|
1564
|
+
}
|
|
1565
|
+
let resolve, reject;
|
|
1566
|
+
let promise = new NativePromise((_resolve, _reject) => {
|
|
1567
|
+
resolve = _resolve;
|
|
1568
|
+
reject = _reject;
|
|
1569
|
+
});
|
|
1570
|
+
return {promise, resolve, reject};
|
|
1496
1571
|
}
|
|
1497
1572
|
|
|
1498
1573
|
|
|
1499
1574
|
/**
|
|
1500
1575
|
* Creates a promise that has been resolved with the given value.
|
|
1576
|
+
*
|
|
1577
|
+
* If the promise manager is currently enabled, this function will return a
|
|
1578
|
+
* {@linkplain ManagedPromise managed promise}. Otherwise, it will return a
|
|
1579
|
+
* {@linkplain NativePromise native promise}.
|
|
1580
|
+
*
|
|
1501
1581
|
* @param {T=} opt_value The resolved value.
|
|
1502
|
-
* @return {!
|
|
1503
|
-
* @deprecated Use {@link ManagedPromise#resolve Promise.resolve(value)}.
|
|
1582
|
+
* @return {!Thenable<T>} The resolved promise.
|
|
1504
1583
|
* @template T
|
|
1505
1584
|
*/
|
|
1506
1585
|
function fulfilled(opt_value) {
|
|
1507
|
-
|
|
1586
|
+
let ctor = usePromiseManager() ? ManagedPromise : NativePromise;
|
|
1587
|
+
if (opt_value instanceof ctor) {
|
|
1588
|
+
return /** @type {!Thenable} */(opt_value);
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1591
|
+
if (usePromiseManager()) {
|
|
1592
|
+
// We can skip logging warnings about creating a managed promise because
|
|
1593
|
+
// this function will automatically switch to use a native promise when
|
|
1594
|
+
// the promise manager is disabled.
|
|
1595
|
+
return new ManagedPromise(
|
|
1596
|
+
resolve => resolve(opt_value), undefined, SKIP_LOG);
|
|
1597
|
+
}
|
|
1598
|
+
return NativePromise.resolve(opt_value);
|
|
1508
1599
|
}
|
|
1509
1600
|
|
|
1510
1601
|
|
|
1511
1602
|
/**
|
|
1512
1603
|
* Creates a promise that has been rejected with the given reason.
|
|
1604
|
+
*
|
|
1605
|
+
* If the promise manager is currently enabled, this function will return a
|
|
1606
|
+
* {@linkplain ManagedPromise managed promise}. Otherwise, it will return a
|
|
1607
|
+
* {@linkplain NativePromise native promise}.
|
|
1608
|
+
*
|
|
1513
1609
|
* @param {*=} opt_reason The rejection reason; may be any value, but is
|
|
1514
1610
|
* usually an Error or a string.
|
|
1515
|
-
* @return {!
|
|
1516
|
-
* @deprecated Use {@link ManagedPromise#reject Promise.reject(reason)}.
|
|
1611
|
+
* @return {!Thenable<?>} The rejected promise.
|
|
1517
1612
|
*/
|
|
1518
1613
|
function rejected(opt_reason) {
|
|
1519
|
-
|
|
1614
|
+
if (usePromiseManager()) {
|
|
1615
|
+
// We can skip logging warnings about creating a managed promise because
|
|
1616
|
+
// this function will automatically switch to use a native promise when
|
|
1617
|
+
// the promise manager is disabled.
|
|
1618
|
+
return new ManagedPromise(
|
|
1619
|
+
(_, reject) => reject(opt_reason), undefined, SKIP_LOG);
|
|
1620
|
+
}
|
|
1621
|
+
return NativePromise.reject(opt_reason);
|
|
1520
1622
|
}
|
|
1521
1623
|
|
|
1522
1624
|
|
|
@@ -1610,21 +1712,17 @@ function thenFinally(promise, callback) {
|
|
|
1610
1712
|
* @param {Function=} opt_errback The function to call when the value is
|
|
1611
1713
|
* rejected.
|
|
1612
1714
|
* @return {!Thenable} A new promise.
|
|
1715
|
+
* @deprecated Use `promise.fulfilled(value).then(opt_callback, opt_errback)`
|
|
1613
1716
|
*/
|
|
1614
1717
|
function when(value, opt_callback, opt_errback) {
|
|
1615
|
-
|
|
1616
|
-
return value.then(opt_callback, opt_errback);
|
|
1617
|
-
}
|
|
1618
|
-
|
|
1619
|
-
return createPromise(resolve => resolve(value))
|
|
1620
|
-
.then(opt_callback, opt_errback);
|
|
1718
|
+
return fulfilled(value).then(opt_callback, opt_errback);
|
|
1621
1719
|
}
|
|
1622
1720
|
|
|
1623
1721
|
|
|
1624
1722
|
/**
|
|
1625
1723
|
* Invokes the appropriate callback function as soon as a promised `value` is
|
|
1626
|
-
* resolved.
|
|
1627
|
-
*
|
|
1724
|
+
* resolved.
|
|
1725
|
+
*
|
|
1628
1726
|
* @param {*} value The value to observe.
|
|
1629
1727
|
* @param {Function} callback The function to call when the value is
|
|
1630
1728
|
* resolved successfully.
|
|
@@ -1826,7 +1924,7 @@ function filter(arr, fn, opt_self) {
|
|
|
1826
1924
|
*/
|
|
1827
1925
|
function fullyResolved(value) {
|
|
1828
1926
|
if (isPromise(value)) {
|
|
1829
|
-
return
|
|
1927
|
+
return fulfilled(value).then(fullyResolveValue);
|
|
1830
1928
|
}
|
|
1831
1929
|
return fullyResolveValue(value);
|
|
1832
1930
|
}
|
|
@@ -1973,7 +2071,7 @@ class Scheduler {
|
|
|
1973
2071
|
/**
|
|
1974
2072
|
* Schedules a task to wait for a condition to hold.
|
|
1975
2073
|
*
|
|
1976
|
-
* If the condition is defined as a function, it may return any value.
|
|
2074
|
+
* If the condition is defined as a function, it may return any value. Promise
|
|
1977
2075
|
* will be resolved before testing if the condition holds (resolution time
|
|
1978
2076
|
* counts towards the timeout). Once resolved, values are always evaluated as
|
|
1979
2077
|
* booleans.
|
|
@@ -1997,7 +2095,7 @@ class Scheduler {
|
|
|
1997
2095
|
* @param {string=} opt_message An optional error message to include if the
|
|
1998
2096
|
* wait times out; defaults to the empty string.
|
|
1999
2097
|
* @return {!Thenable<T>} A promise that will be fulfilled
|
|
2000
|
-
* when the condition has been
|
|
2098
|
+
* when the condition has been satisfied. The promise shall be rejected
|
|
2001
2099
|
* if the wait times out waiting for the condition.
|
|
2002
2100
|
* @throws {TypeError} If condition is not a function or promise or if timeout
|
|
2003
2101
|
* is not a number >= 0.
|
|
@@ -2018,6 +2116,10 @@ function usePromiseManager() {
|
|
|
2018
2116
|
|
|
2019
2117
|
|
|
2020
2118
|
/**
|
|
2119
|
+
* Creates a new promise with the given `resolver` function. If the promise
|
|
2120
|
+
* manager is currently enabled, the returned promise will be a
|
|
2121
|
+
* {@linkplain ManagedPromise} instance. Otherwise, it will be a native promise.
|
|
2122
|
+
*
|
|
2021
2123
|
* @param {function(
|
|
2022
2124
|
* function((T|IThenable<T>|Thenable|null)=),
|
|
2023
2125
|
* function(*=))} resolver
|
|
@@ -2040,7 +2142,7 @@ function createPromise(resolver) {
|
|
|
2040
2142
|
* @param {string=} opt_message An optional error message to include if the
|
|
2041
2143
|
* wait times out; defaults to the empty string.
|
|
2042
2144
|
* @return {!Thenable<T>} A promise that will be fulfilled
|
|
2043
|
-
* when the condition has been
|
|
2145
|
+
* when the condition has been satisfied. The promise shall be rejected
|
|
2044
2146
|
* if the wait times out waiting for the condition.
|
|
2045
2147
|
* @throws {TypeError} If condition is not a function or promise or if timeout
|
|
2046
2148
|
* is not a number >= 0.
|
|
@@ -2164,7 +2266,7 @@ const SIMPLE_SCHEDULER = new SimpleScheduler;
|
|
|
2164
2266
|
/**
|
|
2165
2267
|
* Handles the execution of scheduled tasks, each of which may be an
|
|
2166
2268
|
* asynchronous operation. The control flow will ensure tasks are executed in
|
|
2167
|
-
* the
|
|
2269
|
+
* the order scheduled, starting each task only once those before it have
|
|
2168
2270
|
* completed.
|
|
2169
2271
|
*
|
|
2170
2272
|
* Each task scheduled within this flow may return a {@link ManagedPromise} to
|
|
@@ -2172,21 +2274,21 @@ const SIMPLE_SCHEDULER = new SimpleScheduler;
|
|
|
2172
2274
|
* promises to be resolved before marking the task as completed.
|
|
2173
2275
|
*
|
|
2174
2276
|
* Tasks and each callback registered on a {@link ManagedPromise} will be run
|
|
2175
|
-
* in their own ControlFlow frame.
|
|
2277
|
+
* in their own ControlFlow frame. Any tasks scheduled within a frame will take
|
|
2176
2278
|
* priority over previously scheduled tasks. Furthermore, if any of the tasks in
|
|
2177
2279
|
* the frame fail, the remainder of the tasks in that frame will be discarded
|
|
2178
2280
|
* and the failure will be propagated to the user through the callback/task's
|
|
2179
2281
|
* promised result.
|
|
2180
2282
|
*
|
|
2181
2283
|
* Each time a ControlFlow empties its task queue, it will fire an
|
|
2182
|
-
* {@link ControlFlow.EventType.IDLE IDLE} event. Conversely,
|
|
2183
|
-
*
|
|
2284
|
+
* {@link ControlFlow.EventType.IDLE IDLE} event. Conversely, whenever
|
|
2285
|
+
* the flow terminates due to an unhandled error, it will remove all
|
|
2184
2286
|
* remaining tasks in its queue and fire an
|
|
2185
2287
|
* {@link ControlFlow.EventType.UNCAUGHT_EXCEPTION UNCAUGHT_EXCEPTION} event.
|
|
2186
2288
|
* If there are no listeners registered with the flow, the error will be
|
|
2187
2289
|
* rethrown to the global error handler.
|
|
2188
2290
|
*
|
|
2189
|
-
* Refer to the {@link ./promise} module documentation for a
|
|
2291
|
+
* Refer to the {@link ./promise} module documentation for a detailed
|
|
2190
2292
|
* explanation of how the ControlFlow coordinates task execution.
|
|
2191
2293
|
*
|
|
2192
2294
|
* @implements {Scheduler}
|
|
@@ -2212,7 +2314,7 @@ class ControlFlow extends events.EventEmitter {
|
|
|
2212
2314
|
this.taskQueues_ = null;
|
|
2213
2315
|
|
|
2214
2316
|
/**
|
|
2215
|
-
*
|
|
2317
|
+
* Microtask that controls shutting down the control flow. Upon shut down,
|
|
2216
2318
|
* the flow will emit an
|
|
2217
2319
|
* {@link ControlFlow.EventType.IDLE} event. Idle events
|
|
2218
2320
|
* always follow a brief timeout in order to catch latent errors from the
|
|
@@ -2221,8 +2323,8 @@ class ControlFlow extends events.EventEmitter {
|
|
|
2221
2323
|
* by the promise system until the next turn of the event loop:
|
|
2222
2324
|
*
|
|
2223
2325
|
* // Schedule 1 task that fails.
|
|
2224
|
-
* var result = promise.controlFlow().
|
|
2225
|
-
*
|
|
2326
|
+
* var result = promise.controlFlow().execute(
|
|
2327
|
+
* () => promise.rejected('failed'), 'example');
|
|
2226
2328
|
* // Set a callback on the result. This delays reporting the unhandled
|
|
2227
2329
|
* // failure for 1 turn of the event loop.
|
|
2228
2330
|
* result.then(function() {});
|
|
@@ -2246,7 +2348,7 @@ class ControlFlow extends events.EventEmitter {
|
|
|
2246
2348
|
/**
|
|
2247
2349
|
* Returns a string representation of this control flow, which is its current
|
|
2248
2350
|
* {@linkplain #getSchedule() schedule}, sans task stack traces.
|
|
2249
|
-
* @return {string} The string representation of this
|
|
2351
|
+
* @return {string} The string representation of this control flow.
|
|
2250
2352
|
* @override
|
|
2251
2353
|
*/
|
|
2252
2354
|
toString() {
|
|
@@ -2258,8 +2360,7 @@ class ControlFlow extends events.EventEmitter {
|
|
|
2258
2360
|
* control flow stack and cause rejections within parent tasks. If error
|
|
2259
2361
|
* propagation is disabled, tasks will not be aborted when an unhandled
|
|
2260
2362
|
* promise rejection is detected, but the rejection _will_ trigger an
|
|
2261
|
-
* {@link ControlFlow.EventType.UNCAUGHT_EXCEPTION}
|
|
2262
|
-
* event.
|
|
2363
|
+
* {@link ControlFlow.EventType.UNCAUGHT_EXCEPTION} event.
|
|
2263
2364
|
*
|
|
2264
2365
|
* The default behavior is to propagate all unhandled rejections. _The use
|
|
2265
2366
|
* of this option is highly discouraged._
|
|
@@ -2293,7 +2394,7 @@ class ControlFlow extends events.EventEmitter {
|
|
|
2293
2394
|
* {@code opt_includeStackTraces === true}, the string will include the
|
|
2294
2395
|
* stack trace from when each task was scheduled.
|
|
2295
2396
|
* @param {string=} opt_includeStackTraces Whether to include the stack traces
|
|
2296
|
-
*
|
|
2397
|
+
* from when each task was scheduled. Defaults to false.
|
|
2297
2398
|
* @return {string} String representation of this flow's internal state.
|
|
2298
2399
|
*/
|
|
2299
2400
|
getSchedule(opt_includeStackTraces) {
|
|
@@ -2345,7 +2446,7 @@ class ControlFlow extends events.EventEmitter {
|
|
|
2345
2446
|
}
|
|
2346
2447
|
|
|
2347
2448
|
/**
|
|
2348
|
-
* Returns the currently
|
|
2449
|
+
* Returns the currently active task queue for this flow. If there is no
|
|
2349
2450
|
* active queue, one will be created.
|
|
2350
2451
|
* @return {!TaskQueue} the currently active task queue for this flow.
|
|
2351
2452
|
* @private
|
|
@@ -2377,15 +2478,31 @@ class ControlFlow extends events.EventEmitter {
|
|
|
2377
2478
|
}
|
|
2378
2479
|
|
|
2379
2480
|
if (!this.hold_) {
|
|
2380
|
-
|
|
2481
|
+
let holdIntervalMs = 2147483647; // 2^31-1; max timer length for Node.js
|
|
2381
2482
|
this.hold_ = setInterval(function() {}, holdIntervalMs);
|
|
2382
2483
|
}
|
|
2383
2484
|
|
|
2384
|
-
|
|
2485
|
+
let task = new Task(
|
|
2385
2486
|
this, fn, opt_description || '<anonymous>',
|
|
2386
|
-
{name: 'Task', top: ControlFlow.prototype.execute}
|
|
2487
|
+
{name: 'Task', top: ControlFlow.prototype.execute},
|
|
2488
|
+
true);
|
|
2489
|
+
|
|
2490
|
+
let q = this.getActiveQueue_();
|
|
2491
|
+
|
|
2492
|
+
for (let i = q.tasks_.length; i > 0; i--) {
|
|
2493
|
+
let previousTask = q.tasks_[i - 1];
|
|
2494
|
+
if (previousTask.userTask_) {
|
|
2495
|
+
FLOW_LOG.warning(() => {
|
|
2496
|
+
return `Detected scheduling of an unchained task.
|
|
2497
|
+
When the promise manager is disabled, unchained tasks will not wait for
|
|
2498
|
+
previously scheduled tasks to finish before starting to execute.
|
|
2499
|
+
New task: ${task.promise.stack_.stack}
|
|
2500
|
+
Previous task: ${previousTask.promise.stack_.stack}`.split(/\n/).join('\n ');
|
|
2501
|
+
});
|
|
2502
|
+
break;
|
|
2503
|
+
}
|
|
2504
|
+
}
|
|
2387
2505
|
|
|
2388
|
-
var q = this.getActiveQueue_();
|
|
2389
2506
|
q.enqueue(task);
|
|
2390
2507
|
this.emit(ControlFlow.EventType.SCHEDULE_TASK, task.description);
|
|
2391
2508
|
return task.promise;
|
|
@@ -2393,7 +2510,7 @@ class ControlFlow extends events.EventEmitter {
|
|
|
2393
2510
|
|
|
2394
2511
|
/** @override */
|
|
2395
2512
|
promise(resolver) {
|
|
2396
|
-
return new ManagedPromise(resolver, this);
|
|
2513
|
+
return new ManagedPromise(resolver, this, SKIP_LOG);
|
|
2397
2514
|
}
|
|
2398
2515
|
|
|
2399
2516
|
/** @override */
|
|
@@ -2622,7 +2739,7 @@ class MicroTask {
|
|
|
2622
2739
|
}
|
|
2623
2740
|
|
|
2624
2741
|
/**
|
|
2625
|
-
* Runs the given function after a
|
|
2742
|
+
* Runs the given function after a microtask yield.
|
|
2626
2743
|
* @param {function()} fn The function to run.
|
|
2627
2744
|
*/
|
|
2628
2745
|
static run(fn) {
|
|
@@ -2662,9 +2779,11 @@ class Task extends Deferred {
|
|
|
2662
2779
|
* @param {string} description A description of the task for debugging.
|
|
2663
2780
|
* @param {{name: string, top: !Function}=} opt_stackOptions Options to use
|
|
2664
2781
|
* when capturing the stacktrace for when this task was created.
|
|
2782
|
+
* @param {boolean=} opt_isUserTask Whether this task was explicitly scheduled
|
|
2783
|
+
* by the use of the promise manager.
|
|
2665
2784
|
*/
|
|
2666
|
-
constructor(flow, fn, description, opt_stackOptions) {
|
|
2667
|
-
super(flow);
|
|
2785
|
+
constructor(flow, fn, description, opt_stackOptions, opt_isUserTask) {
|
|
2786
|
+
super(flow, SKIP_LOG);
|
|
2668
2787
|
getUid(this);
|
|
2669
2788
|
|
|
2670
2789
|
/** @type {function(): (T|!ManagedPromise<T>)} */
|
|
@@ -2676,6 +2795,9 @@ class Task extends Deferred {
|
|
|
2676
2795
|
/** @type {TaskQueue} */
|
|
2677
2796
|
this.queue = null;
|
|
2678
2797
|
|
|
2798
|
+
/** @private @const {boolean} */
|
|
2799
|
+
this.userTask_ = !!opt_isUserTask;
|
|
2800
|
+
|
|
2679
2801
|
/**
|
|
2680
2802
|
* Whether this task is considered block. A blocked task may be registered
|
|
2681
2803
|
* in a task queue, but will be dropped if it is still blocked when it
|
|
@@ -2889,7 +3011,7 @@ class TaskQueue extends events.EventEmitter {
|
|
|
2889
3011
|
}
|
|
2890
3012
|
|
|
2891
3013
|
// Now that all of the remaining tasks have been silently cancelled (e.g. no
|
|
2892
|
-
//
|
|
3014
|
+
// existing callbacks on those tasks will fire), clear the silence bit on
|
|
2893
3015
|
// the cancellation error. This ensures additional callbacks registered in
|
|
2894
3016
|
// the future will actually execute.
|
|
2895
3017
|
cancellation.silent_ = false;
|
|
@@ -2935,7 +3057,7 @@ class TaskQueue extends events.EventEmitter {
|
|
|
2935
3057
|
|
|
2936
3058
|
this.subQ_.once('end', () => { // On task completion.
|
|
2937
3059
|
this.subQ_ = null;
|
|
2938
|
-
this.pending_ && this.pending_.task.
|
|
3060
|
+
this.pending_ && this.pending_.task.resolve(result);
|
|
2939
3061
|
});
|
|
2940
3062
|
|
|
2941
3063
|
this.subQ_.once('error', e => { // On task failure.
|
|
@@ -3068,7 +3190,7 @@ class TaskQueue extends events.EventEmitter {
|
|
|
3068
3190
|
}
|
|
3069
3191
|
return task;
|
|
3070
3192
|
}
|
|
3071
|
-
}
|
|
3193
|
+
}
|
|
3072
3194
|
|
|
3073
3195
|
|
|
3074
3196
|
|
|
@@ -3214,7 +3336,7 @@ function consume(generatorFn, opt_self, ...var_args) {
|
|
|
3214
3336
|
|
|
3215
3337
|
function pump(fn, opt_arg) {
|
|
3216
3338
|
if (ret instanceof ManagedPromise && !isPending(ret)) {
|
|
3217
|
-
return; //
|
|
3339
|
+
return; // Deferred was cancelled; silently abort.
|
|
3218
3340
|
}
|
|
3219
3341
|
|
|
3220
3342
|
try {
|
|
@@ -3246,6 +3368,7 @@ module.exports = {
|
|
|
3246
3368
|
MultipleUnhandledRejectionError: MultipleUnhandledRejectionError,
|
|
3247
3369
|
Thenable: Thenable,
|
|
3248
3370
|
Promise: ManagedPromise,
|
|
3371
|
+
Resolver: Resolver,
|
|
3249
3372
|
Scheduler: Scheduler,
|
|
3250
3373
|
all: all,
|
|
3251
3374
|
asap: asap,
|
|
@@ -3254,6 +3377,7 @@ module.exports = {
|
|
|
3254
3377
|
consume: consume,
|
|
3255
3378
|
controlFlow: controlFlow,
|
|
3256
3379
|
createFlow: createFlow,
|
|
3380
|
+
createPromise: createPromise,
|
|
3257
3381
|
defer: defer,
|
|
3258
3382
|
delayed: delayed,
|
|
3259
3383
|
filter: filter,
|
|
@@ -3275,7 +3399,7 @@ module.exports = {
|
|
|
3275
3399
|
* The promise manager is currently enabled by default, but may be disabled
|
|
3276
3400
|
* by setting the environment variable `SELENIUM_PROMISE_MANAGER=0` or by
|
|
3277
3401
|
* setting this property to false. Setting this property will always take
|
|
3278
|
-
* precedence
|
|
3402
|
+
* precedence over the use of the environment variable.
|
|
3279
3403
|
*
|
|
3280
3404
|
* @return {boolean} Whether the promise manager is enabled.
|
|
3281
3405
|
* @see <https://github.com/SeleniumHQ/selenium/issues/2969>
|