From 6743175a3fd9217814fcc394f18f0ba83fa2b5c9 Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Sun, 1 Mar 2015 14:11:33 +0000
Subject: [PATCH] Issue #2442411 by jhedstrom: Update react/promise to 2.2.0

---
 core/composer.lock                            |  12 +-
 core/vendor/composer/autoload_files.php       |   2 +-
 core/vendor/composer/installed.json           |  92 +++---
 core/vendor/react/promise/CHANGELOG.md        |  12 +
 core/vendor/react/promise/README.md           | 279 ++++++++++++++---
 core/vendor/react/promise/composer.json       |   2 +-
 core/vendor/react/promise/src/Deferred.php    |  23 +-
 .../promise/src/ExtendedPromiseInterface.php  |  26 ++
 .../react/promise/src/FulfilledPromise.php    |  34 ++-
 core/vendor/react/promise/src/LazyPromise.php |  23 +-
 core/vendor/react/promise/src/Promise.php     |  67 +++-
 .../react/promise/src/RejectedPromise.php     |  42 ++-
 .../src/UnhandledRejectionException.php       |  31 ++
 core/vendor/react/promise/src/functions.php   |  56 +++-
 .../react/promise/src/functions_include.php   |   5 +
 .../react/promise/tests/DeferredTest.php      |  29 +-
 .../promise/tests/FulfilledPromiseTest.php    |   4 +-
 .../tests/FunctionCheckTypehintTest.php       | 118 +++++++
 .../promise/tests/FunctionResolveTest.php     |   8 +
 .../react/promise/tests/LazyPromiseTest.php   |   8 +-
 .../PromiseAdapter/CallbackPromiseAdapter.php |   4 +-
 .../PromiseAdapterInterface.php               |   2 +-
 .../react/promise/tests/PromiseTest.php       |  74 ++++-
 .../tests/PromiseTest/FullTestTrait.php       |   2 +-
 ...gressTestTrait.php => NotifyTestTrait.php} |  85 ++++--
 .../PromiseTest/PromiseFulfilledTestTrait.php | 153 ++++++++++
 .../PromiseTest/PromisePendingTestTrait.php   |  33 ++
 .../PromiseTest/PromiseRejectedTestTrait.php  | 289 ++++++++++++++++++
 .../PromiseTest/PromiseSettledTestTrait.php   |  37 +++
 .../tests/PromiseTest/RejectTestTrait.php     | 255 ++++++++++++++++
 .../tests/PromiseTest/ResolveTestTrait.php    | 149 +++++++++
 .../promise/tests/RejectedPromiseTest.php     |   4 +-
 32 files changed, 1798 insertions(+), 162 deletions(-)
 create mode 100644 core/vendor/react/promise/src/ExtendedPromiseInterface.php
 create mode 100644 core/vendor/react/promise/src/UnhandledRejectionException.php
 create mode 100644 core/vendor/react/promise/src/functions_include.php
 create mode 100644 core/vendor/react/promise/tests/FunctionCheckTypehintTest.php
 rename core/vendor/react/promise/tests/PromiseTest/{ProgressTestTrait.php => NotifyTestTrait.php} (73%)

diff --git a/core/composer.lock b/core/composer.lock
index a8c2d39f6a8e..8fd348dd9d9a 100644
--- a/core/composer.lock
+++ b/core/composer.lock
@@ -1390,16 +1390,16 @@
         },
         {
             "name": "react/promise",
-            "version": "v2.1.0",
+            "version": "v2.2.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/reactphp/promise.git",
-                "reference": "937b04f1b0ee8f6d180e75a0830aac778ca4bcd6"
+                "reference": "365fcee430dfa4ace1fbc75737ca60ceea7eeeef"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/reactphp/promise/zipball/937b04f1b0ee8f6d180e75a0830aac778ca4bcd6",
-                "reference": "937b04f1b0ee8f6d180e75a0830aac778ca4bcd6",
+                "url": "https://api.github.com/repos/reactphp/promise/zipball/365fcee430dfa4ace1fbc75737ca60ceea7eeeef",
+                "reference": "365fcee430dfa4ace1fbc75737ca60ceea7eeeef",
                 "shasum": ""
             },
             "require": {
@@ -1416,7 +1416,7 @@
                     "React\\Promise\\": "src/"
                 },
                 "files": [
-                    "src/functions.php"
+                    "src/functions_include.php"
                 ]
             },
             "notification-url": "https://packagist.org/downloads/",
@@ -1430,7 +1430,7 @@
                 }
             ],
             "description": "A lightweight implementation of CommonJS Promises/A for PHP",
-            "time": "2014-10-15 20:05:57"
+            "time": "2014-12-30 13:32:42"
         },
         {
             "name": "sdboyer/gliph",
diff --git a/core/vendor/composer/autoload_files.php b/core/vendor/composer/autoload_files.php
index c85d22cbdb20..853f9a068592 100644
--- a/core/vendor/composer/autoload_files.php
+++ b/core/vendor/composer/autoload_files.php
@@ -6,6 +6,6 @@
 $baseDir = dirname($vendorDir);
 
 return array(
-    $vendorDir . '/react/promise/src/functions.php',
+    $vendorDir . '/react/promise/src/functions_include.php',
     $baseDir . '/lib/Drupal.php',
 );
diff --git a/core/vendor/composer/installed.json b/core/vendor/composer/installed.json
index d41b956a9fe6..4544688d6f64 100644
--- a/core/vendor/composer/installed.json
+++ b/core/vendor/composer/installed.json
@@ -329,52 +329,6 @@
             "parser"
         ]
     },
-    {
-        "name": "react/promise",
-        "version": "v2.1.0",
-        "version_normalized": "2.1.0.0",
-        "source": {
-            "type": "git",
-            "url": "https://github.com/reactphp/promise.git",
-            "reference": "937b04f1b0ee8f6d180e75a0830aac778ca4bcd6"
-        },
-        "dist": {
-            "type": "zip",
-            "url": "https://api.github.com/repos/reactphp/promise/zipball/937b04f1b0ee8f6d180e75a0830aac778ca4bcd6",
-            "reference": "937b04f1b0ee8f6d180e75a0830aac778ca4bcd6",
-            "shasum": ""
-        },
-        "require": {
-            "php": ">=5.4.0"
-        },
-        "time": "2014-10-15 20:05:57",
-        "type": "library",
-        "extra": {
-            "branch-alias": {
-                "dev-master": "2.0-dev"
-            }
-        },
-        "installation-source": "dist",
-        "autoload": {
-            "psr-4": {
-                "React\\Promise\\": "src/"
-            },
-            "files": [
-                "src/functions.php"
-            ]
-        },
-        "notification-url": "https://packagist.org/downloads/",
-        "license": [
-            "MIT"
-        ],
-        "authors": [
-            {
-                "name": "Jan Sorgalla",
-                "email": "jsorgalla@googlemail.com"
-            }
-        ],
-        "description": "A lightweight implementation of CommonJS Promises/A for PHP"
-    },
     {
         "name": "guzzlehttp/streams",
         "version": "3.0.0",
@@ -3066,5 +3020,51 @@
         "keywords": [
             "scraper"
         ]
+    },
+    {
+        "name": "react/promise",
+        "version": "v2.2.0",
+        "version_normalized": "2.2.0.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/reactphp/promise.git",
+            "reference": "365fcee430dfa4ace1fbc75737ca60ceea7eeeef"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/reactphp/promise/zipball/365fcee430dfa4ace1fbc75737ca60ceea7eeeef",
+            "reference": "365fcee430dfa4ace1fbc75737ca60ceea7eeeef",
+            "shasum": ""
+        },
+        "require": {
+            "php": ">=5.4.0"
+        },
+        "time": "2014-12-30 13:32:42",
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-master": "2.0-dev"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "psr-4": {
+                "React\\Promise\\": "src/"
+            },
+            "files": [
+                "src/functions_include.php"
+            ]
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "Jan Sorgalla",
+                "email": "jsorgalla@googlemail.com"
+            }
+        ],
+        "description": "A lightweight implementation of CommonJS Promises/A for PHP"
     }
 ]
diff --git a/core/vendor/react/promise/CHANGELOG.md b/core/vendor/react/promise/CHANGELOG.md
index 870e112e2e42..f2d16543dfb2 100644
--- a/core/vendor/react/promise/CHANGELOG.md
+++ b/core/vendor/react/promise/CHANGELOG.md
@@ -1,6 +1,18 @@
 CHANGELOG
 =========
 
+* 2.2.0 (2014-12-30)
+
+  * Introduce new ExtendedPromiseInterface implemented by all promises
+  * Add new .done() method (part of the ExtendedPromiseInterface)
+  * Add new .otherwise() method (part of the ExtendedPromiseInterface)
+  * Add new .always() method (part of the ExtendedPromiseInterface)
+  * Add new .progress() method (part of the ExtendedPromiseInterface)
+  * Rename Deferred::progress to Deferred::notify to avoid confusion with
+    ExtendedPromiseInterface::progress (a Deferred::progress alias is still
+    available for backward compatibility)
+  * resolve() now always returns a ExtendedPromiseInterface
+
 * 2.1.0 (2014-10-15)
 
   * Introduce new CancellablePromiseInterface implemented by all promises
