selenium-webdriver 3.0.0-beta-1 → 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 +109 -0
- package/LICENSE +1 -1
- package/README.md +7 -6
- package/chrome.js +31 -128
- package/edge.js +13 -91
- package/example/chrome_android.js +18 -13
- package/example/chrome_mobile_emulation.js +19 -15
- package/example/google_search.js +11 -11
- package/example/google_search_generator.js +23 -18
- package/example/google_search_test.js +31 -17
- package/example/logging.js +9 -17
- package/example/parallel_flows.js +3 -0
- package/firefox/binary.js +17 -0
- package/firefox/index.js +198 -101
- package/firefox/profile.js +24 -3
- package/http/util.js +95 -59
- package/ie.js +6 -10
- package/index.js +636 -2
- package/lib/actions.js +18 -10
- package/lib/atoms/getAttribute.js +11 -0
- package/lib/atoms/isDisplayed.js +106 -0
- 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/http.js +159 -46
- package/lib/logging.js +7 -1
- package/lib/promise.js +602 -358
- package/lib/proxy.js +28 -0
- package/lib/session.js +1 -1
- package/lib/test/build.js +26 -28
- package/lib/test/data/formPage.html +1 -0
- package/lib/test/fileserver.js +12 -10
- package/lib/test/httpserver.js +4 -6
- package/lib/test/index.js +18 -11
- package/lib/test/promise.js +79 -0
- package/lib/webdriver.js +587 -479
- package/opera.js +12 -88
- package/package.json +13 -14
- package/phantomjs.js +7 -14
- package/remote/index.js +201 -30
- package/safari.js +62 -416
- package/test/actions_test.js +9 -11
- package/test/chrome/options_test.js +8 -8
- package/test/chrome/service_test.js +2 -2
- package/test/cookie_test.js +57 -57
- package/test/element_finding_test.js +201 -185
- package/test/execute_script_test.js +108 -111
- package/test/fingerprint_test.js +16 -11
- package/test/firefox/firefox_test.js +75 -49
- package/test/firefox/profile_test.js +1 -3
- package/test/http/util_test.js +21 -27
- package/test/io_test.js +2 -5
- package/test/lib/http_test.js +8 -6
- package/test/lib/promise_aplus_test.js +48 -44
- package/test/lib/promise_error_test.js +687 -611
- package/test/lib/promise_flow_test.js +1810 -1806
- package/test/lib/promise_generator_test.js +227 -225
- package/test/lib/promise_test.js +864 -835
- package/test/lib/until_test.js +1 -1
- package/test/lib/webdriver_test.js +520 -424
- package/test/logging_test.js +43 -45
- package/test/net/portprober_test.js +23 -24
- package/test/page_loading_test.js +84 -78
- package/test/phantomjs/execute_phantomjs_test.js +11 -25
- package/test/proxy_test.js +23 -23
- package/test/remote_test.js +22 -22
- package/test/safari_test.js +108 -0
- package/test/session_test.js +11 -10
- package/test/stale_element_test.js +18 -16
- package/test/tag_name_test.js +7 -5
- package/test/testing/assert_test.js +2 -3
- package/test/testing/index_test.js +163 -117
- package/test/upload_test.js +13 -13
- package/test/window_test.js +94 -70
- package/testing/index.js +176 -37
- package/builder.js +0 -553
- package/lib/safari/client.js +0 -56
package/lib/promise.js
CHANGED
|
@@ -17,6 +17,42 @@
|
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* @fileoverview
|
|
20
|
+
*
|
|
21
|
+
* > ### IMPORTANT NOTICE
|
|
22
|
+
* >
|
|
23
|
+
* > The promise manager contained in this module is in the process of being
|
|
24
|
+
* > phased out in favor of native JavaScript promises. This will be a long
|
|
25
|
+
* > process and will not be completed until there have been two major LTS Node
|
|
26
|
+
* > releases (approx. Node v10.0) that support
|
|
27
|
+
* > [async functions](https://tc39.github.io/ecmascript-asyncawait/).
|
|
28
|
+
* >
|
|
29
|
+
* > At this time, the promise manager can be disabled by setting an environment
|
|
30
|
+
* > variable, `SELENIUM_PROMISE_MANAGER=0`. In the absence of async functions,
|
|
31
|
+
* > users may use generators with the
|
|
32
|
+
* > {@link ./promise.consume promise.consume()} function to write "synchronous"
|
|
33
|
+
* > style tests:
|
|
34
|
+
* >
|
|
35
|
+
* > ```js
|
|
36
|
+
* > const {Builder, By, promise, until} = require('selenium-webdriver');
|
|
37
|
+
* >
|
|
38
|
+
* > let result = promise.consume(function* doGoogleSearch() {
|
|
39
|
+
* > let driver = new Builder().forBrowser('firefox').build();
|
|
40
|
+
* > yield driver.get('http://www.google.com/ncr');
|
|
41
|
+
* > yield driver.findElement(By.name('q')).sendKeys('webdriver');
|
|
42
|
+
* > yield driver.findElement(By.name('btnG')).click();
|
|
43
|
+
* > yield driver.wait(until.titleIs('webdriver - Google Search'), 1000);
|
|
44
|
+
* > yield driver.quit();
|
|
45
|
+
* > });
|
|
46
|
+
* >
|
|
47
|
+
* > result.then(_ => console.log('SUCCESS!'),
|
|
48
|
+
* > e => console.error('FAILURE: ' + e));
|
|
49
|
+
* > ```
|
|
50
|
+
* >
|
|
51
|
+
* > The motiviation behind this change and full deprecation plan are documented
|
|
52
|
+
* > in [issue 2969](https://github.com/SeleniumHQ/selenium/issues/2969).
|
|
53
|
+
* >
|
|
54
|
+
* >
|
|
55
|
+
*
|
|
20
56
|
* The promise module is centered around the {@linkplain ControlFlow}, a class
|
|
21
57
|
* that coordinates the execution of asynchronous tasks. The ControlFlow allows
|
|
22
58
|
* users to focus on the imperative commands for their script without worrying
|
|
@@ -592,6 +628,7 @@
|
|
|
592
628
|
|
|
593
629
|
'use strict';
|
|
594
630
|
|
|
631
|
+
const error = require('./error');
|
|
595
632
|
const events = require('./events');
|
|
596
633
|
const logging = require('./logging');
|
|
597
634
|
|
|
@@ -643,19 +680,6 @@ function asyncRun(fn) {
|
|
|
643
680
|
});
|
|
644
681
|
}
|
|
645
682
|
|
|
646
|
-
|
|
647
|
-
/**
|
|
648
|
-
* Throws an error asynchronously so it is reported to the global error handler.
|
|
649
|
-
*
|
|
650
|
-
* @param {!Error} error The error to throw.
|
|
651
|
-
*/
|
|
652
|
-
function asyncThrow(error) {
|
|
653
|
-
setTimeout(function() {
|
|
654
|
-
throw error;
|
|
655
|
-
}, 0);
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
|
|
659
683
|
/**
|
|
660
684
|
* @param {number} level What level of verbosity to log with.
|
|
661
685
|
* @param {(string|function(this: T): string)} loggable The message to log.
|
|
@@ -811,32 +835,56 @@ class MultipleUnhandledRejectionError extends Error {
|
|
|
811
835
|
* @const
|
|
812
836
|
*/
|
|
813
837
|
const IMPLEMENTED_BY_SYMBOL = Symbol('promise.Thenable');
|
|
838
|
+
const CANCELLABLE_SYMBOL = Symbol('promise.CancellableThenable');
|
|
839
|
+
|
|
840
|
+
|
|
841
|
+
/**
|
|
842
|
+
* @param {function(new: ?)} ctor
|
|
843
|
+
* @param {!Object} symbol
|
|
844
|
+
*/
|
|
845
|
+
function addMarkerSymbol(ctor, symbol) {
|
|
846
|
+
try {
|
|
847
|
+
ctor.prototype[symbol] = true;
|
|
848
|
+
} catch (ignored) {
|
|
849
|
+
// Property access denied?
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
|
|
854
|
+
/**
|
|
855
|
+
* @param {*} object
|
|
856
|
+
* @param {!Object} symbol
|
|
857
|
+
* @return {boolean}
|
|
858
|
+
*/
|
|
859
|
+
function hasMarkerSymbol(object, symbol) {
|
|
860
|
+
if (!object) {
|
|
861
|
+
return false;
|
|
862
|
+
}
|
|
863
|
+
try {
|
|
864
|
+
return !!object[symbol];
|
|
865
|
+
} catch (e) {
|
|
866
|
+
return false; // Property access seems to be forbidden.
|
|
867
|
+
}
|
|
868
|
+
}
|
|
814
869
|
|
|
815
870
|
|
|
816
871
|
/**
|
|
817
872
|
* Thenable is a promise-like object with a {@code then} method which may be
|
|
818
873
|
* used to schedule callbacks on a promised value.
|
|
819
874
|
*
|
|
820
|
-
* @
|
|
875
|
+
* @record
|
|
821
876
|
* @extends {IThenable<T>}
|
|
822
877
|
* @template T
|
|
823
878
|
*/
|
|
824
879
|
class Thenable {
|
|
825
880
|
/**
|
|
826
881
|
* Adds a property to a class prototype to allow runtime checks of whether
|
|
827
|
-
* instances of that class implement the Thenable interface.
|
|
828
|
-
* will also ensure the prototype's {@code then} function is exported from
|
|
829
|
-
* compiled code.
|
|
882
|
+
* instances of that class implement the Thenable interface.
|
|
830
883
|
* @param {function(new: Thenable, ...?)} ctor The
|
|
831
884
|
* constructor whose prototype to modify.
|
|
832
885
|
*/
|
|
833
886
|
static addImplementation(ctor) {
|
|
834
|
-
ctor
|
|
835
|
-
try {
|
|
836
|
-
ctor.prototype[IMPLEMENTED_BY_SYMBOL] = true;
|
|
837
|
-
} catch (ignored) {
|
|
838
|
-
// Property access denied?
|
|
839
|
-
}
|
|
887
|
+
addMarkerSymbol(ctor, IMPLEMENTED_BY_SYMBOL);
|
|
840
888
|
}
|
|
841
889
|
|
|
842
890
|
/**
|
|
@@ -847,29 +895,9 @@ class Thenable {
|
|
|
847
895
|
* interface.
|
|
848
896
|
*/
|
|
849
897
|
static isImplementation(object) {
|
|
850
|
-
|
|
851
|
-
return false;
|
|
852
|
-
}
|
|
853
|
-
try {
|
|
854
|
-
return !!object[IMPLEMENTED_BY_SYMBOL];
|
|
855
|
-
} catch (e) {
|
|
856
|
-
return false; // Property access seems to be forbidden.
|
|
857
|
-
}
|
|
898
|
+
return hasMarkerSymbol(object, IMPLEMENTED_BY_SYMBOL);
|
|
858
899
|
}
|
|
859
900
|
|
|
860
|
-
/**
|
|
861
|
-
* Cancels the computation of this promise's value, rejecting the promise in
|
|
862
|
-
* the process. This method is a no-op if the promise has already been
|
|
863
|
-
* resolved.
|
|
864
|
-
*
|
|
865
|
-
* @param {(string|Error)=} opt_reason The reason this promise is being
|
|
866
|
-
* cancelled. This value will be wrapped in a {@link CancellationError}.
|
|
867
|
-
*/
|
|
868
|
-
cancel(opt_reason) {}
|
|
869
|
-
|
|
870
|
-
/** @return {boolean} Whether this promise's value is still being computed. */
|
|
871
|
-
isPending() {}
|
|
872
|
-
|
|
873
901
|
/**
|
|
874
902
|
* Registers listeners for when this instance is resolved.
|
|
875
903
|
*
|
|
@@ -879,8 +907,8 @@ class Thenable {
|
|
|
879
907
|
* @param {?(function(*): (R|IThenable<R>))=} opt_errback
|
|
880
908
|
* The function to call if this promise is rejected. The function should
|
|
881
909
|
* expect a single argument: the rejection reason.
|
|
882
|
-
* @return {!
|
|
883
|
-
*
|
|
910
|
+
* @return {!Thenable<R>} A new promise which will be resolved with the result
|
|
911
|
+
* of the invoked callback.
|
|
884
912
|
* @template R
|
|
885
913
|
*/
|
|
886
914
|
then(opt_callback, opt_errback) {}
|
|
@@ -904,49 +932,53 @@ class Thenable {
|
|
|
904
932
|
* @param {function(*): (R|IThenable<R>)} errback The
|
|
905
933
|
* function to call if this promise is rejected. The function should
|
|
906
934
|
* expect a single argument: the rejection reason.
|
|
907
|
-
* @return {!
|
|
908
|
-
*
|
|
935
|
+
* @return {!Thenable<R>} A new promise which will be resolved with the result
|
|
936
|
+
* of the invoked callback.
|
|
909
937
|
* @template R
|
|
910
938
|
*/
|
|
911
939
|
catch(errback) {}
|
|
940
|
+
}
|
|
912
941
|
|
|
942
|
+
|
|
943
|
+
/**
|
|
944
|
+
* Marker interface for objects that allow consumers to request the cancellation
|
|
945
|
+
* of a promies-based operation. A cancelled promise will be rejected with a
|
|
946
|
+
* {@link CancellationError}.
|
|
947
|
+
*
|
|
948
|
+
* This interface is considered package-private and should not be used outside
|
|
949
|
+
* of selenium-webdriver.
|
|
950
|
+
*
|
|
951
|
+
* @interface
|
|
952
|
+
* @extends {Thenable<T>}
|
|
953
|
+
* @template T
|
|
954
|
+
* @package
|
|
955
|
+
*/
|
|
956
|
+
class CancellableThenable {
|
|
913
957
|
/**
|
|
914
|
-
*
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
*
|
|
923
|
-
*
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
*
|
|
931
|
-
*
|
|
932
|
-
*
|
|
933
|
-
* throw Error('one');
|
|
934
|
-
* } finally {
|
|
935
|
-
* throw Error('two'); // Hides Error: one
|
|
936
|
-
* }
|
|
937
|
-
*
|
|
938
|
-
* promise.rejected(Error('one'))
|
|
939
|
-
* .finally(function() {
|
|
940
|
-
* throw Error('two'); // Hides Error: one
|
|
941
|
-
* });
|
|
958
|
+
* @param {function(new: CancellableThenable, ...?)} ctor
|
|
959
|
+
*/
|
|
960
|
+
static addImplementation(ctor) {
|
|
961
|
+
Thenable.addImplementation(ctor);
|
|
962
|
+
addMarkerSymbol(ctor, CANCELLABLE_SYMBOL);
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
/**
|
|
966
|
+
* @param {*} object
|
|
967
|
+
* @return {boolean}
|
|
968
|
+
*/
|
|
969
|
+
static isImplementation(object) {
|
|
970
|
+
return hasMarkerSymbol(object, CANCELLABLE_SYMBOL);
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
/**
|
|
974
|
+
* Requests the cancellation of the computation of this promise's value,
|
|
975
|
+
* rejecting the promise in the process. This method is a no-op if the promise
|
|
976
|
+
* has already been resolved.
|
|
942
977
|
*
|
|
943
|
-
* @param {
|
|
944
|
-
*
|
|
945
|
-
* @return {!ManagedPromise<R>} A promise that will be fulfilled
|
|
946
|
-
* with the callback result.
|
|
947
|
-
* @template R
|
|
978
|
+
* @param {(string|Error)=} opt_reason The reason this promise is being
|
|
979
|
+
* cancelled. This value will be wrapped in a {@link CancellationError}.
|
|
948
980
|
*/
|
|
949
|
-
|
|
981
|
+
cancel(opt_reason) {}
|
|
950
982
|
}
|
|
951
983
|
|
|
952
984
|
|
|
@@ -979,7 +1011,7 @@ const ON_CANCEL_HANDLER = new WeakMap;
|
|
|
979
1011
|
* fulfilled or rejected state, at which point the promise is considered
|
|
980
1012
|
* resolved.
|
|
981
1013
|
*
|
|
982
|
-
* @implements {
|
|
1014
|
+
* @implements {CancellableThenable<T>}
|
|
983
1015
|
* @template T
|
|
984
1016
|
* @see http://promises-aplus.github.io/promises-spec/
|
|
985
1017
|
*/
|
|
@@ -995,6 +1027,12 @@ class ManagedPromise {
|
|
|
995
1027
|
* this instance was created under. Defaults to the currently active flow.
|
|
996
1028
|
*/
|
|
997
1029
|
constructor(resolver, opt_flow) {
|
|
1030
|
+
if (!usePromiseManager()) {
|
|
1031
|
+
throw TypeError(
|
|
1032
|
+
'Unable to create a managed promise instance: the promise manager has'
|
|
1033
|
+
+ ' been disabled by the SELENIUM_PROMISE_MANAGER environment'
|
|
1034
|
+
+ ' variable: ' + process.env['SELENIUM_PROMISE_MANAGER']);
|
|
1035
|
+
}
|
|
998
1036
|
getUid(this);
|
|
999
1037
|
|
|
1000
1038
|
/** @private {!ControlFlow} */
|
|
@@ -1036,6 +1074,30 @@ class ManagedPromise {
|
|
|
1036
1074
|
}
|
|
1037
1075
|
}
|
|
1038
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
|
+
|
|
1039
1101
|
/** @override */
|
|
1040
1102
|
toString() {
|
|
1041
1103
|
return 'ManagedPromise::' + getUid(this) +
|
|
@@ -1188,7 +1250,7 @@ class ManagedPromise {
|
|
|
1188
1250
|
}
|
|
1189
1251
|
|
|
1190
1252
|
if (this.parent_ && canCancel(this.parent_)) {
|
|
1191
|
-
this.parent_.cancel(opt_reason);
|
|
1253
|
+
/** @type {!CancellableThenable} */(this.parent_).cancel(opt_reason);
|
|
1192
1254
|
} else {
|
|
1193
1255
|
var reason = CancellationError.wrap(opt_reason);
|
|
1194
1256
|
let onCancel = ON_CANCEL_HANDLER.get(this);
|
|
@@ -1206,18 +1268,13 @@ class ManagedPromise {
|
|
|
1206
1268
|
|
|
1207
1269
|
function canCancel(promise) {
|
|
1208
1270
|
if (!(promise instanceof ManagedPromise)) {
|
|
1209
|
-
return
|
|
1271
|
+
return CancellableThenable.isImplementation(promise);
|
|
1210
1272
|
}
|
|
1211
1273
|
return promise.state_ === PromiseState.PENDING
|
|
1212
1274
|
|| promise.state_ === PromiseState.BLOCKED;
|
|
1213
1275
|
}
|
|
1214
1276
|
}
|
|
1215
1277
|
|
|
1216
|
-
/** @override */
|
|
1217
|
-
isPending() {
|
|
1218
|
-
return this.state_ === PromiseState.PENDING;
|
|
1219
|
-
}
|
|
1220
|
-
|
|
1221
1278
|
/** @override */
|
|
1222
1279
|
then(opt_callback, opt_errback) {
|
|
1223
1280
|
return this.addCallback_(
|
|
@@ -1230,21 +1287,15 @@ class ManagedPromise {
|
|
|
1230
1287
|
null, errback, 'catch', ManagedPromise.prototype.catch);
|
|
1231
1288
|
}
|
|
1232
1289
|
|
|
1233
|
-
/**
|
|
1290
|
+
/**
|
|
1291
|
+
* @param {function(): (R|IThenable<R>)} callback
|
|
1292
|
+
* @return {!ManagedPromise<R>}
|
|
1293
|
+
* @template R
|
|
1294
|
+
* @see ./promise.finally()
|
|
1295
|
+
*/
|
|
1234
1296
|
finally(callback) {
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
return this.then(function() {
|
|
1238
|
-
return callback();
|
|
1239
|
-
}, function(err) {
|
|
1240
|
-
error = err;
|
|
1241
|
-
mustThrow = true;
|
|
1242
|
-
return callback();
|
|
1243
|
-
}).then(function() {
|
|
1244
|
-
if (mustThrow) {
|
|
1245
|
-
throw error;
|
|
1246
|
-
}
|
|
1247
|
-
});
|
|
1297
|
+
let result = thenFinally(this, callback);
|
|
1298
|
+
return /** @type {!ManagedPromise} */(result);
|
|
1248
1299
|
}
|
|
1249
1300
|
|
|
1250
1301
|
/**
|
|
@@ -1320,7 +1371,16 @@ class ManagedPromise {
|
|
|
1320
1371
|
}
|
|
1321
1372
|
}
|
|
1322
1373
|
}
|
|
1323
|
-
|
|
1374
|
+
CancellableThenable.addImplementation(ManagedPromise);
|
|
1375
|
+
|
|
1376
|
+
|
|
1377
|
+
/**
|
|
1378
|
+
* @param {!ManagedPromise} promise
|
|
1379
|
+
* @return {boolean}
|
|
1380
|
+
*/
|
|
1381
|
+
function isPending(promise) {
|
|
1382
|
+
return promise.state_ === PromiseState.PENDING;
|
|
1383
|
+
}
|
|
1324
1384
|
|
|
1325
1385
|
|
|
1326
1386
|
/**
|
|
@@ -1417,19 +1477,11 @@ function isPromise(value) {
|
|
|
1417
1477
|
* Creates a promise that will be resolved at a set time in the future.
|
|
1418
1478
|
* @param {number} ms The amount of time, in milliseconds, to wait before
|
|
1419
1479
|
* resolving the promise.
|
|
1420
|
-
* @return {!
|
|
1480
|
+
* @return {!Thenable} The promise.
|
|
1421
1481
|
*/
|
|
1422
1482
|
function delayed(ms) {
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
key = setTimeout(function() {
|
|
1426
|
-
key = null;
|
|
1427
|
-
fulfill();
|
|
1428
|
-
}, ms);
|
|
1429
|
-
}).catch(function(e) {
|
|
1430
|
-
clearTimeout(key);
|
|
1431
|
-
key = null;
|
|
1432
|
-
throw e;
|
|
1483
|
+
return createPromise(resolve => {
|
|
1484
|
+
setTimeout(() => resolve(), ms);
|
|
1433
1485
|
});
|
|
1434
1486
|
}
|
|
1435
1487
|
|
|
@@ -1448,15 +1500,11 @@ function defer() {
|
|
|
1448
1500
|
* Creates a promise that has been resolved with the given value.
|
|
1449
1501
|
* @param {T=} opt_value The resolved value.
|
|
1450
1502
|
* @return {!ManagedPromise<T>} The resolved promise.
|
|
1503
|
+
* @deprecated Use {@link ManagedPromise#resolve Promise.resolve(value)}.
|
|
1451
1504
|
* @template T
|
|
1452
1505
|
*/
|
|
1453
1506
|
function fulfilled(opt_value) {
|
|
1454
|
-
|
|
1455
|
-
return opt_value;
|
|
1456
|
-
}
|
|
1457
|
-
return new ManagedPromise(function(fulfill) {
|
|
1458
|
-
fulfill(opt_value);
|
|
1459
|
-
});
|
|
1507
|
+
return ManagedPromise.resolve(opt_value);
|
|
1460
1508
|
}
|
|
1461
1509
|
|
|
1462
1510
|
|
|
@@ -1464,16 +1512,11 @@ function fulfilled(opt_value) {
|
|
|
1464
1512
|
* Creates a promise that has been rejected with the given reason.
|
|
1465
1513
|
* @param {*=} opt_reason The rejection reason; may be any value, but is
|
|
1466
1514
|
* usually an Error or a string.
|
|
1467
|
-
* @return {!ManagedPromise
|
|
1468
|
-
* @
|
|
1515
|
+
* @return {!ManagedPromise<?>} The rejected promise.
|
|
1516
|
+
* @deprecated Use {@link ManagedPromise#reject Promise.reject(reason)}.
|
|
1469
1517
|
*/
|
|
1470
1518
|
function rejected(opt_reason) {
|
|
1471
|
-
|
|
1472
|
-
return opt_reason;
|
|
1473
|
-
}
|
|
1474
|
-
return new ManagedPromise(function(_, reject) {
|
|
1475
|
-
reject(opt_reason);
|
|
1476
|
-
});
|
|
1519
|
+
return ManagedPromise.reject(opt_reason);
|
|
1477
1520
|
}
|
|
1478
1521
|
|
|
1479
1522
|
|
|
@@ -1486,12 +1529,12 @@ function rejected(opt_reason) {
|
|
|
1486
1529
|
* @param {!Function} fn The function to wrap.
|
|
1487
1530
|
* @param {...?} var_args The arguments to apply to the function, excluding the
|
|
1488
1531
|
* final callback.
|
|
1489
|
-
* @return {!
|
|
1532
|
+
* @return {!Thenable} A promise that will be resolved with the
|
|
1490
1533
|
* result of the provided function's callback.
|
|
1491
1534
|
*/
|
|
1492
1535
|
function checkedNodeCall(fn, var_args) {
|
|
1493
1536
|
let args = Array.prototype.slice.call(arguments, 1);
|
|
1494
|
-
return
|
|
1537
|
+
return createPromise(function(fulfill, reject) {
|
|
1495
1538
|
try {
|
|
1496
1539
|
args.push(function(error, value) {
|
|
1497
1540
|
error ? reject(error) : fulfill(value);
|
|
@@ -1503,6 +1546,59 @@ function checkedNodeCall(fn, var_args) {
|
|
|
1503
1546
|
});
|
|
1504
1547
|
}
|
|
1505
1548
|
|
|
1549
|
+
/**
|
|
1550
|
+
* Registers a listener to invoke when a promise is resolved, regardless
|
|
1551
|
+
* of whether the promise's value was successfully computed. This function
|
|
1552
|
+
* is synonymous with the {@code finally} clause in a synchronous API:
|
|
1553
|
+
*
|
|
1554
|
+
* // Synchronous API:
|
|
1555
|
+
* try {
|
|
1556
|
+
* doSynchronousWork();
|
|
1557
|
+
* } finally {
|
|
1558
|
+
* cleanUp();
|
|
1559
|
+
* }
|
|
1560
|
+
*
|
|
1561
|
+
* // Asynchronous promise API:
|
|
1562
|
+
* doAsynchronousWork().finally(cleanUp);
|
|
1563
|
+
*
|
|
1564
|
+
* __Note:__ similar to the {@code finally} clause, if the registered
|
|
1565
|
+
* callback returns a rejected promise or throws an error, it will silently
|
|
1566
|
+
* replace the rejection error (if any) from this promise:
|
|
1567
|
+
*
|
|
1568
|
+
* try {
|
|
1569
|
+
* throw Error('one');
|
|
1570
|
+
* } finally {
|
|
1571
|
+
* throw Error('two'); // Hides Error: one
|
|
1572
|
+
* }
|
|
1573
|
+
*
|
|
1574
|
+
* let p = Promise.reject(Error('one'));
|
|
1575
|
+
* promise.finally(p, function() {
|
|
1576
|
+
* throw Error('two'); // Hides Error: one
|
|
1577
|
+
* });
|
|
1578
|
+
*
|
|
1579
|
+
* @param {!IThenable<?>} promise The promise to add the listener to.
|
|
1580
|
+
* @param {function(): (R|IThenable<R>)} callback The function to call when
|
|
1581
|
+
* the promise is resolved.
|
|
1582
|
+
* @return {!IThenable<R>} A promise that will be resolved with the callback
|
|
1583
|
+
* result.
|
|
1584
|
+
* @template R
|
|
1585
|
+
*/
|
|
1586
|
+
function thenFinally(promise, callback) {
|
|
1587
|
+
let error;
|
|
1588
|
+
let mustThrow = false;
|
|
1589
|
+
return promise.then(function() {
|
|
1590
|
+
return callback();
|
|
1591
|
+
}, function(err) {
|
|
1592
|
+
error = err;
|
|
1593
|
+
mustThrow = true;
|
|
1594
|
+
return callback();
|
|
1595
|
+
}).then(function() {
|
|
1596
|
+
if (mustThrow) {
|
|
1597
|
+
throw error;
|
|
1598
|
+
}
|
|
1599
|
+
});
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1506
1602
|
|
|
1507
1603
|
/**
|
|
1508
1604
|
* Registers an observer on a promised {@code value}, returning a new promise
|
|
@@ -1513,16 +1609,15 @@ function checkedNodeCall(fn, var_args) {
|
|
|
1513
1609
|
* resolved successfully.
|
|
1514
1610
|
* @param {Function=} opt_errback The function to call when the value is
|
|
1515
1611
|
* rejected.
|
|
1516
|
-
* @return {!
|
|
1612
|
+
* @return {!Thenable} A new promise.
|
|
1517
1613
|
*/
|
|
1518
1614
|
function when(value, opt_callback, opt_errback) {
|
|
1519
1615
|
if (Thenable.isImplementation(value)) {
|
|
1520
1616
|
return value.then(opt_callback, opt_errback);
|
|
1521
1617
|
}
|
|
1522
1618
|
|
|
1523
|
-
return
|
|
1524
|
-
|
|
1525
|
-
}).then(opt_callback, opt_errback);
|
|
1619
|
+
return createPromise(resolve => resolve(value))
|
|
1620
|
+
.then(opt_callback, opt_errback);
|
|
1526
1621
|
}
|
|
1527
1622
|
|
|
1528
1623
|
|
|
@@ -1554,14 +1649,14 @@ function asap(value, callback, opt_errback) {
|
|
|
1554
1649
|
*
|
|
1555
1650
|
* @param {!Array<(T|!ManagedPromise<T>)>} arr An array of
|
|
1556
1651
|
* promises to wait on.
|
|
1557
|
-
* @return {!
|
|
1652
|
+
* @return {!Thenable<!Array<T>>} A promise that is
|
|
1558
1653
|
* fulfilled with an array containing the fulfilled values of the
|
|
1559
1654
|
* input array, or rejected with the same reason as the first
|
|
1560
1655
|
* rejected value.
|
|
1561
1656
|
* @template T
|
|
1562
1657
|
*/
|
|
1563
1658
|
function all(arr) {
|
|
1564
|
-
return
|
|
1659
|
+
return createPromise(function(fulfill, reject) {
|
|
1565
1660
|
var n = arr.length;
|
|
1566
1661
|
var values = [];
|
|
1567
1662
|
|
|
@@ -1615,12 +1710,12 @@ function all(arr) {
|
|
|
1615
1710
|
* @template TYPE, SELF
|
|
1616
1711
|
*/
|
|
1617
1712
|
function map(arr, fn, opt_self) {
|
|
1618
|
-
return
|
|
1713
|
+
return createPromise(resolve => resolve(arr)).then(v => {
|
|
1619
1714
|
if (!Array.isArray(v)) {
|
|
1620
1715
|
throw TypeError('not an array');
|
|
1621
1716
|
}
|
|
1622
1717
|
var arr = /** @type {!Array} */(v);
|
|
1623
|
-
return
|
|
1718
|
+
return createPromise(function(fulfill, reject) {
|
|
1624
1719
|
var n = arr.length;
|
|
1625
1720
|
var values = new Array(n);
|
|
1626
1721
|
(function processNext(i) {
|
|
@@ -1673,12 +1768,12 @@ function map(arr, fn, opt_self) {
|
|
|
1673
1768
|
* @template TYPE, SELF
|
|
1674
1769
|
*/
|
|
1675
1770
|
function filter(arr, fn, opt_self) {
|
|
1676
|
-
return
|
|
1771
|
+
return createPromise(resolve => resolve(arr)).then(v => {
|
|
1677
1772
|
if (!Array.isArray(v)) {
|
|
1678
1773
|
throw TypeError('not an array');
|
|
1679
1774
|
}
|
|
1680
1775
|
var arr = /** @type {!Array} */(v);
|
|
1681
|
-
return
|
|
1776
|
+
return createPromise(function(fulfill, reject) {
|
|
1682
1777
|
var n = arr.length;
|
|
1683
1778
|
var values = [];
|
|
1684
1779
|
var valuesLength = 0;
|
|
@@ -1726,7 +1821,7 @@ function filter(arr, fn, opt_self) {
|
|
|
1726
1821
|
* promise.fullyResolved(value); // Stack overflow.
|
|
1727
1822
|
*
|
|
1728
1823
|
* @param {*} value The value to fully resolve.
|
|
1729
|
-
* @return {!
|
|
1824
|
+
* @return {!Thenable} A promise for a fully resolved version
|
|
1730
1825
|
* of the input value.
|
|
1731
1826
|
*/
|
|
1732
1827
|
function fullyResolved(value) {
|
|
@@ -1740,7 +1835,7 @@ function fullyResolved(value) {
|
|
|
1740
1835
|
/**
|
|
1741
1836
|
* @param {*} value The value to fully resolve. If a promise, assumed to
|
|
1742
1837
|
* already be resolved.
|
|
1743
|
-
* @return {!
|
|
1838
|
+
* @return {!Thenable} A promise for a fully resolved version
|
|
1744
1839
|
* of the input value.
|
|
1745
1840
|
*/
|
|
1746
1841
|
function fullyResolveValue(value) {
|
|
@@ -1767,13 +1862,13 @@ function fullyResolveValue(value) {
|
|
|
1767
1862
|
return fullyResolveKeys(/** @type {!Object} */ (value));
|
|
1768
1863
|
}
|
|
1769
1864
|
|
|
1770
|
-
return
|
|
1865
|
+
return createPromise(resolve => resolve(value));
|
|
1771
1866
|
}
|
|
1772
1867
|
|
|
1773
1868
|
|
|
1774
1869
|
/**
|
|
1775
1870
|
* @param {!(Array|Object)} obj the object to resolve.
|
|
1776
|
-
* @return {!
|
|
1871
|
+
* @return {!Thenable} A promise that will be resolved with the
|
|
1777
1872
|
* input object once all of its values have been fully resolved.
|
|
1778
1873
|
*/
|
|
1779
1874
|
function fullyResolveKeys(obj) {
|
|
@@ -1785,8 +1880,9 @@ function fullyResolveKeys(obj) {
|
|
|
1785
1880
|
}
|
|
1786
1881
|
return n;
|
|
1787
1882
|
})();
|
|
1883
|
+
|
|
1788
1884
|
if (!numKeys) {
|
|
1789
|
-
return
|
|
1885
|
+
return createPromise(resolve => resolve(obj));
|
|
1790
1886
|
}
|
|
1791
1887
|
|
|
1792
1888
|
function forEachProperty(obj, fn) {
|
|
@@ -1800,7 +1896,7 @@ function fullyResolveKeys(obj) {
|
|
|
1800
1896
|
}
|
|
1801
1897
|
|
|
1802
1898
|
var numResolved = 0;
|
|
1803
|
-
return
|
|
1899
|
+
return createPromise(function(fulfill, reject) {
|
|
1804
1900
|
var forEachKey = isArray ? forEachElement: forEachProperty;
|
|
1805
1901
|
|
|
1806
1902
|
forEachKey(obj, function(partialValue, key) {
|
|
@@ -1834,6 +1930,236 @@ function fullyResolveKeys(obj) {
|
|
|
1834
1930
|
//////////////////////////////////////////////////////////////////////////////
|
|
1835
1931
|
|
|
1836
1932
|
|
|
1933
|
+
/**
|
|
1934
|
+
* Defines methods for coordinating the execution of asynchronous tasks.
|
|
1935
|
+
* @record
|
|
1936
|
+
*/
|
|
1937
|
+
class Scheduler {
|
|
1938
|
+
/**
|
|
1939
|
+
* Schedules a task for execution. If the task function is a generator, the
|
|
1940
|
+
* task will be executed using {@link ./promise.consume consume()}.
|
|
1941
|
+
*
|
|
1942
|
+
* @param {function(): (T|IThenable<T>)} fn The function to call to start the
|
|
1943
|
+
* task.
|
|
1944
|
+
* @param {string=} opt_description A description of the task for debugging
|
|
1945
|
+
* purposes.
|
|
1946
|
+
* @return {!Thenable<T>} A promise that will be resolved with the task
|
|
1947
|
+
* result.
|
|
1948
|
+
* @template T
|
|
1949
|
+
*/
|
|
1950
|
+
execute(fn, opt_description) {}
|
|
1951
|
+
|
|
1952
|
+
/**
|
|
1953
|
+
* Creates a new promise using the given resolver function.
|
|
1954
|
+
*
|
|
1955
|
+
* @param {function(
|
|
1956
|
+
* function((T|IThenable<T>|Thenable|null)=),
|
|
1957
|
+
* function(*=))} resolver
|
|
1958
|
+
* @return {!Thenable<T>}
|
|
1959
|
+
* @template T
|
|
1960
|
+
*/
|
|
1961
|
+
promise(resolver) {}
|
|
1962
|
+
|
|
1963
|
+
/**
|
|
1964
|
+
* Schedules a `setTimeout` call.
|
|
1965
|
+
*
|
|
1966
|
+
* @param {number} ms The timeout delay, in milliseconds.
|
|
1967
|
+
* @param {string=} opt_description A description to accompany the timeout.
|
|
1968
|
+
* @return {!Thenable<void>} A promise that will be resolved when the timeout
|
|
1969
|
+
* fires.
|
|
1970
|
+
*/
|
|
1971
|
+
timeout(ms, opt_description) {}
|
|
1972
|
+
|
|
1973
|
+
/**
|
|
1974
|
+
* Schedules a task to wait for a condition to hold.
|
|
1975
|
+
*
|
|
1976
|
+
* If the condition is defined as a function, it may return any value. Promies
|
|
1977
|
+
* will be resolved before testing if the condition holds (resolution time
|
|
1978
|
+
* counts towards the timeout). Once resolved, values are always evaluated as
|
|
1979
|
+
* booleans.
|
|
1980
|
+
*
|
|
1981
|
+
* If the condition function throws, or returns a rejected promise, the
|
|
1982
|
+
* wait task will fail.
|
|
1983
|
+
*
|
|
1984
|
+
* If the condition is defined as a promise, the scheduler will wait for it to
|
|
1985
|
+
* settle. If the timeout expires before the promise settles, the promise
|
|
1986
|
+
* returned by this function will be rejected.
|
|
1987
|
+
*
|
|
1988
|
+
* If this function is invoked with `timeout === 0`, or the timeout is
|
|
1989
|
+
* omitted, this scheduler will wait indefinitely for the condition to be
|
|
1990
|
+
* satisfied.
|
|
1991
|
+
*
|
|
1992
|
+
* @param {(!IThenable<T>|function())} condition The condition to poll,
|
|
1993
|
+
* or a promise to wait on.
|
|
1994
|
+
* @param {number=} opt_timeout How long to wait, in milliseconds, for the
|
|
1995
|
+
* condition to hold before timing out. If omitted, the flow will wait
|
|
1996
|
+
* indefinitely.
|
|
1997
|
+
* @param {string=} opt_message An optional error message to include if the
|
|
1998
|
+
* wait times out; defaults to the empty string.
|
|
1999
|
+
* @return {!Thenable<T>} A promise that will be fulfilled
|
|
2000
|
+
* when the condition has been satisified. The promise shall be rejected
|
|
2001
|
+
* if the wait times out waiting for the condition.
|
|
2002
|
+
* @throws {TypeError} If condition is not a function or promise or if timeout
|
|
2003
|
+
* is not a number >= 0.
|
|
2004
|
+
* @template T
|
|
2005
|
+
*/
|
|
2006
|
+
wait(condition, opt_timeout, opt_message) {}
|
|
2007
|
+
}
|
|
2008
|
+
|
|
2009
|
+
|
|
2010
|
+
let USE_PROMISE_MANAGER;
|
|
2011
|
+
function usePromiseManager() {
|
|
2012
|
+
if (typeof USE_PROMISE_MANAGER !== 'undefined') {
|
|
2013
|
+
return !!USE_PROMISE_MANAGER;
|
|
2014
|
+
}
|
|
2015
|
+
return process.env['SELENIUM_PROMISE_MANAGER'] === undefined
|
|
2016
|
+
|| !/^0|false$/i.test(process.env['SELENIUM_PROMISE_MANAGER']);
|
|
2017
|
+
}
|
|
2018
|
+
|
|
2019
|
+
|
|
2020
|
+
/**
|
|
2021
|
+
* @param {function(
|
|
2022
|
+
* function((T|IThenable<T>|Thenable|null)=),
|
|
2023
|
+
* function(*=))} resolver
|
|
2024
|
+
* @return {!Thenable<T>}
|
|
2025
|
+
* @template T
|
|
2026
|
+
*/
|
|
2027
|
+
function createPromise(resolver) {
|
|
2028
|
+
let ctor = usePromiseManager() ? ManagedPromise : NativePromise;
|
|
2029
|
+
return new ctor(resolver);
|
|
2030
|
+
}
|
|
2031
|
+
|
|
2032
|
+
|
|
2033
|
+
/**
|
|
2034
|
+
* @param {!Scheduler} scheduler The scheduler to use.
|
|
2035
|
+
* @param {(!IThenable<T>|function())} condition The condition to poll,
|
|
2036
|
+
* or a promise to wait on.
|
|
2037
|
+
* @param {number=} opt_timeout How long to wait, in milliseconds, for the
|
|
2038
|
+
* condition to hold before timing out. If omitted, the flow will wait
|
|
2039
|
+
* indefinitely.
|
|
2040
|
+
* @param {string=} opt_message An optional error message to include if the
|
|
2041
|
+
* wait times out; defaults to the empty string.
|
|
2042
|
+
* @return {!Thenable<T>} A promise that will be fulfilled
|
|
2043
|
+
* when the condition has been satisified. The promise shall be rejected
|
|
2044
|
+
* if the wait times out waiting for the condition.
|
|
2045
|
+
* @throws {TypeError} If condition is not a function or promise or if timeout
|
|
2046
|
+
* is not a number >= 0.
|
|
2047
|
+
* @template T
|
|
2048
|
+
*/
|
|
2049
|
+
function scheduleWait(scheduler, condition, opt_timeout, opt_message) {
|
|
2050
|
+
let timeout = opt_timeout || 0;
|
|
2051
|
+
if (typeof timeout !== 'number' || timeout < 0) {
|
|
2052
|
+
throw TypeError('timeout must be a number >= 0: ' + timeout);
|
|
2053
|
+
}
|
|
2054
|
+
|
|
2055
|
+
if (isPromise(condition)) {
|
|
2056
|
+
return scheduler.execute(function() {
|
|
2057
|
+
if (!timeout) {
|
|
2058
|
+
return condition;
|
|
2059
|
+
}
|
|
2060
|
+
return scheduler.promise(function(fulfill, reject) {
|
|
2061
|
+
let start = Date.now();
|
|
2062
|
+
let timer = setTimeout(function() {
|
|
2063
|
+
timer = null;
|
|
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'));
|
|
2069
|
+
}, timeout);
|
|
2070
|
+
|
|
2071
|
+
/** @type {Thenable} */(condition).then(
|
|
2072
|
+
function(value) {
|
|
2073
|
+
timer && clearTimeout(timer);
|
|
2074
|
+
fulfill(value);
|
|
2075
|
+
},
|
|
2076
|
+
function(error) {
|
|
2077
|
+
timer && clearTimeout(timer);
|
|
2078
|
+
reject(error);
|
|
2079
|
+
});
|
|
2080
|
+
});
|
|
2081
|
+
}, opt_message || '<anonymous wait: promise resolution>');
|
|
2082
|
+
}
|
|
2083
|
+
|
|
2084
|
+
if (typeof condition !== 'function') {
|
|
2085
|
+
throw TypeError('Invalid condition; must be a function or promise: ' +
|
|
2086
|
+
typeof condition);
|
|
2087
|
+
}
|
|
2088
|
+
|
|
2089
|
+
if (isGenerator(condition)) {
|
|
2090
|
+
let original = condition;
|
|
2091
|
+
condition = () => consume(original);
|
|
2092
|
+
}
|
|
2093
|
+
|
|
2094
|
+
return scheduler.execute(function() {
|
|
2095
|
+
var startTime = Date.now();
|
|
2096
|
+
return scheduler.promise(function(fulfill, reject) {
|
|
2097
|
+
pollCondition();
|
|
2098
|
+
|
|
2099
|
+
function pollCondition() {
|
|
2100
|
+
var conditionFn = /** @type {function()} */(condition);
|
|
2101
|
+
scheduler.execute(conditionFn).then(function(value) {
|
|
2102
|
+
var elapsed = Date.now() - startTime;
|
|
2103
|
+
if (!!value) {
|
|
2104
|
+
fulfill(value);
|
|
2105
|
+
} else if (timeout && elapsed >= timeout) {
|
|
2106
|
+
reject(
|
|
2107
|
+
new error.TimeoutError(
|
|
2108
|
+
(opt_message ? opt_message + '\n' : '')
|
|
2109
|
+
+ `Wait timed out after ${elapsed}ms`));
|
|
2110
|
+
} else {
|
|
2111
|
+
// Do not use asyncRun here because we need a non-micro yield
|
|
2112
|
+
// here so the UI thread is given a chance when running in a
|
|
2113
|
+
// browser.
|
|
2114
|
+
setTimeout(pollCondition, 0);
|
|
2115
|
+
}
|
|
2116
|
+
}, reject);
|
|
2117
|
+
}
|
|
2118
|
+
});
|
|
2119
|
+
}, opt_message || '<anonymous wait>');
|
|
2120
|
+
}
|
|
2121
|
+
|
|
2122
|
+
|
|
2123
|
+
/**
|
|
2124
|
+
* A scheduler that executes all tasks immediately, with no coordination. This
|
|
2125
|
+
* class is an event emitter for API compatibility with the {@link ControlFlow},
|
|
2126
|
+
* however, it emits no events.
|
|
2127
|
+
*
|
|
2128
|
+
* @implements {Scheduler}
|
|
2129
|
+
*/
|
|
2130
|
+
class SimpleScheduler extends events.EventEmitter {
|
|
2131
|
+
/** @override */
|
|
2132
|
+
execute(fn) {
|
|
2133
|
+
return this.promise((resolve, reject) => {
|
|
2134
|
+
try {
|
|
2135
|
+
if (isGenerator(fn)) {
|
|
2136
|
+
consume(fn).then(resolve, reject);
|
|
2137
|
+
} else {
|
|
2138
|
+
resolve(fn.call(undefined));
|
|
2139
|
+
}
|
|
2140
|
+
} catch (ex) {
|
|
2141
|
+
reject(ex);
|
|
2142
|
+
}
|
|
2143
|
+
});
|
|
2144
|
+
}
|
|
2145
|
+
|
|
2146
|
+
/** @override */
|
|
2147
|
+
promise(resolver) {
|
|
2148
|
+
return new NativePromise(resolver);
|
|
2149
|
+
}
|
|
2150
|
+
|
|
2151
|
+
/** @override */
|
|
2152
|
+
timeout(ms) {
|
|
2153
|
+
return this.promise(resolve => setTimeout(_ => resolve(), ms));
|
|
2154
|
+
}
|
|
2155
|
+
|
|
2156
|
+
/** @override */
|
|
2157
|
+
wait(condition, opt_timeout, opt_message) {
|
|
2158
|
+
return scheduleWait(this, condition, opt_timeout, opt_message);
|
|
2159
|
+
}
|
|
2160
|
+
}
|
|
2161
|
+
const SIMPLE_SCHEDULER = new SimpleScheduler;
|
|
2162
|
+
|
|
1837
2163
|
|
|
1838
2164
|
/**
|
|
1839
2165
|
* Handles the execution of scheduled tasks, each of which may be an
|
|
@@ -1860,13 +2186,20 @@ function fullyResolveKeys(obj) {
|
|
|
1860
2186
|
* If there are no listeners registered with the flow, the error will be
|
|
1861
2187
|
* rethrown to the global error handler.
|
|
1862
2188
|
*
|
|
1863
|
-
* Refer to the {@link ./promise} module documentation
|
|
2189
|
+
* Refer to the {@link ./promise} module documentation for a detailed
|
|
1864
2190
|
* explanation of how the ControlFlow coordinates task execution.
|
|
1865
2191
|
*
|
|
2192
|
+
* @implements {Scheduler}
|
|
1866
2193
|
* @final
|
|
1867
2194
|
*/
|
|
1868
2195
|
class ControlFlow extends events.EventEmitter {
|
|
1869
2196
|
constructor() {
|
|
2197
|
+
if (!usePromiseManager()) {
|
|
2198
|
+
throw TypeError(
|
|
2199
|
+
'Cannot instantiate control flow when the promise manager has'
|
|
2200
|
+
+ ' been disabled');
|
|
2201
|
+
}
|
|
2202
|
+
|
|
1870
2203
|
super();
|
|
1871
2204
|
|
|
1872
2205
|
/** @private {boolean} */
|
|
@@ -2036,21 +2369,7 @@ class ControlFlow extends events.EventEmitter {
|
|
|
2036
2369
|
return this.activeQueue_;
|
|
2037
2370
|
}
|
|
2038
2371
|
|
|
2039
|
-
/**
|
|
2040
|
-
* Schedules a task for execution. If there is nothing currently in the
|
|
2041
|
-
* queue, the task will be executed in the next turn of the event loop. If
|
|
2042
|
-
* the task function is a generator, the task will be executed using
|
|
2043
|
-
* {@link ./promise.consume consume()}.
|
|
2044
|
-
*
|
|
2045
|
-
* @param {function(): (T|ManagedPromise<T>)} fn The function to
|
|
2046
|
-
* call to start the task. If the function returns a
|
|
2047
|
-
* {@link ManagedPromise}, this instance will wait for it to be
|
|
2048
|
-
* resolved before starting the next task.
|
|
2049
|
-
* @param {string=} opt_description A description of the task.
|
|
2050
|
-
* @return {!ManagedPromise<T>} A promise that will be resolved
|
|
2051
|
-
* with the result of the action.
|
|
2052
|
-
* @template T
|
|
2053
|
-
*/
|
|
2372
|
+
/** @override */
|
|
2054
2373
|
execute(fn, opt_description) {
|
|
2055
2374
|
if (isGenerator(fn)) {
|
|
2056
2375
|
let original = fn;
|
|
@@ -2072,126 +2391,21 @@ class ControlFlow extends events.EventEmitter {
|
|
|
2072
2391
|
return task.promise;
|
|
2073
2392
|
}
|
|
2074
2393
|
|
|
2075
|
-
/**
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
* @return {!ManagedPromise} A promise that will be resolved with
|
|
2082
|
-
* the result of the action.
|
|
2083
|
-
*/
|
|
2394
|
+
/** @override */
|
|
2395
|
+
promise(resolver) {
|
|
2396
|
+
return new ManagedPromise(resolver, this);
|
|
2397
|
+
}
|
|
2398
|
+
|
|
2399
|
+
/** @override */
|
|
2084
2400
|
timeout(ms, opt_description) {
|
|
2085
|
-
return this.execute(
|
|
2086
|
-
return
|
|
2401
|
+
return this.execute(() => {
|
|
2402
|
+
return this.promise(resolve => setTimeout(() => resolve(), ms));
|
|
2087
2403
|
}, opt_description);
|
|
2088
2404
|
}
|
|
2089
2405
|
|
|
2090
|
-
/**
|
|
2091
|
-
* Schedules a task that shall wait for a condition to hold. Each condition
|
|
2092
|
-
* function may return any value, but it will always be evaluated as a
|
|
2093
|
-
* boolean.
|
|
2094
|
-
*
|
|
2095
|
-
* Condition functions may schedule sub-tasks with this instance, however,
|
|
2096
|
-
* their execution time will be factored into whether a wait has timed out.
|
|
2097
|
-
*
|
|
2098
|
-
* In the event a condition returns a ManagedPromise, the polling loop will wait for
|
|
2099
|
-
* it to be resolved before evaluating whether the condition has been
|
|
2100
|
-
* satisfied. The resolution time for a promise is factored into whether a
|
|
2101
|
-
* wait has timed out.
|
|
2102
|
-
*
|
|
2103
|
-
* If the condition function throws, or returns a rejected promise, the
|
|
2104
|
-
* wait task will fail.
|
|
2105
|
-
*
|
|
2106
|
-
* If the condition is defined as a promise, the flow will wait for it to
|
|
2107
|
-
* settle. If the timeout expires before the promise settles, the promise
|
|
2108
|
-
* returned by this function will be rejected.
|
|
2109
|
-
*
|
|
2110
|
-
* If this function is invoked with `timeout === 0`, or the timeout is
|
|
2111
|
-
* omitted, the flow will wait indefinitely for the condition to be satisfied.
|
|
2112
|
-
*
|
|
2113
|
-
* @param {(!ManagedPromise<T>|function())} condition The condition to poll,
|
|
2114
|
-
* or a promise to wait on.
|
|
2115
|
-
* @param {number=} opt_timeout How long to wait, in milliseconds, for the
|
|
2116
|
-
* condition to hold before timing out. If omitted, the flow will wait
|
|
2117
|
-
* indefinitely.
|
|
2118
|
-
* @param {string=} opt_message An optional error message to include if the
|
|
2119
|
-
* wait times out; defaults to the empty string.
|
|
2120
|
-
* @return {!ManagedPromise<T>} A promise that will be fulfilled
|
|
2121
|
-
* when the condition has been satisified. The promise shall be rejected
|
|
2122
|
-
* if the wait times out waiting for the condition.
|
|
2123
|
-
* @throws {TypeError} If condition is not a function or promise or if timeout
|
|
2124
|
-
* is not a number >= 0.
|
|
2125
|
-
* @template T
|
|
2126
|
-
*/
|
|
2406
|
+
/** @override */
|
|
2127
2407
|
wait(condition, opt_timeout, opt_message) {
|
|
2128
|
-
|
|
2129
|
-
if (typeof timeout !== 'number' || timeout < 0) {
|
|
2130
|
-
throw TypeError('timeout must be a number >= 0: ' + timeout);
|
|
2131
|
-
}
|
|
2132
|
-
|
|
2133
|
-
if (isPromise(condition)) {
|
|
2134
|
-
return this.execute(function() {
|
|
2135
|
-
if (!timeout) {
|
|
2136
|
-
return condition;
|
|
2137
|
-
}
|
|
2138
|
-
return new ManagedPromise(function(fulfill, reject) {
|
|
2139
|
-
var start = Date.now();
|
|
2140
|
-
var timer = setTimeout(function() {
|
|
2141
|
-
timer = null;
|
|
2142
|
-
reject(Error((opt_message ? opt_message + '\n' : '') +
|
|
2143
|
-
'Timed out waiting for promise to resolve after ' +
|
|
2144
|
-
(Date.now() - start) + 'ms'));
|
|
2145
|
-
}, timeout);
|
|
2146
|
-
|
|
2147
|
-
/** @type {Thenable} */(condition).then(
|
|
2148
|
-
function(value) {
|
|
2149
|
-
timer && clearTimeout(timer);
|
|
2150
|
-
fulfill(value);
|
|
2151
|
-
},
|
|
2152
|
-
function(error) {
|
|
2153
|
-
timer && clearTimeout(timer);
|
|
2154
|
-
reject(error);
|
|
2155
|
-
});
|
|
2156
|
-
});
|
|
2157
|
-
}, opt_message || '<anonymous wait: promise resolution>');
|
|
2158
|
-
}
|
|
2159
|
-
|
|
2160
|
-
if (typeof condition !== 'function') {
|
|
2161
|
-
throw TypeError('Invalid condition; must be a function or promise: ' +
|
|
2162
|
-
typeof condition);
|
|
2163
|
-
}
|
|
2164
|
-
|
|
2165
|
-
if (isGenerator(condition)) {
|
|
2166
|
-
let original = condition;
|
|
2167
|
-
condition = () => consume(original);
|
|
2168
|
-
}
|
|
2169
|
-
|
|
2170
|
-
var self = this;
|
|
2171
|
-
return this.execute(function() {
|
|
2172
|
-
var startTime = Date.now();
|
|
2173
|
-
return new ManagedPromise(function(fulfill, reject) {
|
|
2174
|
-
pollCondition();
|
|
2175
|
-
|
|
2176
|
-
function pollCondition() {
|
|
2177
|
-
var conditionFn = /** @type {function()} */(condition);
|
|
2178
|
-
self.execute(conditionFn).then(function(value) {
|
|
2179
|
-
var elapsed = Date.now() - startTime;
|
|
2180
|
-
if (!!value) {
|
|
2181
|
-
fulfill(value);
|
|
2182
|
-
} else if (timeout && elapsed >= timeout) {
|
|
2183
|
-
reject(new Error((opt_message ? opt_message + '\n' : '') +
|
|
2184
|
-
'Wait timed out after ' + elapsed + 'ms'));
|
|
2185
|
-
} else {
|
|
2186
|
-
// Do not use asyncRun here because we need a non-micro yield
|
|
2187
|
-
// here so the UI thread is given a chance when running in a
|
|
2188
|
-
// browser.
|
|
2189
|
-
setTimeout(pollCondition, 0);
|
|
2190
|
-
}
|
|
2191
|
-
}, reject);
|
|
2192
|
-
}
|
|
2193
|
-
});
|
|
2194
|
-
}, opt_message || '<anonymous wait>');
|
|
2408
|
+
return scheduleWait(this, condition, opt_timeout, opt_message);
|
|
2195
2409
|
}
|
|
2196
2410
|
|
|
2197
2411
|
/**
|
|
@@ -2297,13 +2511,14 @@ class ControlFlow extends events.EventEmitter {
|
|
|
2297
2511
|
this.cancelShutdown_();
|
|
2298
2512
|
this.cancelHold_();
|
|
2299
2513
|
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2514
|
+
setTimeout(() => {
|
|
2515
|
+
let listeners = this.listeners(ControlFlow.EventType.UNCAUGHT_EXCEPTION);
|
|
2516
|
+
if (!listeners.size) {
|
|
2517
|
+
throw error;
|
|
2518
|
+
} else {
|
|
2519
|
+
this.reportUncaughtException_(error);
|
|
2520
|
+
}
|
|
2521
|
+
}, 0);
|
|
2307
2522
|
}
|
|
2308
2523
|
|
|
2309
2524
|
/**
|
|
@@ -2521,6 +2736,9 @@ class TaskQueue extends events.EventEmitter {
|
|
|
2521
2736
|
/** @private {({task: !Task, q: !TaskQueue}|null)} */
|
|
2522
2737
|
this.pending_ = null;
|
|
2523
2738
|
|
|
2739
|
+
/** @private {TaskQueue} */
|
|
2740
|
+
this.subQ_ = null;
|
|
2741
|
+
|
|
2524
2742
|
/** @private {TaskQueueState} */
|
|
2525
2743
|
this.state_ = TaskQueueState.NEW;
|
|
2526
2744
|
|
|
@@ -2670,6 +2888,12 @@ class TaskQueue extends events.EventEmitter {
|
|
|
2670
2888
|
this.tasks_ = [];
|
|
2671
2889
|
}
|
|
2672
2890
|
|
|
2891
|
+
// Now that all of the remaining tasks have been silently cancelled (e.g. no
|
|
2892
|
+
// exisitng callbacks on those tasks will fire), clear the silence bit on
|
|
2893
|
+
// the cancellation error. This ensures additional callbacks registered in
|
|
2894
|
+
// the future will actually execute.
|
|
2895
|
+
cancellation.silent_ = false;
|
|
2896
|
+
|
|
2673
2897
|
if (this.pending_) {
|
|
2674
2898
|
vlog(2, () => this + '.abort(); cancelling pending task', this);
|
|
2675
2899
|
this.pending_.task.promise.cancel(
|
|
@@ -2695,7 +2919,7 @@ class TaskQueue extends events.EventEmitter {
|
|
|
2695
2919
|
var task;
|
|
2696
2920
|
do {
|
|
2697
2921
|
task = this.getNextTask_();
|
|
2698
|
-
} while (task && !task.promise
|
|
2922
|
+
} while (task && !isPending(task.promise));
|
|
2699
2923
|
|
|
2700
2924
|
if (!task) {
|
|
2701
2925
|
this.state_ = TaskQueueState.FINISHED;
|
|
@@ -2706,20 +2930,30 @@ class TaskQueue extends events.EventEmitter {
|
|
|
2706
2930
|
return;
|
|
2707
2931
|
}
|
|
2708
2932
|
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2933
|
+
let result = undefined;
|
|
2934
|
+
this.subQ_ = new TaskQueue(this.flow_);
|
|
2935
|
+
|
|
2936
|
+
this.subQ_.once('end', () => { // On task completion.
|
|
2937
|
+
this.subQ_ = null;
|
|
2938
|
+
this.pending_ && this.pending_.task.fulfill(result);
|
|
2939
|
+
});
|
|
2940
|
+
|
|
2941
|
+
this.subQ_.once('error', e => { // On task failure.
|
|
2942
|
+
this.subQ_ = null;
|
|
2943
|
+
if (Thenable.isImplementation(result)) {
|
|
2944
|
+
result.cancel(CancellationError.wrap(e));
|
|
2945
|
+
}
|
|
2946
|
+
this.pending_ && this.pending_.task.reject(e);
|
|
2947
|
+
});
|
|
2948
|
+
vlog(2, () => `${this} created ${this.subQ_} for ${task}`);
|
|
2714
2949
|
|
|
2715
|
-
var result = undefined;
|
|
2716
2950
|
try {
|
|
2717
|
-
this.pending_ = {task: task, q:
|
|
2951
|
+
this.pending_ = {task: task, q: this.subQ_};
|
|
2718
2952
|
task.promise.queue_ = this;
|
|
2719
|
-
result =
|
|
2720
|
-
|
|
2953
|
+
result = this.subQ_.execute_(task.execute);
|
|
2954
|
+
this.subQ_.start();
|
|
2721
2955
|
} catch (ex) {
|
|
2722
|
-
|
|
2956
|
+
this.subQ_.abort_(ex);
|
|
2723
2957
|
}
|
|
2724
2958
|
}
|
|
2725
2959
|
|
|
@@ -2809,28 +3043,6 @@ class TaskQueue extends events.EventEmitter {
|
|
|
2809
3043
|
}
|
|
2810
3044
|
}
|
|
2811
3045
|
|
|
2812
|
-
/**
|
|
2813
|
-
* @param {*} value the value originally returned by the task function.
|
|
2814
|
-
* @private
|
|
2815
|
-
*/
|
|
2816
|
-
onTaskComplete_(value) {
|
|
2817
|
-
if (this.pending_) {
|
|
2818
|
-
this.pending_.task.fulfill(value);
|
|
2819
|
-
}
|
|
2820
|
-
}
|
|
2821
|
-
|
|
2822
|
-
/**
|
|
2823
|
-
* @param {*} taskFnResult the value originally returned by the task function.
|
|
2824
|
-
* @param {*} error the error that caused the task function to terminate.
|
|
2825
|
-
* @private
|
|
2826
|
-
*/
|
|
2827
|
-
onTaskFailure_(taskFnResult, error) {
|
|
2828
|
-
if (Thenable.isImplementation(taskFnResult)) {
|
|
2829
|
-
taskFnResult.cancel(CancellationError.wrap(error));
|
|
2830
|
-
}
|
|
2831
|
-
this.pending_.task.reject(error);
|
|
2832
|
-
}
|
|
2833
|
-
|
|
2834
3046
|
/**
|
|
2835
3047
|
* @return {(Task|undefined)} the next task scheduled within this queue,
|
|
2836
3048
|
* if any.
|
|
@@ -2862,9 +3074,9 @@ class TaskQueue extends events.EventEmitter {
|
|
|
2862
3074
|
|
|
2863
3075
|
/**
|
|
2864
3076
|
* The default flow to use if no others are active.
|
|
2865
|
-
* @type {
|
|
3077
|
+
* @type {ControlFlow}
|
|
2866
3078
|
*/
|
|
2867
|
-
var defaultFlow
|
|
3079
|
+
var defaultFlow;
|
|
2868
3080
|
|
|
2869
3081
|
|
|
2870
3082
|
/**
|
|
@@ -2883,6 +3095,11 @@ var activeFlows = [];
|
|
|
2883
3095
|
* @throws {Error} If the default flow is not currently active.
|
|
2884
3096
|
*/
|
|
2885
3097
|
function setDefaultFlow(flow) {
|
|
3098
|
+
if (!usePromiseManager()) {
|
|
3099
|
+
throw Error(
|
|
3100
|
+
'You may not change set the control flow when the promise'
|
|
3101
|
+
+' manager is disabled');
|
|
3102
|
+
}
|
|
2886
3103
|
if (activeFlows.length) {
|
|
2887
3104
|
throw Error('You may only change the default flow while it is active');
|
|
2888
3105
|
}
|
|
@@ -2892,10 +3109,21 @@ function setDefaultFlow(flow) {
|
|
|
2892
3109
|
|
|
2893
3110
|
/**
|
|
2894
3111
|
* @return {!ControlFlow} The currently active control flow.
|
|
3112
|
+
* @suppress {checkTypes}
|
|
2895
3113
|
*/
|
|
2896
3114
|
function controlFlow() {
|
|
2897
|
-
|
|
2898
|
-
|
|
3115
|
+
if (!usePromiseManager()) {
|
|
3116
|
+
return SIMPLE_SCHEDULER;
|
|
3117
|
+
}
|
|
3118
|
+
|
|
3119
|
+
if (activeFlows.length) {
|
|
3120
|
+
return activeFlows[activeFlows.length - 1];
|
|
3121
|
+
}
|
|
3122
|
+
|
|
3123
|
+
if (!defaultFlow) {
|
|
3124
|
+
defaultFlow = new ControlFlow;
|
|
3125
|
+
}
|
|
3126
|
+
return defaultFlow;
|
|
2899
3127
|
}
|
|
2900
3128
|
|
|
2901
3129
|
|
|
@@ -2905,8 +3133,7 @@ function controlFlow() {
|
|
|
2905
3133
|
* a promise that resolves to the callback result.
|
|
2906
3134
|
* @param {function(!ControlFlow)} callback The entry point
|
|
2907
3135
|
* to the newly created flow.
|
|
2908
|
-
* @return {!
|
|
2909
|
-
* result.
|
|
3136
|
+
* @return {!Thenable} A promise that resolves to the callback result.
|
|
2910
3137
|
*/
|
|
2911
3138
|
function createFlow(callback) {
|
|
2912
3139
|
var flow = new ControlFlow;
|
|
@@ -2960,53 +3187,51 @@ function isGenerator(fn) {
|
|
|
2960
3187
|
* @param {Object=} opt_self The object to use as "this" when invoking the
|
|
2961
3188
|
* initial generator.
|
|
2962
3189
|
* @param {...*} var_args Any arguments to pass to the initial generator.
|
|
2963
|
-
* @return {!
|
|
3190
|
+
* @return {!Thenable<?>} A promise that will resolve to the
|
|
2964
3191
|
* generator's final result.
|
|
2965
3192
|
* @throws {TypeError} If the given function is not a generator.
|
|
2966
3193
|
*/
|
|
2967
|
-
function consume(generatorFn, opt_self, var_args) {
|
|
3194
|
+
function consume(generatorFn, opt_self, ...var_args) {
|
|
2968
3195
|
if (!isGenerator(generatorFn)) {
|
|
2969
3196
|
throw new TypeError('Input is not a GeneratorFunction: ' +
|
|
2970
3197
|
generatorFn.constructor.name);
|
|
2971
3198
|
}
|
|
2972
3199
|
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
return deferred.promise;
|
|
3200
|
+
let ret;
|
|
3201
|
+
return ret = createPromise((resolve, reject) => {
|
|
3202
|
+
let generator = generatorFn.apply(opt_self, var_args);
|
|
3203
|
+
callNext();
|
|
2978
3204
|
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
}
|
|
2983
|
-
|
|
2984
|
-
/** @param {*=} opt_error . */
|
|
2985
|
-
function callThrow(opt_error) {
|
|
2986
|
-
// Dictionary lookup required because Closure compiler's built-in
|
|
2987
|
-
// externs does not include GeneratorFunction.prototype.throw.
|
|
2988
|
-
pump(generator['throw'], opt_error);
|
|
2989
|
-
}
|
|
2990
|
-
|
|
2991
|
-
function pump(fn, opt_arg) {
|
|
2992
|
-
if (!deferred.promise.isPending()) {
|
|
2993
|
-
return; // Defererd was cancelled; silently abort.
|
|
3205
|
+
/** @param {*=} opt_value . */
|
|
3206
|
+
function callNext(opt_value) {
|
|
3207
|
+
pump(generator.next, opt_value);
|
|
2994
3208
|
}
|
|
2995
3209
|
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
deferred.reject(ex);
|
|
3000
|
-
return;
|
|
3210
|
+
/** @param {*=} opt_error . */
|
|
3211
|
+
function callThrow(opt_error) {
|
|
3212
|
+
pump(generator.throw, opt_error);
|
|
3001
3213
|
}
|
|
3002
3214
|
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3215
|
+
function pump(fn, opt_arg) {
|
|
3216
|
+
if (ret instanceof ManagedPromise && !isPending(ret)) {
|
|
3217
|
+
return; // Defererd was cancelled; silently abort.
|
|
3218
|
+
}
|
|
3007
3219
|
|
|
3008
|
-
|
|
3009
|
-
|
|
3220
|
+
try {
|
|
3221
|
+
var result = fn.call(generator, opt_arg);
|
|
3222
|
+
} catch (ex) {
|
|
3223
|
+
reject(ex);
|
|
3224
|
+
return;
|
|
3225
|
+
}
|
|
3226
|
+
|
|
3227
|
+
if (result.done) {
|
|
3228
|
+
resolve(result.value);
|
|
3229
|
+
return;
|
|
3230
|
+
}
|
|
3231
|
+
|
|
3232
|
+
asap(result.value, callNext, callThrow);
|
|
3233
|
+
}
|
|
3234
|
+
});
|
|
3010
3235
|
}
|
|
3011
3236
|
|
|
3012
3237
|
|
|
@@ -3014,12 +3239,14 @@ function consume(generatorFn, opt_self, var_args) {
|
|
|
3014
3239
|
|
|
3015
3240
|
|
|
3016
3241
|
module.exports = {
|
|
3242
|
+
CancellableThenable: CancellableThenable,
|
|
3017
3243
|
CancellationError: CancellationError,
|
|
3018
3244
|
ControlFlow: ControlFlow,
|
|
3019
3245
|
Deferred: Deferred,
|
|
3020
3246
|
MultipleUnhandledRejectionError: MultipleUnhandledRejectionError,
|
|
3021
3247
|
Thenable: Thenable,
|
|
3022
3248
|
Promise: ManagedPromise,
|
|
3249
|
+
Scheduler: Scheduler,
|
|
3023
3250
|
all: all,
|
|
3024
3251
|
asap: asap,
|
|
3025
3252
|
captureStackTrace: captureStackTrace,
|
|
@@ -3030,6 +3257,7 @@ module.exports = {
|
|
|
3030
3257
|
defer: defer,
|
|
3031
3258
|
delayed: delayed,
|
|
3032
3259
|
filter: filter,
|
|
3260
|
+
finally: thenFinally,
|
|
3033
3261
|
fulfilled: fulfilled,
|
|
3034
3262
|
fullyResolved: fullyResolved,
|
|
3035
3263
|
isGenerator: isGenerator,
|
|
@@ -3039,6 +3267,22 @@ module.exports = {
|
|
|
3039
3267
|
setDefaultFlow: setDefaultFlow,
|
|
3040
3268
|
when: when,
|
|
3041
3269
|
|
|
3270
|
+
/**
|
|
3271
|
+
* Indicates whether the promise manager is currently enabled. When disabled,
|
|
3272
|
+
* attempting to use the {@link ControlFlow} or {@link ManagedPromise Promise}
|
|
3273
|
+
* classes will generate an error.
|
|
3274
|
+
*
|
|
3275
|
+
* The promise manager is currently enabled by default, but may be disabled
|
|
3276
|
+
* by setting the environment variable `SELENIUM_PROMISE_MANAGER=0` or by
|
|
3277
|
+
* setting this property to false. Setting this property will always take
|
|
3278
|
+
* precedence ove the use of the environment variable.
|
|
3279
|
+
*
|
|
3280
|
+
* @return {boolean} Whether the promise manager is enabled.
|
|
3281
|
+
* @see <https://github.com/SeleniumHQ/selenium/issues/2969>
|
|
3282
|
+
*/
|
|
3283
|
+
get USE_PROMISE_MANAGER() { return usePromiseManager(); },
|
|
3284
|
+
set USE_PROMISE_MANAGER(/** boolean */value) { USE_PROMISE_MANAGER = value; },
|
|
3285
|
+
|
|
3042
3286
|
get LONG_STACK_TRACES() { return LONG_STACK_TRACES; },
|
|
3043
3287
|
set LONG_STACK_TRACES(v) { LONG_STACK_TRACES = v; },
|
|
3044
3288
|
};
|