Issue #2442411 by jhedstrom: Update react/promise to 2.2.0
parent
0b5587bf86
commit
6743175a3f
|
@ -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",
|
||||
|
|
|
@ -6,6 +6,6 @@ $vendorDir = dirname(dirname(__FILE__));
|
|||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
$vendorDir . '/react/promise/src/functions.php',
|
||||
$vendorDir . '/react/promise/src/functions_include.php',
|
||||
$baseDir . '/lib/Drupal.php',
|
||||
);
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
-------
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
"psr-4": {
|
||||
"React\\Promise\\": "src/"
|
||||
},
|
||||
"files": ["src/functions.php"]
|
||||
"files": ["src/functions_include.php"]
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
|
|
@ -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 @@ class Deferred implements PromisorInterface
|
|||
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 @@ class Deferred implements PromisorInterface
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace React\Promise;
|
||||
|
||||
class FulfilledPromise implements CancellablePromiseInterface
|
||||
class FulfilledPromise implements ExtendedPromiseInterface, CancellablePromiseInterface
|
||||
{
|
||||
private $value;
|
||||
|
||||
|
@ -30,6 +30,38 @@ class FulfilledPromise implements CancellablePromiseInterface
|
|||
}
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace React\Promise;
|
||||
|
||||
class LazyPromise implements CancellablePromiseInterface
|
||||
class LazyPromise implements ExtendedPromiseInterface, CancellablePromiseInterface
|
||||
{
|
||||
private $factory;
|
||||
private $promise;
|
||||
|
@ -17,6 +17,27 @@ class LazyPromise implements CancellablePromiseInterface
|
|||
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();
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace React\Promise;
|
||||
|
||||
class Promise implements CancellablePromiseInterface
|
||||
class Promise implements ExtendedPromiseInterface, CancellablePromiseInterface
|
||||
{
|
||||
private $canceller;
|
||||
private $result;
|
||||
|
@ -40,6 +40,51 @@ class Promise implements CancellablePromiseInterface
|
|||
});
|
||||
}
|
||||
|
||||
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 @@ class Promise implements CancellablePromiseInterface
|
|||
|
||||
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 @@ class Promise implements CancellablePromiseInterface
|
|||
$this->settle(reject($reason));
|
||||
}
|
||||
|
||||
private function progress($update = null)
|
||||
private function notify($update = null)
|
||||
{
|
||||
if (null !== $this->result) {
|
||||
return;
|
||||
|
@ -103,8 +148,10 @@ class Promise implements CancellablePromiseInterface
|
|||
}
|
||||
}
|
||||
|
||||
private function settle(PromiseInterface $result)
|
||||
private function settle(ExtendedPromiseInterface $promise)
|
||||
{
|
||||
$result = $promise;
|
||||
|
||||
foreach ($this->handlers as $handler) {
|
||||
$handler($result);
|
||||
}
|
||||
|
@ -125,7 +172,7 @@ class Promise implements CancellablePromiseInterface
|
|||
$this->reject($reason);
|
||||
},
|
||||
function ($update = null) {
|
||||
$this->progress($update);
|
||||
$this->notify($update);
|
||||
}
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace React\Promise;
|
||||
|
||||
class RejectedPromise implements CancellablePromiseInterface
|
||||
class RejectedPromise implements ExtendedPromiseInterface, CancellablePromiseInterface
|
||||
{
|
||||
private $reason;
|
||||
|
||||
|
@ -28,6 +28,46 @@ class RejectedPromise implements CancellablePromiseInterface
|
|||
}
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -4,17 +4,23 @@ namespace React\Promise;
|
|||
|
||||
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 map($promisesOrValues, callable $mapFunc)
|
|||
}
|
||||
},
|
||||
$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);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
if (!function_exists('React\Promise\resolve')) {
|
||||
require __DIR__.'/functions.php';
|
||||
}
|
|
@ -13,11 +13,30 @@ class DeferredTest extends TestCase
|
|||
$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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,8 +29,8 @@ class FulfilledPromiseTest extends TestCase
|
|||
'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) {
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -91,4 +91,12 @@ class FunctionResolveTest extends TestCase
|
|||
|
||||
$result->then($mock);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function returnsExtendePromiseForSimplePromise()
|
||||
{
|
||||
$promise = $this->getMock('React\Promise\PromiseInterface');
|
||||
|
||||
$this->assertInstanceOf('React\Promise\ExtendedPromiseInterface', resolve($promise));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,10 +20,10 @@ class LazyPromiseTest extends TestCase
|
|||
'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'],
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
@ -28,9 +28,9 @@ class CallbackPromiseAdapter implements PromiseAdapterInterface
|
|||
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()
|
||||
|
|
|
@ -9,6 +9,6 @@ interface PromiseAdapterInterface
|
|||
public function promise();
|
||||
public function resolve();
|
||||
public function reject();
|
||||
public function progress();
|
||||
public function notify();
|
||||
public function settle();
|
||||
}
|
||||
|
|
|
@ -22,10 +22,10 @@ class PromiseTest extends TestCase
|
|||
'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 @@ class PromiseTest extends TestCase
|
|||
$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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,6 @@ trait FullTestTrait
|
|||
PromiseRejectedTestTrait,
|
||||
ResolveTestTrait,
|
||||
RejectTestTrait,
|
||||
ProgressTestTrait,
|
||||
NotifyTestTrait,
|
||||
CancelTestTrait;
|
||||
}
|
||||
|
|
|
@ -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 @@ trait ProgressTestTrait
|
|||
$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 @@ trait ProgressTestTrait
|
|||
$mock2
|
||||
);
|
||||
|
||||
$adapter->progress($sentinel);
|
||||
$adapter->notify($sentinel);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function progressShouldPropagateTransformedProgressToDownstreamPromises()
|
||||
public function notifyShouldPropagateTransformedProgressToDownstreamPromises()
|
||||
{
|
||||
$adapter = $this->getPromiseTestAdapter();
|
||||
|
||||
|
@ -93,11 +93,11 @@ trait ProgressTestTrait
|
|||
$mock2
|
||||
);
|
||||
|
||||
$adapter->progress(1);
|
||||
$adapter->notify(1);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function progressShouldPropagateCaughtExceptionValueAsProgress()
|
||||
public function notifyShouldPropagateCaughtExceptionValueAsProgress()
|
||||
{
|
||||
$adapter = $this->getPromiseTestAdapter();
|
||||
|
||||
|
@ -127,11 +127,11 @@ trait ProgressTestTrait
|
|||
$mock2
|
||||
);
|
||||
|
||||
$adapter->progress(1);
|
||||
$adapter->notify(1);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function progressShouldForwardProgressEventsWhenIntermediaryCallbackTiedToAResolvedPromiseReturnsAPromise()
|
||||
public function notifyShouldForwardProgressEventsWhenIntermediaryCallbackTiedToAResolvedPromiseReturnsAPromise()
|
||||
{
|
||||
$adapter = $this->getPromiseTestAdapter();
|
||||
$adapter2 = $this->getPromiseTestAdapter();
|
||||
|
@ -159,11 +159,11 @@ trait ProgressTestTrait
|
|||
$mock
|
||||
);
|
||||
|
||||
$adapter2->progress($sentinel);
|
||||
$adapter2->notify($sentinel);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function progressShouldForwardProgressEventsWhenIntermediaryCallbackTiedToAnUnresolvedPromiseReturnsAPromise()
|
||||
public function notifyShouldForwardProgressEventsWhenIntermediaryCallbackTiedToAnUnresolvedPromiseReturnsAPromise()
|
||||
{
|
||||
$adapter = $this->getPromiseTestAdapter();
|
||||
$adapter2 = $this->getPromiseTestAdapter();
|
||||
|
@ -190,11 +190,11 @@ trait ProgressTestTrait
|
|||
|
||||
// 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 @@ trait ProgressTestTrait
|
|||
);
|
||||
|
||||
$adapter->resolve($adapter2->promise());
|
||||
$adapter2->progress($sentinel);
|
||||
$adapter2->notify($sentinel);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function progressShouldAllowResolveAfterProgress()
|
||||
public function notifyShouldAllowResolveAfterProgress()
|
||||
{
|
||||
$adapter = $this->getPromiseTestAdapter();
|
||||
|
||||
|
@ -251,12 +251,12 @@ trait ProgressTestTrait
|
|||
$mock
|
||||
);
|
||||
|
||||
$adapter->progress(1);
|
||||
$adapter->notify(1);
|
||||
$adapter->resolve(2);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function progressShouldAllowRejectAfterProgress()
|
||||
public function notifyShouldAllowRejectAfterProgress()
|
||||
{
|
||||
$adapter = $this->getPromiseTestAdapter();
|
||||
|
||||
|
@ -277,17 +277,60 @@ trait ProgressTestTrait
|
|||
$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);
|
||||
}
|
||||
}
|
|
@ -195,4 +195,157 @@ trait PromiseFulfilledTestTrait
|
|||
|
||||
$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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,4 +32,37 @@ trait PromisePendingTestTrait
|
|||
|
||||
$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 () {}));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace React\Promise\PromiseTest;
|
||||
|
||||
use React\Promise\Deferred;
|
||||
|
||||
trait PromiseRejectedTestTrait
|
||||
{
|
||||
/**
|
||||
|
@ -181,6 +183,293 @@ trait PromiseRejectedTestTrait
|
|||
);
|
||||
}
|
||||
|
||||
/** @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()
|
||||
{
|
||||
|
|
|
@ -46,4 +46,41 @@ trait PromiseSettledTestTrait
|
|||
|
||||
$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 () {}));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace React\Promise\PromiseTest;
|
||||
|
||||
use React\Promise;
|
||||
use React\Promise\Deferred;
|
||||
|
||||
trait RejectTestTrait
|
||||
{
|
||||
|
@ -105,4 +106,258 @@ trait RejectTestTrait
|
|||
$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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -106,4 +106,153 @@ trait ResolveTestTrait
|
|||
$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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,8 +29,8 @@ class RejectedPromiseTest extends TestCase
|
|||
$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) {
|
||||
|
|
Loading…
Reference in New Issue