diff --git a/core/vendor/react/promise/README.md b/core/vendor/react/promise/README.md
index 1bb5c32c969c..0be869ebc57b 100644
--- a/core/vendor/react/promise/README.md
+++ b/core/vendor/react/promise/README.md
@@ -18,9 +18,14 @@ Table of Contents
      * [Deferred::promise()](#deferredpromise)
      * [Deferred::resolve()](#deferredresolve)
      * [Deferred::reject()](#deferredreject)
-     * [Deferred::progress()](#deferredprogress)
+     * [Deferred::notify()](#deferrednotify)
    * [PromiseInterface](#promiseinterface)
      * [PromiseInterface::then()](#promiseinterfacethen)
+   * [ExtendedPromiseInterface](#extendedpromiseinterface)
+        * [ExtendedPromiseInterface::done()](#extendedpromiseinterfacedone)
+        * [ExtendedPromiseInterface::otherwise()](#extendedpromiseinterfaceotherwise)
+        * [ExtendedPromiseInterface::always()](#extendedpromiseinterfacealways)
+        * [ExtendedPromiseInterface::progress()](#extendedpromiseinterfaceprogress)
    * [CancellablePromiseInterface](#cancellablepromiseinterface)
         * [CancellablePromiseInterface::cancel()](#cancellablepromiseinterfacecancel)
    * [Promise](#promise-1)
@@ -44,6 +49,7 @@ Table of Contents
      * [Rejection forwarding](#rejection-forwarding)
      * [Mixed resolution and rejection forwarding](#mixed-resolution-and-rejection-forwarding)
      * [Progress event forwarding](#progress-event-forwarding)
+   * [done() vs. then()](#done-vs-then)
 5. [Credits](#credits)
 6. [License](#license)
 
@@ -82,28 +88,28 @@ API
 A deferred represents an operation whose resolution is pending. It has separate
 promise and resolver parts.
 
-``` php
+```php
 $deferred = new React\Promise\Deferred();
 
 $promise = $deferred->promise();
 
 $deferred->resolve(mixed $value = null);
 $deferred->reject(mixed $reason = null);
-$deferred->progress(mixed $update = null);
+$deferred->notify(mixed $update = null);
 ```
 
 The `promise` method returns the promise of the deferred.
 
 The `resolve` and `reject` methods control the state of the deferred.
 
-The `progress` method is for progress notification.
+The `notify` method is for progress notification.
 
 The constructor of the `Deferred` accepts an optional `$canceller` argument.
 See [Promise](#promise-1) for more information.
 
 #### Deferred::promise()
 
-``` php
+```php
 $promise = $deferred->promise();
 ```
 
@@ -112,7 +118,7 @@ keeping the authority to modify its state to yourself.
 
 #### Deferred::resolve()
 
-``` php
+```php
 $deferred->resolve(mixed $value = null);
 ```
 
@@ -125,7 +131,7 @@ this promise once it is resolved.
 
 #### Deferred::reject()
 
-``` php
+```php
 $deferred->reject(mixed $reason = null);
 ```
 
@@ -137,10 +143,10 @@ All consumers are notified by having `$onRejected` (which they registered via
 If `$reason` itself is a promise, the promise will be rejected with the outcome
 of this promise regardless whether it fulfills or rejects.
 
-#### Deferred::progress()
+#### Deferred::notify()
 
-``` php
-$deferred->progress(mixed $update = null);
+```php
+$deferred->notify(mixed $update = null);
 ```
 
 Triggers progress notifications, to indicate to consumers that the computation
@@ -160,14 +166,24 @@ and an associated value, or rejection (failure) and an associated reason.
 Once in the fulfilled or rejected state, a promise becomes immutable.
 Neither its state nor its result (or error) can be modified.
 
+#### Implementations
+
+* [Promise](#promise-1)
+* [FulfilledPromise](#fulfilledpromise)
+* [RejectedPromise](#rejectedpromise)
+* [LazyPromise](#lazypromise)
+
 #### PromiseInterface::then()
 
-``` php
-$newPromise = $promise->then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null);
+```php
+$transformedPromise = $promise->then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null);
 ```
 
+Transforms a promise's value by applying a function to the promise's fulfillment
+or rejection value. Returns a new promise for the transformed result.
+
 The `then()` method registers new fulfilled, rejection and progress handlers
-with this promise (all parameters are optional):
+with a promise (all parameters are optional):
 
   * `$onFulfilled` will be invoked once the promise is fulfilled and passed
     the result as the first argument.
@@ -190,6 +206,18 @@ the same call to `then()`:
      than once.
   3. `$onProgress` may be called multiple times.
 
+#### See also
+
+* [resolve()](#resolve) - Creating a resolved promise
+* [reject()](#reject) - Creating a rejected promise
+* [ExtendedPromiseInterface::done()](#extendedpromiseinterfacedone)
+* [done() vs. then()](#done-vs-then)
+
+### ExtendedPromiseInterface
+
+The ExtendedPromiseInterface extends the PromiseInterface with useful shortcut
+and utility methods which are not part of the Promises/A specification.
+
 #### Implementations
 
 * [Promise](#promise-1)
@@ -197,10 +225,110 @@ the same call to `then()`:
 * [RejectedPromise](#rejectedpromise)
 * [LazyPromise](#lazypromise)
 
+#### ExtendedPromiseInterface::done()
+
+```php
+$promise->done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null);
+```
+
+Consumes the promise's ultimate value if the promise fulfills, or handles the
+ultimate error.
+
+It will cause a fatal error if either `$onFulfilled` or `$onRejected` throw or
+return a rejected promise.
+
+Since the purpose of `done()` is consumption rather than transformation,
+`done()` always returns `null`.
+
 #### See also
 
-* [resolve()](#resolve) - Creating a resolved promise
-* [reject()](#reject) - Creating a rejected promise
+* [PromiseInterface::then()](#promiseinterfacethen)
+* [done() vs. then()](#done-vs-then)
+
+#### ExtendedPromiseInterface::otherwise()
+
+```php
+$promise->otherwise(callable $onRejected);
+```
+
+Registers a rejection handler for promise. It is a shortcut for:
+
+```php
+$promise->then(null, $onRejected);
+```
+
+Additionally, you can type hint the `$reason` argument of `$onRejected` to catch
+only specific errors.
+
+```php
+$promise
+    ->otherwise(function (\RuntimeException $reason) {
+        // Only catch \RuntimeException instances
+        // All other types of errors will propagate automatically
+    })
+    ->otherwise(function ($reason) {
+        // Catch other errors
+    )};
+```
+
+#### ExtendedPromiseInterface::always()
+
+```php
+$newPromise = $promise->always(callable $onFulfilledOrRejected);
+```
+
+Allows you to execute "cleanup" type tasks in a promise chain.
+
+It arranges for `$onFulfilledOrRejected` to be called, with no arguments,
+when the promise is either fulfilled or rejected.
+
+* If `$promise` fulfills, and `$onFulfilledOrRejected` returns successfully,
+  `$newPromise` will fulfill with the same value as `$promise`.
+* If `$promise` fulfills, and `$onFulfilledOrRejected` throws or returns a
+  rejected promise, `$newPromise` will reject with the thrown exception or
+  rejected promise's reason.
+* If `$promise` rejects, and `$onFulfilledOrRejected` returns successfully,
+  `$newPromise` will reject with the same reason as `$promise`.
+* If `$promise` rejects, and `$onFulfilledOrRejected` throws or returns a
+  rejected promise, `$newPromise` will reject with the thrown exception or
+  rejected promise's reason.
+
+`always()` behaves similarly to the synchronous finally statement. When combined
+with `otherwise()`, `always()` allows you to write code that is similar to the familiar
+synchronous catch/finally pair.
+
+Consider the following synchronous code:
+
+```php
+try {
+  return doSomething();
+} catch(\Exception $e) {
+    return handleError($e);
+} finally {
+    cleanup();
+}
+```
+
+Similar asynchronous code (with `doSomething()` that returns a promise) can be
+written:
+
+```php
+return doSomething()
+    ->otherwise('handleError')
+    ->always('cleanup');
+```
+
+#### ExtendedPromiseInterface::progress()
+
+```php
+$promise->progress(callable $onProgress);
+```
+
+Registers a handler for progress updates from promise. It is a shortcut for:
+
+```php
+$promise->then(null, null, $onProgress);
+```
 
 ### CancellablePromiseInterface
 
@@ -232,8 +360,8 @@ a promise has no effect.
 Creates a promise whose state is controlled by the functions passed to
 `$resolver`.
 
-``` php
-$resolver = function (callable $resolve, callable $reject, callable $progress) {
+```php
+$resolver = function (callable $resolve, callable $reject, callable $notify) {
     // Do some work, possibly asynchronously, and then
     // resolve or reject. You can notify of progress events
     // along the way if you want/need.
@@ -241,7 +369,7 @@ $resolver = function (callable $resolve, callable $reject, callable $progress) {
     $resolve($awesomeResult);
     // or $resolve($anotherPromise);
     // or $reject($nastyError);
-    // or $progress($progressNotification);
+    // or $notify($progressNotification);
 };
 
 $canceller = function (callable $resolve, callable $reject, callable $progress) {
@@ -262,7 +390,7 @@ function which both will be called with 3 arguments:
     When called with another promise, e.g. `$resolve($otherPromise)`, promise's
     fate will be equivalent to that of `$otherPromise`.
   * `$reject($reason)` - Function that rejects the promise.
-  * `$progress($update)` - Function that issues progress events for the promise.
+  * `$notify($update)` - Function that issues progress events for the promise.
 
 If the resolver or canceller throw an exception, the promise will be rejected
 with that thrown exception as the rejection reason.
@@ -320,20 +448,25 @@ promises.
 
 #### resolve()
 
-``` php
+```php
 $promise = React\Promise\resolve(mixed $promiseOrValue);
 ```
 
-Creates a resolved promise for the supplied `$promiseOrValue`.
+Creates a promise for the supplied `$promiseOrValue`.
 
 If `$promiseOrValue` is a value, it will be the resolution value of the
 returned promise.
 
 If `$promiseOrValue` is a promise, it will simply be returned.
 
+Note: The promise returned is always a promise implementing
+[ExtendedPromiseInterface](#extendedpromiseinterface). If you pass in a custom
+promise which only implements [PromiseInterface](#promiseinterface), this
+promise will be assimilated to a extended promise following `$promiseOrValue`.
+
 #### reject()
 
-``` php
+```php
 $promise = React\Promise\reject(mixed $promiseOrValue);
 ```
 
@@ -351,7 +484,7 @@ the value of another promise.
 
 #### all()
 
-``` php
+```php
 $promise = React\Promise\all(array|React\Promise\PromiseInterface $promisesOrValues);
 ```
 
@@ -362,7 +495,7 @@ will be an array containing the resolution values of each of the items in
 
 #### race()
 
-``` php
+```php
 $promise = React\Promise\race(array|React\Promise\PromiseInterface $promisesOrValues);
 ```
 
@@ -371,7 +504,7 @@ resolved in the same way the first settled promise resolves.
 
 #### any()
 
-``` php
+```php
 $promise = React\Promise\any(array|React\Promise\PromiseInterface $promisesOrValues);
 ```
 
@@ -384,7 +517,7 @@ rejected. The rejection value will be an array of all rejection reasons.
 
 #### some()
 
-``` php
+```php
 $promise = React\Promise\some(array|React\Promise\PromiseInterface $promisesOrValues, integer $howMany);
 ```
 
@@ -400,7 +533,7 @@ reject). The rejection value will be an array of
 
 #### map()
 
-``` php
+```php
 $promise = React\Promise\map(array|React\Promise\PromiseInterface $promisesOrValues, callable $mapFunc);
 ```
 
@@ -412,7 +545,7 @@ value of a promise or value in `$promisesOrValues`.
 
 #### reduce()
 
-``` php
+```php
 $promise = React\Promise\reduce(array|React\Promise\PromiseInterface $promisesOrValues, callable $reduceFunc , $initialValue = null);
 ```
 
@@ -432,7 +565,7 @@ Examples
 
 ### How to use Deferred
 
-``` php
+```php
 function getAwesomeResultPromise()
 {
     $deferred = new React\Promise\Deferred();
@@ -480,7 +613,7 @@ to `$deferred->resolve()` below.
 Each call to `then()` returns a new promise that will resolve with the return
 value of the previous handler. This creates a promise "pipeline".
 
-``` php
+```php
 $deferred = new React\Promise\Deferred();
 
 $deferred->promise()
@@ -520,7 +653,7 @@ Similarly, when you handle a rejected promise, to propagate the rejection,
 "rethrow" it by either returning a rejected promise, or actually throwing
 (since promise translates thrown exceptions into rejections)
 
-``` php
+```php
 $deferred = new React\Promise\Deferred();
 
 $deferred->promise()
@@ -547,7 +680,7 @@ $deferred->resolve(1);  // Prints "Reject 3"
 Just like try/catch, you can choose to propagate or not. Mixing resolutions and
 rejections will still forward handler results in a predictable way.
 
-``` php
+```php
 $deferred = new React\Promise\Deferred();
 
 $deferred->promise()
@@ -587,20 +720,94 @@ chain so that they are meaningful to the next step. It also allows you to choose
 not to transform them, and simply let them propagate untransformed, by not
 registering a progress handler.
 
-``` php
+```php
 $deferred = new React\Promise\Deferred();
 
 $deferred->promise()
-    ->then(null, null, function ($update) {
+    ->progress(function ($update) {
         return $update + 1;
     })
-    ->then(null, null, function ($update) {
+    ->progress(function ($update) {
         echo 'Progress ' . $update; // 2
     });
 
-$deferred->progress(1);  // Prints "Progress 2"
+$deferred->notify(1);  // Prints "Progress 2"
 ```
 
+### done() vs. then()
+
+The golden rule is:
+
+    Either return your promise, or call done() on it.
+
+At a first glance, `then()` and `done()` seem very similar. However, there are
+important distinctions.
+
+The intent of `then()` is to transform a promise's value and to pass or return
+a new promise for the transformed value along to other parts of your code.
+
+The intent of `done()` is to consume a promise's value, transferring
+responsibility for the value to your code.
+
+In addition to transforming a value, `then()` allows you to recover from, or
+propagate intermediate errors. Any errors that are not handled will be caught
+by the promise machinery and used to reject the promise returned by `then()`.
+
+Calling `done()` transfers all responsibility for errors to your code. If an
+error (either a thrown exception or returned rejection) escapes the
+`$onFulfilled` or `$onRejected` callbacks you provide to done, it will be
+rethrown in an uncatchable way causing a fatal error.
+
+```php
+function getJsonResult()
+{
+    return queryApi()
+        ->then(
+            // Transform API results to an object
+            function ($jsonResultString) {
+                return json_decode($jsonResultString);
+            },
+            // Transform API errors to an exception
+            function ($jsonErrorString) {
+                $object = json_decode($jsonErrorString);
+                throw new ApiErrorException($object->errorMessage);
+            }
+        );
+}
+
+// Here we provide no rejection handler.
+// If the promise returned has been rejected,
+// a React\Promise\UnhandledRejectionException will be thrown
+getJsonResult()
+    ->done(
+        // Consume transformed object
+        function ($jsonResultObject) {
+            // Do something with $jsonObject
+        }
+    );
+
+// Here we provide a rejection handler which will either throw while debugging
+// or log the exception.
+getJsonResult()
+    ->done(
+        function ($jsonObject) {
+            // Do something with $jsonObject
+        },
+        function (ApiErrorException $exception) {
+            if (isDebug()) {
+                throw $e;
+            } else {
+                logException($exception);
+            }
+        }
+    );
+```
+
+Note that if a rejection value is not an instance of `\Exception`, it will be
+wrapped in an exception of the type `React\Promise\UnhandledRejectionException`.
+
+You can get the original rejection reason by calling `$exception->getReason()`.
+
 Credits
 -------
 
diff --git a/core/vendor/react/promise/composer.json b/core/vendor/react/promise/composer.json
index b8ca9a5450c3..c428b7ba6558 100644
--- a/core/vendor/react/promise/composer.json
+++ b/core/vendor/react/promise/composer.json
@@ -12,7 +12,7 @@
         "psr-4": {
             "React\\Promise\\": "src/"
         },
-        "files": ["src/functions.php"]
+        "files": ["src/functions_include.php"]
     },
     "extra": {
         "branch-alias": {
diff --git a/core/vendor/react/promise/src/Deferred.php b/core/vendor/react/promise/src/Deferred.php
index d7ae0aa1039b..f23980c31184 100644
--- a/core/vendor/react/promise/src/Deferred.php
+++ b/core/vendor/react/promise/src/Deferred.php
@@ -7,7 +7,7 @@ class Deferred implements PromisorInterface
     private $promise;
     private $resolveCallback;
     private $rejectCallback;
-    private $progressCallback;
+    private $notifyCallback;
     private $canceller;
 
     public function __construct(callable $canceller = null)
@@ -18,10 +18,10 @@ public function __construct(callable $canceller = null)
     public function promise()
     {
         if (null === $this->promise) {
-            $this->promise = new Promise(function ($resolve, $reject, $progress) {
-                $this->resolveCallback  = $resolve;
-                $this->rejectCallback   = $reject;
-                $this->progressCallback = $progress;
+            $this->promise = new Promise(function ($resolve, $reject, $notify) {
+                $this->resolveCallback = $resolve;
+                $this->rejectCallback  = $reject;
+                $this->notifyCallback  = $notify;
             }, $this->canceller);
         }
 
@@ -42,10 +42,19 @@ public function reject($reason = null)
         call_user_func($this->rejectCallback, $reason);
     }
 
-    public function progress($update = null)
+    public function notify($update = null)
     {
         $this->promise();
 
-        call_user_func($this->progressCallback, $update);
+        call_user_func($this->notifyCallback, $update);
+    }
+
+    /**
+     * @deprecated 2.2.0
+     * @see Deferred::notify()
+     */
+    public function progress($update = null)
+    {
+        $this->notify($update);
     }
 }
diff --git a/core/vendor/react/promise/src/ExtendedPromiseInterface.php b/core/vendor/react/promise/src/ExtendedPromiseInterface.php
new file mode 100644
index 000000000000..9cb643598752
--- /dev/null
+++ b/core/vendor/react/promise/src/ExtendedPromiseInterface.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace React\Promise;
+
+interface ExtendedPromiseInterface extends PromiseInterface
+{
+    /**
+     * @return void
+     */
+    public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null);
+
+    /**
+     * @return ExtendedPromiseInterface
+     */
+    public function otherwise(callable $onRejected);
+
+    /**
+     * @return ExtendedPromiseInterface
+     */
+    public function always(callable $onFulfilledOrRejected);
+
+    /**
+     * @return ExtendedPromiseInterface
+     */
+    public function progress(callable $onProgress);
+}
diff --git a/core/vendor/react/promise/src/FulfilledPromise.php b/core/vendor/react/promise/src/FulfilledPromise.php
index bfa3f9953e80..cd3665929bb5 100644
--- a/core/vendor/react/promise/src/FulfilledPromise.php
+++ b/core/vendor/react/promise/src/FulfilledPromise.php
@@ -2,7 +2,7 @@
 
 namespace React\Promise;
 
-class FulfilledPromise implements CancellablePromiseInterface
+class FulfilledPromise implements ExtendedPromiseInterface, CancellablePromiseInterface
 {
     private $value;
 
@@ -30,6 +30,38 @@ public function then(callable $onFulfilled = null, callable $onRejected = null,
         }
     }
 
+    public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
+    {
+        if (null === $onFulfilled) {
+            return;
+        }
+
+        $result = $onFulfilled($this->value);
+
+        if ($result instanceof ExtendedPromiseInterface) {
+            $result->done();
+        }
+    }
+
+    public function otherwise(callable $onRejected)
+    {
+        return new FulfilledPromise($this->value);
+    }
+
+    public function always(callable $onFulfilledOrRejected)
+    {
+        return $this->then(function ($value) use ($onFulfilledOrRejected) {
+            return resolve($onFulfilledOrRejected())->then(function () use ($value) {
+                return $value;
+            });
+        });
+    }
+
+    public function progress(callable $onProgress)
+    {
+        return new FulfilledPromise($this->value);
+    }
+
     public function cancel()
     {
     }
diff --git a/core/vendor/react/promise/src/LazyPromise.php b/core/vendor/react/promise/src/LazyPromise.php
index e1172e5499fc..68524a929d9e 100644
--- a/core/vendor/react/promise/src/LazyPromise.php
+++ b/core/vendor/react/promise/src/LazyPromise.php
@@ -2,7 +2,7 @@
 
 namespace React\Promise;
 
-class LazyPromise implements CancellablePromiseInterface
+class LazyPromise implements ExtendedPromiseInterface, CancellablePromiseInterface
 {
     private $factory;
     private $promise;
@@ -17,6 +17,27 @@ public function then(callable $onFulfilled = null, callable $onRejected = null,
         return $this->promise()->then($onFulfilled, $onRejected, $onProgress);
     }
 
+
+    public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
+    {
+        return $this->promise()->done($onFulfilled, $onRejected, $onProgress);
+    }
+
+    public function otherwise(callable $onRejected)
+    {
+        return $this->promise()->otherwise($onRejected);
+    }
+
+    public function always(callable $onFulfilledOrRejected)
+    {
+        return $this->promise()->always($onFulfilledOrRejected);
+    }
+
+    public function progress(callable $onProgress)
+    {
+        return $this->promise()->progress($onProgress);
+    }
+
     public function cancel()
     {
         return $this->promise()->cancel();
diff --git a/core/vendor/react/promise/src/Promise.php b/core/vendor/react/promise/src/Promise.php
index 09ebb32be831..b2635bf307f3 100644
--- a/core/vendor/react/promise/src/Promise.php
+++ b/core/vendor/react/promise/src/Promise.php
@@ -2,7 +2,7 @@
 
 namespace React\Promise;
 
-class Promise implements CancellablePromiseInterface
+class Promise implements ExtendedPromiseInterface, CancellablePromiseInterface
 {
     private $canceller;
     private $result;
@@ -40,6 +40,51 @@ public function then(callable $onFulfilled = null, callable $onRejected = null,
         });
     }
 
+    public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
+    {
+        if (null !== $this->result) {
+            return $this->result->done($onFulfilled, $onRejected, $onProgress);
+        }
+
+        $this->handlers[] = function (PromiseInterface $promise) use ($onFulfilled, $onRejected) {
+            $promise
+                ->done($onFulfilled, $onRejected);
+        };
+
+        if ($onProgress) {
+            $this->progressHandlers[] = $onProgress;
+        }
+    }
+
+    public function otherwise(callable $onRejected)
+    {
+        return $this->then(null, function ($reason) use ($onRejected) {
+            if (!_checkTypehint($onRejected, $reason)) {
+                return new RejectedPromise($reason);
+            }
+
+            return $onRejected($reason);
+        });
+    }
+
+    public function always(callable $onFulfilledOrRejected)
+    {
+        return $this->then(function ($value) use ($onFulfilledOrRejected) {
+            return resolve($onFulfilledOrRejected())->then(function () use ($value) {
+                return $value;
+            });
+        }, function ($reason) use ($onFulfilledOrRejected) {
+            return resolve($onFulfilledOrRejected())->then(function () use ($reason) {
+                return new RejectedPromise($reason);
+            });
+        });
+    }
+
+    public function progress(callable $onProgress)
+    {
+        return $this->then(null, null, $onProgress);
+    }
+
     public function cancel()
     {
         if (null === $this->canceller || null !== $this->result) {
@@ -51,23 +96,23 @@ public function cancel()
 
     private function resolver(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
     {
-        return function ($resolve, $reject, $progress) use ($onFulfilled, $onRejected, $onProgress) {
+        return function ($resolve, $reject, $notify) use ($onFulfilled, $onRejected, $onProgress) {
             if ($onProgress) {
-                $progressHandler = function ($update) use ($progress, $onProgress) {
+                $progressHandler = function ($update) use ($notify, $onProgress) {
                     try {
-                        $progress($onProgress($update));
+                        $notify($onProgress($update));
                     } catch (\Exception $e) {
-                        $progress($e);
+                        $notify($e);
                     }
                 };
             } else {
-                $progressHandler = $progress;
+                $progressHandler = $notify;
             }
 
             $this->handlers[] = function (PromiseInterface $promise) use ($onFulfilled, $onRejected, $resolve, $reject, $progressHandler) {
                 $promise
                     ->then($onFulfilled, $onRejected)
-                    ->then($resolve, $reject, $progressHandler);
+                    ->done($resolve, $reject, $progressHandler);
             };
 
             $this->progressHandlers[] = $progressHandler;
@@ -92,7 +137,7 @@ private function reject($reason = null)
         $this->settle(reject($reason));
     }
 
-    private function progress($update = null)
+    private function notify($update = null)
     {
         if (null !== $this->result) {
             return;
@@ -103,8 +148,10 @@ private function progress($update = null)
         }
     }
 
-    private function settle(PromiseInterface $result)
+    private function settle(ExtendedPromiseInterface $promise)
     {
+        $result = $promise;
+
         foreach ($this->handlers as $handler) {
             $handler($result);
         }
@@ -125,7 +172,7 @@ function ($reason = null) {
                     $this->reject($reason);
                 },
                 function ($update = null) {
-                    $this->progress($update);
+                    $this->notify($update);
                 }
             );
         } catch (\Exception $e) {
diff --git a/core/vendor/react/promise/src/RejectedPromise.php b/core/vendor/react/promise/src/RejectedPromise.php
index ee318cbf448a..350286df4300 100644
--- a/core/vendor/react/promise/src/RejectedPromise.php
+++ b/core/vendor/react/promise/src/RejectedPromise.php
@@ -2,7 +2,7 @@
 
 namespace React\Promise;
 
-class RejectedPromise implements CancellablePromiseInterface
+class RejectedPromise implements ExtendedPromiseInterface, CancellablePromiseInterface
 {
     private $reason;
 
@@ -28,6 +28,46 @@ public function then(callable $onFulfilled = null, callable $onRejected = null,
         }
     }
 
+    public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
+    {
+        if (null === $onRejected) {
+            throw UnhandledRejectionException::resolve($this->reason);
+        }
+
+        $result = $onRejected($this->reason);
+
+        if ($result instanceof self) {
+            throw UnhandledRejectionException::resolve($result->reason);
+        }
+
+        if ($result instanceof ExtendedPromiseInterface) {
+            $result->done();
+        }
+    }
+
+    public function otherwise(callable $onRejected)
+    {
+        if (!_checkTypehint($onRejected, $this->reason)) {
+            return new RejectedPromise($this->reason);
+        }
+
+        return $this->then(null, $onRejected);
+    }
+
+    public function always(callable $onFulfilledOrRejected)
+    {
+        return $this->then(null, function ($reason) use ($onFulfilledOrRejected) {
+            return resolve($onFulfilledOrRejected())->then(function () use ($reason) {
+                return new RejectedPromise($reason);
+            });
+        });
+    }
+
+    public function progress(callable $onProgress)
+    {
+        return new RejectedPromise($this->reason);
+    }
+
     public function cancel()
     {
     }
diff --git a/core/vendor/react/promise/src/UnhandledRejectionException.php b/core/vendor/react/promise/src/UnhandledRejectionException.php
new file mode 100644
index 000000000000..ed166b30a53a
--- /dev/null
+++ b/core/vendor/react/promise/src/UnhandledRejectionException.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace React\Promise;
+
+class UnhandledRejectionException extends \RuntimeException
+{
+    private $reason;
+
+    public static function resolve($reason)
+    {
+        if ($reason instanceof \Exception) {
+            return $reason;
+        }
+
+        return new static($reason);
+    }
+
+    public function __construct($reason)
+    {
+        $this->reason = $reason;
+
+        $message = sprintf('Unhandled Rejection: %s', json_encode($reason));
+
+        parent::__construct($message, 0);
+    }
+
+    public function getReason()
+    {
+        return $this->reason;
+    }
+}
diff --git a/core/vendor/react/promise/src/functions.php b/core/vendor/react/promise/src/functions.php
index fbf7766262c3..2eae6050e146 100644
--- a/core/vendor/react/promise/src/functions.php
+++ b/core/vendor/react/promise/src/functions.php
@@ -4,17 +4,23 @@
 
 function resolve($promiseOrValue = null)
 {
-    if ($promiseOrValue instanceof PromiseInterface) {
+    if (!$promiseOrValue instanceof PromiseInterface) {
+        return new FulfilledPromise($promiseOrValue);
+    }
+
+    if ($promiseOrValue instanceof ExtendedPromiseInterface) {
         return $promiseOrValue;
     }
 
-    return new FulfilledPromise($promiseOrValue);
+    return new Promise(function ($resolve, $reject, $notify) use ($promiseOrValue) {
+        $promiseOrValue->then($resolve, $reject, $notify);
+    });
 }
 
 function reject($promiseOrValue = null)
 {
     if ($promiseOrValue instanceof PromiseInterface) {
-        return $promiseOrValue->then(function ($value) {
+        return resolve($promiseOrValue)->then(function ($value) {
             return new RejectedPromise($value);
         });
     }
@@ -37,10 +43,10 @@ function race($promisesOrValues)
                 return resolve();
             }
 
-            return new Promise(function ($resolve, $reject, $progress) use ($array) {
+            return new Promise(function ($resolve, $reject, $notify) use ($array) {
                 foreach ($array as $promiseOrValue) {
                     resolve($promiseOrValue)
-                        ->then($resolve, $reject, $progress);
+                        ->done($resolve, $reject, $notify);
                 }
             });
         });
@@ -62,7 +68,7 @@ function some($promisesOrValues, $howMany)
                 return resolve([]);
             }
 
-            return new Promise(function ($resolve, $reject, $progress) use ($array, $howMany) {
+            return new Promise(function ($resolve, $reject, $notify) use ($array, $howMany) {
                 $len       = count($array);
                 $toResolve = min($howMany, $len);
                 $toReject  = ($len - $toResolve) + 1;
@@ -95,7 +101,7 @@ function some($promisesOrValues, $howMany)
                     };
 
                     resolve($promiseOrValue)
-                        ->then($fulfiller, $rejecter, $progress);
+                        ->done($fulfiller, $rejecter, $notify);
                 }
             });
         });
@@ -109,14 +115,14 @@ function map($promisesOrValues, callable $mapFunc)
                 return resolve([]);
             }
 
-            return new Promise(function ($resolve, $reject, $progress) use ($array, $mapFunc) {
+            return new Promise(function ($resolve, $reject, $notify) use ($array, $mapFunc) {
                 $toResolve = count($array);
                 $values    = [];
 
                 foreach ($array as $i => $promiseOrValue) {
                     resolve($promiseOrValue)
                         ->then($mapFunc)
-                        ->then(
+                        ->done(
                             function ($mapped) use ($i, &$values, &$toResolve, $resolve) {
                                 $values[$i] = $mapped;
 
@@ -125,7 +131,7 @@ function ($mapped) use ($i, &$values, &$toResolve, $resolve) {
                                 }
                             },
                             $reject,
-                            $progress
+                            $notify
                         );
                 }
             });
@@ -158,3 +164,33 @@ function reduce($promisesOrValues, callable $reduceFunc , $initialValue = null)
             return array_reduce($array, $wrappedReduceFunc, $initialValue);
         });
 }
+
+// Internal functions
+function _checkTypehint(callable $callback, $object)
+{
+    if (!is_object($object)) {
+        return true;
+    }
+
+    if (is_array($callback)) {
+        $callbackReflection = new \ReflectionMethod($callback[0], $callback[1]);
+    } elseif (is_object($callback) && !$callback instanceof \Closure) {
+        $callbackReflection = new \ReflectionMethod($callback, '__invoke');
+    } else {
+        $callbackReflection = new \ReflectionFunction($callback);
+    }
+
+    $parameters = $callbackReflection->getParameters();
+
+    if (!isset($parameters[0])) {
+        return true;
+    }
+
+    $expectedException = $parameters[0];
+
+    if (!$expectedException->getClass()) {
+        return true;
+    }
+
+    return $expectedException->getClass()->isInstance($object);
+}
diff --git a/core/vendor/react/promise/src/functions_include.php b/core/vendor/react/promise/src/functions_include.php
new file mode 100644
index 000000000000..c71decbf9895
--- /dev/null
+++ b/core/vendor/react/promise/src/functions_include.php
@@ -0,0 +1,5 @@
+<?php
+
+if (!function_exists('React\Promise\resolve')) {
+    require __DIR__.'/functions.php';
+}
diff --git a/core/vendor/react/promise/tests/DeferredTest.php b/core/vendor/react/promise/tests/DeferredTest.php
index 754a84dfcadf..16212e9e1cb8 100644
--- a/core/vendor/react/promise/tests/DeferredTest.php
+++ b/core/vendor/react/promise/tests/DeferredTest.php
@@ -13,11 +13,30 @@ public function getPromiseTestAdapter(callable $canceller = null)
         $d = new Deferred($canceller);
 
         return new CallbackPromiseAdapter([
-            'promise'  => [$d, 'promise'],
-            'resolve'  => [$d, 'resolve'],
-            'reject'   => [$d, 'reject'],
-            'progress' => [$d, 'progress'],
-            'settle'   => [$d, 'resolve'],
+            'promise' => [$d, 'promise'],
+            'resolve' => [$d, 'resolve'],
+            'reject'  => [$d, 'reject'],
+            'notify'  => [$d, 'progress'],
+            'settle'  => [$d, 'resolve'],
         ]);
     }
+
+    /** @test */
+    public function progressIsAnAliasForNotify()
+    {
+        $deferred = new Deferred();
+
+        $sentinel = new \stdClass();
+
+        $mock = $this->createCallableMock();
+        $mock
+            ->expects($this->once())
+            ->method('__invoke')
+            ->with($sentinel);
+
+        $deferred->promise()
+            ->then($this->expectCallableNever(), $this->expectCallableNever(), $mock);
+
+        $deferred->progress($sentinel);
+    }
 }
diff --git a/core/vendor/react/promise/tests/FulfilledPromiseTest.php b/core/vendor/react/promise/tests/FulfilledPromiseTest.php
index e72ecebc0ad0..97fc8f6c6d3c 100644
--- a/core/vendor/react/promise/tests/FulfilledPromiseTest.php
+++ b/core/vendor/react/promise/tests/FulfilledPromiseTest.php
@@ -29,8 +29,8 @@ public function getPromiseTestAdapter(callable $canceller = null)
             'reject' => function () {
                 throw new \LogicException('You cannot call reject() for React\Promise\FulfilledPromise');
             },
-            'progress' => function () {
-                throw new \LogicException('You cannot call progress() for React\Promise\FulfilledPromise');
+            'notify' => function () {
+                // no-op
             },
             'settle' => function ($value = null) use (&$promise) {
                 if (!$promise) {
diff --git a/core/vendor/react/promise/tests/FunctionCheckTypehintTest.php b/core/vendor/react/promise/tests/FunctionCheckTypehintTest.php
new file mode 100644
index 000000000000..8449bc1f7a39
--- /dev/null
+++ b/core/vendor/react/promise/tests/FunctionCheckTypehintTest.php
@@ -0,0 +1,118 @@
+<?php
+
+namespace React\Promise;
+
+class FunctionCheckTypehintTest extends TestCase
+{
+    /** @test */
+    public function shouldAcceptClosureCallbackWithTypehint()
+    {
+        $this->assertTrue(_checkTypehint(function (\InvalidArgumentException $e) {
+                }, new \InvalidArgumentException()));
+        $this->assertfalse(_checkTypehint(function (\InvalidArgumentException $e) {
+                }, new \Exception()));
+    }
+
+    /** @test */
+    public function shouldAcceptFunctionStringCallbackWithTypehint()
+    {
+        $this->assertTrue(_checkTypehint('React\Promise\testCallbackWithTypehint', new \InvalidArgumentException()));
+        $this->assertfalse(_checkTypehint('React\Promise\testCallbackWithTypehint', new \Exception()));
+    }
+
+    /** @test */
+    public function shouldAcceptInvokableObjectCallbackWithTypehint()
+    {
+        $this->assertTrue(_checkTypehint(new TestCallbackWithTypehintClass(), new \InvalidArgumentException()));
+        $this->assertfalse(_checkTypehint(new TestCallbackWithTypehintClass(), new \Exception()));
+    }
+
+    /** @test */
+    public function shouldAcceptObjectMethodCallbackWithTypehint()
+    {
+        $this->assertTrue(_checkTypehint([new TestCallbackWithTypehintClass(), 'testCallback'], new \InvalidArgumentException()));
+        $this->assertfalse(_checkTypehint([new TestCallbackWithTypehintClass(), 'testCallback'], new \Exception()));
+    }
+
+    /** @test */
+    public function shouldAcceptStaticClassCallbackWithTypehint()
+    {
+        $this->assertTrue(_checkTypehint(['React\Promise\TestCallbackWithTypehintClass', 'testCallbackStatic'], new \InvalidArgumentException()));
+        $this->assertfalse(_checkTypehint(['React\Promise\TestCallbackWithTypehintClass', 'testCallbackStatic'], new \Exception()));
+    }
+
+    /** @test */
+    public function shouldAcceptClosureCallbackWithoutTypehint()
+    {
+        $this->assertTrue(_checkTypehint(function (\InvalidArgumentException $e) {
+        }, new \InvalidArgumentException()));
+    }
+
+    /** @test */
+    public function shouldAcceptFunctionStringCallbackWithoutTypehint()
+    {
+        $this->assertTrue(_checkTypehint('React\Promise\testCallbackWithoutTypehint', new \InvalidArgumentException()));
+    }
+
+    /** @test */
+    public function shouldAcceptInvokableObjectCallbackWithoutTypehint()
+    {
+        $this->assertTrue(_checkTypehint(new TestCallbackWithoutTypehintClass(), new \InvalidArgumentException()));
+    }
+
+    /** @test */
+    public function shouldAcceptObjectMethodCallbackWithoutTypehint()
+    {
+        $this->assertTrue(_checkTypehint([new TestCallbackWithoutTypehintClass(), 'testCallback'], new \InvalidArgumentException()));
+    }
+
+    /** @test */
+    public function shouldAcceptStaticClassCallbackWithoutTypehint()
+    {
+        $this->assertTrue(_checkTypehint(['React\Promise\TestCallbackWithoutTypehintClass', 'testCallbackStatic'], new \InvalidArgumentException()));
+    }
+}
+
+function testCallbackWithTypehint(\InvalidArgumentException $e)
+{
+}
+
+function testCallbackWithoutTypehint()
+{
+}
+
+class TestCallbackWithTypehintClass
+{
+    public function __invoke(\InvalidArgumentException $e)
+    {
+
+    }
+
+    public function testCallback(\InvalidArgumentException $e)
+    {
+
+    }
+
+    public static function testCallbackStatic(\InvalidArgumentException $e)
+    {
+
+    }
+}
+
+class TestCallbackWithoutTypehintClass
+{
+    public function __invoke()
+    {
+
+    }
+
+    public function testCallback()
+    {
+
+    }
+
+    public static function testCallbackStatic()
+    {
+
+    }
+}
diff --git a/core/vendor/react/promise/tests/FunctionResolveTest.php b/core/vendor/react/promise/tests/FunctionResolveTest.php
index 01307d5a857a..576c30931f01 100644
--- a/core/vendor/react/promise/tests/FunctionResolveTest.php
+++ b/core/vendor/react/promise/tests/FunctionResolveTest.php
@@ -91,4 +91,12 @@ function ($val) {
 
         $result->then($mock);
     }
+
+    /** @test */
+    public function returnsExtendePromiseForSimplePromise()
+    {
+        $promise = $this->getMock('React\Promise\PromiseInterface');
+
+        $this->assertInstanceOf('React\Promise\ExtendedPromiseInterface', resolve($promise));
+    }
 }
diff --git a/core/vendor/react/promise/tests/LazyPromiseTest.php b/core/vendor/react/promise/tests/LazyPromiseTest.php
index a6eb44638083..b6308818a771 100644
--- a/core/vendor/react/promise/tests/LazyPromiseTest.php
+++ b/core/vendor/react/promise/tests/LazyPromiseTest.php
@@ -20,10 +20,10 @@ public function getPromiseTestAdapter(callable $canceller = null)
             'promise'  => function () use ($factory) {
                 return new LazyPromise($factory);
             },
-            'resolve'  => [$d, 'resolve'],
-            'reject'   => [$d, 'reject'],
-            'progress' => [$d, 'progress'],
-            'settle'   => [$d, 'resolve'],
+            'resolve' => [$d, 'resolve'],
+            'reject'  => [$d, 'reject'],
+            'notify'  => [$d, 'progress'],
+            'settle'  => [$d, 'resolve'],
         ]);
     }
 
diff --git a/core/vendor/react/promise/tests/PromiseAdapter/CallbackPromiseAdapter.php b/core/vendor/react/promise/tests/PromiseAdapter/CallbackPromiseAdapter.php
index 3a46050e9f43..bdedf4658e45 100644
--- a/core/vendor/react/promise/tests/PromiseAdapter/CallbackPromiseAdapter.php
+++ b/core/vendor/react/promise/tests/PromiseAdapter/CallbackPromiseAdapter.php
@@ -28,9 +28,9 @@ public function reject()
         return call_user_func_array($this->callbacks['reject'], func_get_args());
     }
 
-    public function progress()
+    public function notify()
     {
-        return call_user_func_array($this->callbacks['progress'], func_get_args());
+        return call_user_func_array($this->callbacks['notify'], func_get_args());
     }
 
     public function settle()
diff --git a/core/vendor/react/promise/tests/PromiseAdapter/PromiseAdapterInterface.php b/core/vendor/react/promise/tests/PromiseAdapter/PromiseAdapterInterface.php
index 01baf4667866..9157cd4ea725 100644
--- a/core/vendor/react/promise/tests/PromiseAdapter/PromiseAdapterInterface.php
+++ b/core/vendor/react/promise/tests/PromiseAdapter/PromiseAdapterInterface.php
@@ -9,6 +9,6 @@ interface PromiseAdapterInterface
     public function promise();
     public function resolve();
     public function reject();
-    public function progress();
+    public function notify();
     public function settle();
 }
diff --git a/core/vendor/react/promise/tests/PromiseTest.php b/core/vendor/react/promise/tests/PromiseTest.php
index 18e30f7c38ef..faba7046839c 100644
--- a/core/vendor/react/promise/tests/PromiseTest.php
+++ b/core/vendor/react/promise/tests/PromiseTest.php
@@ -22,10 +22,10 @@ public function getPromiseTestAdapter(callable $canceller = null)
             'promise' => function () use ($promise) {
                 return $promise;
             },
-            'resolve'  => $resolveCallback,
-            'reject'   => $rejectCallback,
-            'progress' => $progressCallback,
-            'settle'   => $resolveCallback,
+            'resolve' => $resolveCallback,
+            'reject'  => $rejectCallback,
+            'notify'  => $progressCallback,
+            'settle'  => $resolveCallback,
         ]);
     }
 
@@ -47,4 +47,70 @@ public function shouldRejectIfResolverThrowsException()
         $promise
             ->then($this->expectCallableNever(), $mock);
     }
+
+    /** @test */
+    public function shouldFulfillIfFullfilledWithSimplePromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $mock = $this->createCallableMock();
+        $mock
+            ->expects($this->once())
+            ->method('__invoke')
+            ->with($this->identicalTo('foo'));
+
+        $adapter->promise()
+            ->then($mock);
+
+        $adapter->resolve(new SimpleFulfilledTestPromise());
+    }
+
+    /** @test */
+    public function shouldRejectIfRejectedWithSimplePromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $mock = $this->createCallableMock();
+        $mock
+            ->expects($this->once())
+            ->method('__invoke')
+            ->with($this->identicalTo('foo'));
+
+        $adapter->promise()
+            ->then($this->expectCallableNever(), $mock);
+
+        $adapter->resolve(new SimpleRejectedTestPromise());
+    }
+}
+
+class SimpleFulfilledTestPromise implements PromiseInterface
+{
+    public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
+    {
+        try {
+            if ($onFulfilled) {
+                $onFulfilled('foo');
+            }
+
+            return new self('foo');
+        } catch (\Exception $exception) {
+            return new RejectedPromise($exception);
+        }
+    }
+}
+
+class SimpleRejectedTestPromise implements PromiseInterface
+{
+    public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
+    {
+        try {
+            if ($onRejected) {
+                $onRejected('foo');
+            }
+
+            return new self('foo');
+        } catch (\Exception $exception) {
+            return new RejectedPromise($exception);
+        }
+    }
 }
diff --git a/core/vendor/react/promise/tests/PromiseTest/FullTestTrait.php b/core/vendor/react/promise/tests/PromiseTest/FullTestTrait.php
index fd8f9342004b..3ce45d61fae4 100644
--- a/core/vendor/react/promise/tests/PromiseTest/FullTestTrait.php
+++ b/core/vendor/react/promise/tests/PromiseTest/FullTestTrait.php
@@ -10,6 +10,6 @@ trait FullTestTrait
         PromiseRejectedTestTrait,
         ResolveTestTrait,
         RejectTestTrait,
-        ProgressTestTrait,
+        NotifyTestTrait,
         CancelTestTrait;
 }
diff --git a/core/vendor/react/promise/tests/PromiseTest/ProgressTestTrait.php b/core/vendor/react/promise/tests/PromiseTest/NotifyTestTrait.php
similarity index 73%
rename from core/vendor/react/promise/tests/PromiseTest/ProgressTestTrait.php
rename to core/vendor/react/promise/tests/PromiseTest/NotifyTestTrait.php
index 0d160a8165aa..4501df67683f 100644
--- a/core/vendor/react/promise/tests/PromiseTest/ProgressTestTrait.php
+++ b/core/vendor/react/promise/tests/PromiseTest/NotifyTestTrait.php
@@ -2,7 +2,7 @@
 
 namespace React\Promise\PromiseTest;
 
-trait ProgressTestTrait
+trait NotifyTestTrait
 {
     /**
      * @return \React\Promise\PromiseAdapter\PromiseAdapterInterface
@@ -10,7 +10,7 @@ trait ProgressTestTrait
     abstract public function getPromiseTestAdapter(callable $canceller = null);
 
     /** @test */
-    public function progressShouldProgress()
+    public function notifyShouldProgress()
     {
         $adapter = $this->getPromiseTestAdapter();
 
@@ -25,11 +25,11 @@ public function progressShouldProgress()
         $adapter->promise()
             ->then($this->expectCallableNever(), $this->expectCallableNever(), $mock);
 
-        $adapter->progress($sentinel);
+        $adapter->notify($sentinel);
     }
 
     /** @test */
-    public function progressShouldPropagateProgressToDownstreamPromises()
+    public function notifyShouldPropagateProgressToDownstreamPromises()
     {
         $adapter = $this->getPromiseTestAdapter();
 
@@ -59,11 +59,11 @@ public function progressShouldPropagateProgressToDownstreamPromises()
                 $mock2
             );
 
-        $adapter->progress($sentinel);
+        $adapter->notify($sentinel);
     }
 
     /** @test */
-    public function progressShouldPropagateTransformedProgressToDownstreamPromises()
+    public function notifyShouldPropagateTransformedProgressToDownstreamPromises()
     {
         $adapter = $this->getPromiseTestAdapter();
 
@@ -93,11 +93,11 @@ public function progressShouldPropagateTransformedProgressToDownstreamPromises()
                 $mock2
             );
 
-        $adapter->progress(1);
+        $adapter->notify(1);
     }
 
     /** @test */
-    public function progressShouldPropagateCaughtExceptionValueAsProgress()
+    public function notifyShouldPropagateCaughtExceptionValueAsProgress()
     {
         $adapter = $this->getPromiseTestAdapter();
 
@@ -127,11 +127,11 @@ public function progressShouldPropagateCaughtExceptionValueAsProgress()
                 $mock2
             );
 
-        $adapter->progress(1);
+        $adapter->notify(1);
     }
 
     /** @test */
-    public function progressShouldForwardProgressEventsWhenIntermediaryCallbackTiedToAResolvedPromiseReturnsAPromise()
+    public function notifyShouldForwardProgressEventsWhenIntermediaryCallbackTiedToAResolvedPromiseReturnsAPromise()
     {
         $adapter = $this->getPromiseTestAdapter();
         $adapter2 = $this->getPromiseTestAdapter();
@@ -159,11 +159,11 @@ public function progressShouldForwardProgressEventsWhenIntermediaryCallbackTiedT
                 $mock
             );
 
-        $adapter2->progress($sentinel);
+        $adapter2->notify($sentinel);
     }
 
     /** @test */
-    public function progressShouldForwardProgressEventsWhenIntermediaryCallbackTiedToAnUnresolvedPromiseReturnsAPromise()
+    public function notifyShouldForwardProgressEventsWhenIntermediaryCallbackTiedToAnUnresolvedPromiseReturnsAPromise()
     {
         $adapter = $this->getPromiseTestAdapter();
         $adapter2 = $this->getPromiseTestAdapter();
@@ -190,11 +190,11 @@ public function progressShouldForwardProgressEventsWhenIntermediaryCallbackTiedT
 
         // resolve AFTER attaching progress handler
         $adapter->resolve();
-        $adapter2->progress($sentinel);
+        $adapter2->notify($sentinel);
     }
 
     /** @test */
-    public function progressShouldForwardProgressWhenResolvedWithAnotherPromise()
+    public function notifyShouldForwardProgressWhenResolvedWithAnotherPromise()
     {
         $adapter = $this->getPromiseTestAdapter();
         $adapter2 = $this->getPromiseTestAdapter();
@@ -226,11 +226,11 @@ public function progressShouldForwardProgressWhenResolvedWithAnotherPromise()
             );
 
         $adapter->resolve($adapter2->promise());
-        $adapter2->progress($sentinel);
+        $adapter2->notify($sentinel);
     }
 
     /** @test */
-    public function progressShouldAllowResolveAfterProgress()
+    public function notifyShouldAllowResolveAfterProgress()
     {
         $adapter = $this->getPromiseTestAdapter();
 
@@ -251,12 +251,12 @@ public function progressShouldAllowResolveAfterProgress()
                 $mock
             );
 
-        $adapter->progress(1);
+        $adapter->notify(1);
         $adapter->resolve(2);
     }
 
     /** @test */
-    public function progressShouldAllowRejectAfterProgress()
+    public function notifyShouldAllowRejectAfterProgress()
     {
         $adapter = $this->getPromiseTestAdapter();
 
@@ -277,17 +277,60 @@ public function progressShouldAllowRejectAfterProgress()
                 $mock
             );
 
-        $adapter->progress(1);
+        $adapter->notify(1);
         $adapter->reject(2);
     }
 
     /** @test */
-    public function progressShouldReturnSilentlyOnProgressWhenAlreadyRejected()
+    public function notifyShouldReturnSilentlyOnProgressWhenAlreadyRejected()
     {
         $adapter = $this->getPromiseTestAdapter();
 
         $adapter->reject(1);
 
-        $this->assertNull($adapter->progress());
+        $this->assertNull($adapter->notify());
+    }
+
+    /** @test */
+    public function notifyShouldInvokeProgressHandler()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $mock = $this->createCallableMock();
+        $mock
+            ->expects($this->once())
+            ->method('__invoke')
+            ->with($this->identicalTo(1));
+
+        $adapter->promise()->progress($mock);
+        $adapter->notify(1);
+    }
+
+    /** @test */
+    public function notifyShouldInvokeProgressHandlerFromDone()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $mock = $this->createCallableMock();
+        $mock
+            ->expects($this->once())
+            ->method('__invoke')
+            ->with($this->identicalTo(1));
+
+        $this->assertNull($adapter->promise()->done(null, null, $mock));
+        $adapter->notify(1);
+    }
+
+    /** @test */
+    public function notifyShouldThrowExceptionThrownProgressHandlerFromDone()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $this->setExpectedException('\Exception', 'UnhandledRejectionException');
+
+        $this->assertNull($adapter->promise()->done(null, null, function () {
+            throw new \Exception('UnhandledRejectionException');
+        }));
+        $adapter->notify(1);
     }
 }
diff --git a/core/vendor/react/promise/tests/PromiseTest/PromiseFulfilledTestTrait.php b/core/vendor/react/promise/tests/PromiseTest/PromiseFulfilledTestTrait.php
index 5ae29422d056..428230b97ac1 100644
--- a/core/vendor/react/promise/tests/PromiseTest/PromiseFulfilledTestTrait.php
+++ b/core/vendor/react/promise/tests/PromiseTest/PromiseFulfilledTestTrait.php
@@ -195,4 +195,157 @@ public function cancelShouldHaveNoEffectForFulfilledPromise()
 
         $adapter->promise()->cancel();
     }
+
+    /** @test */
+    public function doneShouldInvokeFulfillmentHandlerForFulfilledPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $mock = $this->createCallableMock();
+        $mock
+            ->expects($this->once())
+            ->method('__invoke')
+            ->with($this->identicalTo(1));
+
+        $adapter->resolve(1);
+        $this->assertNull($adapter->promise()->done($mock));
+    }
+
+    /** @test */
+    public function doneShouldThrowExceptionThrownFulfillmentHandlerForFulfilledPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $this->setExpectedException('\Exception', 'UnhandledRejectionException');
+
+        $adapter->resolve(1);
+        $this->assertNull($adapter->promise()->done(function () {
+            throw new \Exception('UnhandledRejectionException');
+        }));
+    }
+
+    /** @test */
+    public function doneShouldThrowUnhandledRejectionExceptionWhenFulfillmentHandlerRejectsForFulfilledPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $this->setExpectedException('React\\Promise\\UnhandledRejectionException');
+
+        $adapter->resolve(1);
+        $this->assertNull($adapter->promise()->done(function () {
+            return \React\Promise\reject();
+        }));
+    }
+
+    /** @test */
+    public function otherwiseShouldNotInvokeRejectionHandlerForFulfilledPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $adapter->resolve(1);
+        $adapter->promise()->otherwise($this->expectCallableNever());
+    }
+
+    /** @test */
+    public function alwaysShouldNotSuppressValueForFulfilledPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $value = new \stdClass();
+
+        $mock = $this->createCallableMock();
+        $mock
+            ->expects($this->once())
+            ->method('__invoke')
+            ->with($this->identicalTo($value));
+
+        $adapter->resolve($value);
+        $adapter->promise()
+            ->always(function () {})
+            ->then($mock);
+    }
+
+    /** @test */
+    public function alwaysShouldNotSuppressValueWhenHandlerReturnsANonPromiseForFulfilledPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $value = new \stdClass();
+
+        $mock = $this->createCallableMock();
+        $mock
+            ->expects($this->once())
+            ->method('__invoke')
+            ->with($this->identicalTo($value));
+
+        $adapter->resolve($value);
+        $adapter->promise()
+            ->always(function () {
+                return 1;
+            })
+            ->then($mock);
+    }
+
+    /** @test */
+    public function alwaysShouldNotSuppressValueWhenHandlerReturnsAPromiseForFulfilledPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $value = new \stdClass();
+
+        $mock = $this->createCallableMock();
+        $mock
+            ->expects($this->once())
+            ->method('__invoke')
+            ->with($this->identicalTo($value));
+
+        $adapter->resolve($value);
+        $adapter->promise()
+            ->always(function () {
+                return \React\Promise\resolve(1);
+            })
+            ->then($mock);
+    }
+
+    /** @test */
+    public function alwaysShouldRejectWhenHandlerThrowsForFulfilledPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $exception = new \Exception();
+
+        $mock = $this->createCallableMock();
+        $mock
+            ->expects($this->once())
+            ->method('__invoke')
+            ->with($this->identicalTo($exception));
+
+        $adapter->resolve(1);
+        $adapter->promise()
+            ->always(function () use ($exception) {
+                throw $exception;
+            })
+            ->then(null, $mock);
+    }
+
+    /** @test */
+    public function alwaysShouldRejectWhenHandlerRejectsForFulfilledPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $exception = new \Exception();
+
+        $mock = $this->createCallableMock();
+        $mock
+            ->expects($this->once())
+            ->method('__invoke')
+            ->with($this->identicalTo($exception));
+
+        $adapter->resolve(1);
+        $adapter->promise()
+            ->always(function () use ($exception) {
+                return \React\Promise\reject($exception);
+            })
+            ->then(null, $mock);
+    }
 }
diff --git a/core/vendor/react/promise/tests/PromiseTest/PromisePendingTestTrait.php b/core/vendor/react/promise/tests/PromiseTest/PromisePendingTestTrait.php
index 0b188013fe90..a4f48ee25304 100644
--- a/core/vendor/react/promise/tests/PromiseTest/PromisePendingTestTrait.php
+++ b/core/vendor/react/promise/tests/PromiseTest/PromisePendingTestTrait.php
@@ -32,4 +32,37 @@ public function cancelShouldReturnNullForPendingPromise()
 
         $this->assertNull($adapter->promise()->cancel());
     }
+
+    /** @test */
+    public function doneShouldReturnNullForPendingPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $this->assertNull($adapter->promise()->done());
+    }
+
+    /** @test */
+    public function doneShouldReturnAllowNullForPendingPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $this->assertNull($adapter->promise()->done(null, null, null));
+    }
+
+    /** @test */
+    public function otherwiseShouldNotInvokeRejectionHandlerForPendingPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $adapter->settle();
+        $adapter->promise()->otherwise($this->expectCallableNever());
+    }
+
+    /** @test */
+    public function alwaysShouldReturnAPromiseForPendingPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $this->assertInstanceOf('React\\Promise\\PromiseInterface', $adapter->promise()->always(function () {}));
+    }
 }
diff --git a/core/vendor/react/promise/tests/PromiseTest/PromiseRejectedTestTrait.php b/core/vendor/react/promise/tests/PromiseTest/PromiseRejectedTestTrait.php
index a9cfa68ad089..64255e8311ab 100644
--- a/core/vendor/react/promise/tests/PromiseTest/PromiseRejectedTestTrait.php
+++ b/core/vendor/react/promise/tests/PromiseTest/PromiseRejectedTestTrait.php
@@ -2,6 +2,8 @@
 
 namespace React\Promise\PromiseTest;
 
+use React\Promise\Deferred;
+
 trait PromiseRejectedTestTrait
 {
     /**
@@ -181,6 +183,293 @@ function ($val) {
             );
     }
 
+    /** @test */
+    public function doneShouldInvokeRejectionHandlerForRejectedPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $mock = $this->createCallableMock();
+        $mock
+            ->expects($this->once())
+            ->method('__invoke')
+            ->with($this->identicalTo(1));
+
+        $adapter->reject(1);
+        $this->assertNull($adapter->promise()->done(null, $mock));
+    }
+
+    /** @test */
+    public function doneShouldThrowExceptionThrownByRejectionHandlerForRejectedPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $this->setExpectedException('\Exception', 'UnhandledRejectionException');
+
+        $adapter->reject(1);
+        $this->assertNull($adapter->promise()->done(null, function () {
+            throw new \Exception('UnhandledRejectionException');
+        }));
+    }
+
+    /** @test */
+    public function doneShouldThrowUnhandledRejectionExceptionWhenRejectedWithNonExceptionForRejectedPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $this->setExpectedException('React\\Promise\\UnhandledRejectionException');
+
+        $adapter->reject(1);
+        $this->assertNull($adapter->promise()->done());
+    }
+
+    /** @test */
+    public function doneShouldThrowUnhandledRejectionExceptionWhenRejectionHandlerRejectsForRejectedPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $this->setExpectedException('React\\Promise\\UnhandledRejectionException');
+
+        $adapter->reject(1);
+        $this->assertNull($adapter->promise()->done(null, function () {
+            return \React\Promise\reject();
+        }));
+    }
+
+    /** @test */
+    public function doneShouldThrowRejectionExceptionWhenRejectionHandlerRejectsWithExceptionForRejectedPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $this->setExpectedException('\Exception', 'UnhandledRejectionException');
+
+        $adapter->reject(1);
+        $this->assertNull($adapter->promise()->done(null, function () {
+            return \React\Promise\reject(new \Exception('UnhandledRejectionException'));
+        }));
+    }
+
+    /** @test */
+    public function doneShouldThrowExceptionProvidedAsRejectionValueForRejectedPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $this->setExpectedException('\Exception', 'UnhandledRejectionException');
+
+        $adapter->reject(new \Exception('UnhandledRejectionException'));
+        $this->assertNull($adapter->promise()->done());
+    }
+
+    /** @test */
+    public function doneShouldThrowWithDeepNestingPromiseChainsForRejectedPromise()
+    {
+        $this->setExpectedException('\Exception', 'UnhandledRejectionException');
+
+        $exception = new \Exception('UnhandledRejectionException');
+
+        $d = new Deferred();
+        $d->resolve();
+
+        $result = \React\Promise\resolve(\React\Promise\resolve($d->promise()->then(function () use ($exception) {
+            $d = new Deferred();
+            $d->resolve();
+
+            return \React\Promise\resolve($d->promise()->then(function () {}))->then(
+                function () use ($exception) {
+                    throw $exception;
+                }
+            );
+        })));
+
+        $result->done();
+    }
+
+    /** @test */
+    public function doneShouldRecoverWhenRejectionHandlerCatchesExceptionForRejectedPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $adapter->reject(new \Exception('UnhandledRejectionException'));
+        $this->assertNull($adapter->promise()->done(null, function (\Exception $e) {
+
+        }));
+    }
+
+    /** @test */
+    public function otherwiseShouldInvokeRejectionHandlerForRejectedPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $mock = $this->createCallableMock();
+        $mock
+            ->expects($this->once())
+            ->method('__invoke')
+            ->with($this->identicalTo(1));
+
+        $adapter->reject(1);
+        $adapter->promise()->otherwise($mock);
+    }
+
+    /** @test */
+    public function otherwiseShouldInvokeNonTypeHintedRejectionHandlerIfReasonIsAnExceptionForRejectedPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $exception = new \Exception();
+
+        $mock = $this->createCallableMock();
+        $mock
+            ->expects($this->once())
+            ->method('__invoke')
+            ->with($this->identicalTo($exception));
+
+        $adapter->reject($exception);
+        $adapter->promise()
+            ->otherwise(function ($reason) use ($mock) {
+                $mock($reason);
+            });
+    }
+
+    /** @test */
+    public function otherwiseShouldInvokeRejectionHandlerIfReasonMatchesTypehintForRejectedPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $exception = new \InvalidArgumentException();
+
+        $mock = $this->createCallableMock();
+        $mock
+            ->expects($this->once())
+            ->method('__invoke')
+            ->with($this->identicalTo($exception));
+
+        $adapter->reject($exception);
+        $adapter->promise()
+            ->otherwise(function (\InvalidArgumentException $reason) use ($mock) {
+                $mock($reason);
+            });
+    }
+
+    /** @test */
+    public function otherwiseShouldNotInvokeRejectionHandlerIfReaonsDoesNotMatchTypehintForRejectedPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $exception = new \Exception();
+
+        $mock = $this->expectCallableNever();
+
+        $adapter->reject($exception);
+        $adapter->promise()
+            ->otherwise(function (\InvalidArgumentException $reason) use ($mock) {
+                $mock($reason);
+            });
+    }
+
+    /** @test */
+    public function alwaysShouldNotSuppressRejectionForRejectedPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $exception = new \Exception();
+
+        $mock = $this->createCallableMock();
+        $mock
+            ->expects($this->once())
+            ->method('__invoke')
+            ->with($this->identicalTo($exception));
+
+        $adapter->reject($exception);
+        $adapter->promise()
+            ->always(function () {})
+            ->then(null, $mock);
+    }
+
+    /** @test */
+    public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsANonPromiseForRejectedPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $exception = new \Exception();
+
+        $mock = $this->createCallableMock();
+        $mock
+            ->expects($this->once())
+            ->method('__invoke')
+            ->with($this->identicalTo($exception));
+
+        $adapter->reject($exception);
+        $adapter->promise()
+            ->always(function () {
+                return 1;
+            })
+            ->then(null, $mock);
+    }
+
+    /** @test */
+    public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsAPromiseForRejectedPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $exception = new \Exception();
+
+        $mock = $this->createCallableMock();
+        $mock
+            ->expects($this->once())
+            ->method('__invoke')
+            ->with($this->identicalTo($exception));
+
+        $adapter->reject($exception);
+        $adapter->promise()
+            ->always(function () {
+                return \React\Promise\resolve(1);
+            })
+            ->then(null, $mock);
+    }
+
+    /** @test */
+    public function alwaysShouldRejectWhenHandlerThrowsForRejectedPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $exception1 = new \Exception();
+        $exception2 = new \Exception();
+
+        $mock = $this->createCallableMock();
+        $mock
+            ->expects($this->once())
+            ->method('__invoke')
+            ->with($this->identicalTo($exception2));
+
+        $adapter->reject($exception1);
+        $adapter->promise()
+            ->always(function () use ($exception2) {
+                throw $exception2;
+            })
+            ->then(null, $mock);
+    }
+
+    /** @test */
+    public function alwaysShouldRejectWhenHandlerRejectsForRejectedPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $exception1 = new \Exception();
+        $exception2 = new \Exception();
+
+        $mock = $this->createCallableMock();
+        $mock
+            ->expects($this->once())
+            ->method('__invoke')
+            ->with($this->identicalTo($exception2));
+
+        $adapter->reject($exception1);
+        $adapter->promise()
+            ->always(function () use ($exception2) {
+                return \React\Promise\reject($exception2);
+            })
+            ->then(null, $mock);
+    }
+
     /** @test */
     public function cancelShouldReturnNullForRejectedPromise()
     {
diff --git a/core/vendor/react/promise/tests/PromiseTest/PromiseSettledTestTrait.php b/core/vendor/react/promise/tests/PromiseTest/PromiseSettledTestTrait.php
index c56028471bbc..e363b6d91c41 100644
--- a/core/vendor/react/promise/tests/PromiseTest/PromiseSettledTestTrait.php
+++ b/core/vendor/react/promise/tests/PromiseTest/PromiseSettledTestTrait.php
@@ -46,4 +46,41 @@ public function cancelShouldHaveNoEffectForSettledPromise()
 
         $adapter->promise()->cancel();
     }
+
+    /** @test */
+    public function doneShouldReturnNullForSettledPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $adapter->settle();
+        $this->assertNull($adapter->promise()->done(null, function () {}));
+    }
+
+    /** @test */
+    public function doneShouldReturnAllowNullForSettledPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $adapter->settle();
+        $this->assertNull($adapter->promise()->done(null, function () {}, null));
+    }
+
+    /** @test */
+    public function progressShouldNotInvokeProgressHandlerForSettledPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $adapter->settle();
+        $adapter->promise()->progress($this->expectCallableNever());
+        $adapter->notify();
+    }
+
+    /** @test */
+    public function alwaysShouldReturnAPromiseForSettledPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $adapter->settle();
+        $this->assertInstanceOf('React\\Promise\\PromiseInterface', $adapter->promise()->always(function () {}));
+    }
 }
diff --git a/core/vendor/react/promise/tests/PromiseTest/RejectTestTrait.php b/core/vendor/react/promise/tests/PromiseTest/RejectTestTrait.php
index 66e5e734ef7c..7d6f65fd0ae3 100644
--- a/core/vendor/react/promise/tests/PromiseTest/RejectTestTrait.php
+++ b/core/vendor/react/promise/tests/PromiseTest/RejectTestTrait.php
@@ -3,6 +3,7 @@
 namespace React\Promise\PromiseTest;
 
 use React\Promise;
+use React\Promise\Deferred;
 
 trait RejectTestTrait
 {
@@ -105,4 +106,258 @@ public function rejectShouldMakePromiseImmutable()
         $adapter->reject(1);
         $adapter->reject(2);
     }
+
+    /** @test */
+    public function notifyShouldInvokeOtherwiseHandler()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $mock = $this->createCallableMock();
+        $mock
+            ->expects($this->once())
+            ->method('__invoke')
+            ->with($this->identicalTo(1));
+
+        $adapter->promise()
+            ->otherwise($mock);
+
+        $adapter->reject(1);
+    }
+
+    /** @test */
+    public function doneShouldInvokeRejectionHandler()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $mock = $this->createCallableMock();
+        $mock
+            ->expects($this->once())
+            ->method('__invoke')
+            ->with($this->identicalTo(1));
+
+        $this->assertNull($adapter->promise()->done(null, $mock));
+        $adapter->reject(1);
+    }
+
+    /** @test */
+    public function doneShouldThrowExceptionThrownByRejectionHandler()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $this->setExpectedException('\Exception', 'UnhandledRejectionException');
+
+        $this->assertNull($adapter->promise()->done(null, function () {
+            throw new \Exception('UnhandledRejectionException');
+        }));
+        $adapter->reject(1);
+    }
+
+    /** @test */
+    public function doneShouldThrowUnhandledRejectionExceptionWhenRejectedWithNonException()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $this->setExpectedException('React\\Promise\\UnhandledRejectionException');
+
+        $this->assertNull($adapter->promise()->done());
+        $adapter->reject(1);
+    }
+
+    /** @test */
+    public function doneShouldThrowUnhandledRejectionExceptionWhenRejectionHandlerRejects()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $this->setExpectedException('React\\Promise\\UnhandledRejectionException');
+
+        $this->assertNull($adapter->promise()->done(null, function () {
+            return \React\Promise\reject();
+        }));
+        $adapter->reject(1);
+    }
+
+    /** @test */
+    public function doneShouldThrowRejectionExceptionWhenRejectionHandlerRejectsWithException()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $this->setExpectedException('\Exception', 'UnhandledRejectionException');
+
+        $this->assertNull($adapter->promise()->done(null, function () {
+            return \React\Promise\reject(new \Exception('UnhandledRejectionException'));
+        }));
+        $adapter->reject(1);
+    }
+
+    /** @test */
+    public function doneShouldThrowUnhandledRejectionExceptionWhenRejectionHandlerRetunsPendingPromiseWhichRejectsLater()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $this->setExpectedException('React\\Promise\\UnhandledRejectionException');
+
+        $d = new Deferred();
+        $promise = $d->promise();
+
+        $this->assertNull($adapter->promise()->done(null, function () use ($promise) {
+            return $promise;
+        }));
+        $adapter->reject(1);
+        $d->reject(1);
+    }
+
+    /** @test */
+    public function doneShouldThrowExceptionProvidedAsRejectionValue()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $this->setExpectedException('\Exception', 'UnhandledRejectionException');
+
+        $this->assertNull($adapter->promise()->done());
+        $adapter->reject(new \Exception('UnhandledRejectionException'));
+    }
+
+    /** @test */
+    public function doneShouldThrowWithDeepNestingPromiseChains()
+    {
+        $this->setExpectedException('\Exception', 'UnhandledRejectionException');
+
+        $exception = new \Exception('UnhandledRejectionException');
+
+        $d = new Deferred();
+
+        $result = \React\Promise\resolve(\React\Promise\resolve($d->promise()->then(function () use ($exception) {
+            $d = new Deferred();
+            $d->resolve();
+
+            return \React\Promise\resolve($d->promise()->then(function () {}))->then(
+                function () use ($exception) {
+                    throw $exception;
+                }
+            );
+        })));
+
+        $result->done();
+
+        $d->resolve();
+    }
+
+    /** @test */
+    public function doneShouldRecoverWhenRejectionHandlerCatchesException()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $this->assertNull($adapter->promise()->done(null, function (\Exception $e) {
+
+        }));
+        $adapter->reject(new \Exception('UnhandledRejectionException'));
+    }
+
+    /** @test */
+    public function alwaysShouldNotSuppressRejection()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $exception = new \Exception();
+
+        $mock = $this->createCallableMock();
+        $mock
+            ->expects($this->once())
+            ->method('__invoke')
+            ->with($this->identicalTo($exception));
+
+        $adapter->promise()
+            ->always(function () {})
+            ->then(null, $mock);
+
+        $adapter->reject($exception);
+    }
+
+    /** @test */
+    public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsANonPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $exception = new \Exception();
+
+        $mock = $this->createCallableMock();
+        $mock
+            ->expects($this->once())
+            ->method('__invoke')
+            ->with($this->identicalTo($exception));
+
+        $adapter->promise()
+            ->always(function () {
+                return 1;
+            })
+            ->then(null, $mock);
+
+        $adapter->reject($exception);
+    }
+
+    /** @test */
+    public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsAPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $exception = new \Exception();
+
+        $mock = $this->createCallableMock();
+        $mock
+            ->expects($this->once())
+            ->method('__invoke')
+            ->with($this->identicalTo($exception));
+
+        $adapter->promise()
+            ->always(function () {
+                return \React\Promise\resolve(1);
+            })
+            ->then(null, $mock);
+
+        $adapter->reject($exception);
+    }
+
+    /** @test */
+    public function alwaysShouldRejectWhenHandlerThrowsForRejection()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $exception = new \Exception();
+
+        $mock = $this->createCallableMock();
+        $mock
+            ->expects($this->once())
+            ->method('__invoke')
+            ->with($this->identicalTo($exception));
+
+        $adapter->promise()
+            ->always(function () use ($exception) {
+                throw $exception;
+            })
+            ->then(null, $mock);
+
+        $adapter->reject($exception);
+    }
+
+    /** @test */
+    public function alwaysShouldRejectWhenHandlerRejectsForRejection()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $exception = new \Exception();
+
+        $mock = $this->createCallableMock();
+        $mock
+            ->expects($this->once())
+            ->method('__invoke')
+            ->with($this->identicalTo($exception));
+
+        $adapter->promise()
+            ->always(function () use ($exception) {
+                return \React\Promise\reject($exception);
+            })
+            ->then(null, $mock);
+
+        $adapter->reject($exception);
+    }
 }
diff --git a/core/vendor/react/promise/tests/PromiseTest/ResolveTestTrait.php b/core/vendor/react/promise/tests/PromiseTest/ResolveTestTrait.php
index 4ee201916142..b05f7fe84bbf 100644
--- a/core/vendor/react/promise/tests/PromiseTest/ResolveTestTrait.php
+++ b/core/vendor/react/promise/tests/PromiseTest/ResolveTestTrait.php
@@ -106,4 +106,153 @@ public function resolveShouldMakePromiseImmutable()
         $adapter->resolve(1);
         $adapter->resolve(2);
     }
+
+    /** @test */
+    public function doneShouldInvokeFulfillmentHandler()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $mock = $this->createCallableMock();
+        $mock
+            ->expects($this->once())
+            ->method('__invoke')
+            ->with($this->identicalTo(1));
+
+        $this->assertNull($adapter->promise()->done($mock));
+        $adapter->resolve(1);
+    }
+
+    /** @test */
+    public function doneShouldThrowExceptionThrownFulfillmentHandler()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $this->setExpectedException('\Exception', 'UnhandledRejectionException');
+
+        $this->assertNull($adapter->promise()->done(function () {
+            throw new \Exception('UnhandledRejectionException');
+        }));
+        $adapter->resolve(1);
+    }
+
+    /** @test */
+    public function doneShouldThrowUnhandledRejectionExceptionWhenFulfillmentHandlerRejects()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $this->setExpectedException('React\\Promise\\UnhandledRejectionException');
+
+        $this->assertNull($adapter->promise()->done(function () {
+            return \React\Promise\reject();
+        }));
+        $adapter->resolve(1);
+    }
+
+    /** @test */
+    public function alwaysShouldNotSuppressValue()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $value = new \stdClass();
+
+        $mock = $this->createCallableMock();
+        $mock
+            ->expects($this->once())
+            ->method('__invoke')
+            ->with($this->identicalTo($value));
+
+        $adapter->promise()
+            ->always(function () {})
+            ->then($mock);
+
+        $adapter->resolve($value);
+    }
+
+    /** @test */
+    public function alwaysShouldNotSuppressValueWhenHandlerReturnsANonPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $value = new \stdClass();
+
+        $mock = $this->createCallableMock();
+        $mock
+            ->expects($this->once())
+            ->method('__invoke')
+            ->with($this->identicalTo($value));
+
+        $adapter->promise()
+            ->always(function () {
+                return 1;
+            })
+            ->then($mock);
+
+        $adapter->resolve($value);
+    }
+
+    /** @test */
+    public function alwaysShouldNotSuppressValueWhenHandlerReturnsAPromise()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $value = new \stdClass();
+
+        $mock = $this->createCallableMock();
+        $mock
+            ->expects($this->once())
+            ->method('__invoke')
+            ->with($this->identicalTo($value));
+
+        $adapter->promise()
+            ->always(function () {
+                return \React\Promise\resolve(1);
+            })
+            ->then($mock);
+
+        $adapter->resolve($value);
+    }
+
+    /** @test */
+    public function alwaysShouldRejectWhenHandlerThrowsForFulfillment()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $exception = new \Exception();
+
+        $mock = $this->createCallableMock();
+        $mock
+            ->expects($this->once())
+            ->method('__invoke')
+            ->with($this->identicalTo($exception));
+
+        $adapter->promise()
+            ->always(function () use ($exception) {
+                throw $exception;
+            })
+            ->then(null, $mock);
+
+        $adapter->resolve(1);
+    }
+
+    /** @test */
+    public function alwaysShouldRejectWhenHandlerRejectsForFulfillment()
+    {
+        $adapter = $this->getPromiseTestAdapter();
+
+        $exception = new \Exception();
+
+        $mock = $this->createCallableMock();
+        $mock
+            ->expects($this->once())
+            ->method('__invoke')
+            ->with($this->identicalTo($exception));
+
+        $adapter->promise()
+            ->always(function () use ($exception) {
+                return \React\Promise\reject($exception);
+            })
+            ->then(null, $mock);
+
+        $adapter->resolve(1);
+    }
 }
diff --git a/core/vendor/react/promise/tests/RejectedPromiseTest.php b/core/vendor/react/promise/tests/RejectedPromiseTest.php
index 040dd2e2cc2e..c886b0095420 100644
--- a/core/vendor/react/promise/tests/RejectedPromiseTest.php
+++ b/core/vendor/react/promise/tests/RejectedPromiseTest.php
@@ -29,8 +29,8 @@ public function getPromiseTestAdapter(callable $canceller = null)
                     $promise = new RejectedPromise($reason);
                 }
             },
-            'progress' => function () {
-                throw new \LogicException('You cannot call progress() for React\Promise\RejectedPromise');
+            'notify' => function () {
+                // no-op
             },
             'settle' => function ($reason = null) use (&$promise) {
                 if (!$promise) {
-- 
GitLab