Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/seregazhuk/php-react-promise-testing

PHPUnit assertions for testing ReactPHP promises
https://github.com/seregazhuk/php-react-promise-testing

async php phpunit promises reactphp

Last synced: 24 days ago
JSON representation

PHPUnit assertions for testing ReactPHP promises

Awesome Lists containing this project

README

        

# ReactPHP Promises Testing
A library that provides a set of convenient assertions for testing ReactPHP promises.
Under the hood uses [clue/php-block-react](https://github.com/clue/php-block-react) to block promises.

[![Build Status](https://travis-ci.org/seregazhuk/php-react-promise-testing.svg?branch=master)](https://travis-ci.org/seregazhuk/php-react-promise-testing)
[![Maintainability](https://api.codeclimate.com/v1/badges/689230cdae09d2e32600/maintainability)](https://codeclimate.com/github/seregazhuk/php-react-promise-testing/maintainability)
[![Test Coverage](https://api.codeclimate.com/v1/badges/689230cdae09d2e32600/test_coverage)](https://codeclimate.com/github/seregazhuk/php-react-promise-testing/test_coverage)
[![Total Downloads](https://poser.pugx.org/seregazhuk/react-promise-testing/downloads)](//packagist.org/packages/seregazhuk/react-promise-testing)

When testing asynchronous code and promises things can be a bit tricky. This library provides a set of convenient
assertions for testing ReactPHP promises.

**Table of Contents**
- [Installation](#installation)
- [Quick Start](#quick-start)
- [Assertions](#assertions)
- [assertPromiseFulfills()](#assertpromisefulfills)
- [assertPromiseFulfillsWith()](#assertpromisefulfillswith)
- [assertPromiseFulfillsWithInstanceOf()](#assertpromisefulfillswithinstanceof)
- [assertPromiseRejects()](#assertpromiserejects())
- [assertPromiseRejectsWith()](#assertpromiserejectswith)
- [assertTrueAboutPromise()](#asserttrueaboutpromise)
- [assertFalseAboutPromise()](#assertfalseaboutpromise)

- [Helpers](#helpers)
- [waitForPromiseToFulfill()](#waitforpromisetofulfill)
- [waitForPromise()](#waitforpromise)

## Installation

### Dependencies
Library requires PHP 8.0 or above.

The recommended way to install this library is via [Composer](https://getcomposer.org).
[New to Composer?](https://getcomposer.org/doc/00-intro.md)

See also the [CHANGELOG](CHANGELOG.md) for details about version upgrades.

```
composer require seregazhuk/react-promise-testing --dev
```

## Quick Start
Use the trait `seregazhuk\React\PromiseTesting\AssertsPromise` or extend your
test classes from `seregazhuk\React\PromiseTesting\TestCase` class,
which itself extends PHPUnit `TestCase`.

```php
final class MyTest extends TestCase
{
/** @test */
public function promise_fulfills_with_a_response_object()
{
$browser = new Clue\React\Buzz\Browser($this->eventLoop());
$promise = $browser->get('http://www.google.com/');
$this->assertPromiseFulfillsWithInstanceOf($promise, ResponseInterface::class);
}
}
```

Using the trait:

```php

use PHPUnit\Framework\TestCase;
use seregazhuk\React\PromiseTesting\AssertsPromise;

final class MyTest extends TestCase
{
use AssertsPromise;

/** @test */
public function promise_fulfills_with_a_response_object()
{
$browser = new Clue\React\Buzz\Browser($this->eventLoop());
$promise = $browser->get('http://www.google.com/');
$this->assertPromiseFulfillsWithInstanceOf($promise, ResponseInterface::class);
}
}
```

Test above checks that a specified promise fulfills with an instance of `ResponseInterface`.

## Event loop

To make promise assertions we need to run the loop. Before each test a new instance of the event loop
is being created (inside `setUp()` method). If you need the loop to build your dependencies you **should**
use `eventLoop()` method to retrieve it.

## Assertions

### assertPromiseFulfills()

`public function assertPromiseFulfills(PromiseInterface $promise, int $timeout = null): void`

The test fails if the `$promise` rejects.

You can specify `$timeout` in seconds to wait for promise to be resolved.
If the promise was not fulfilled in specified timeout the test fails. When not specified, timeout is set to 2 seconds.

```php
final class PromiseFulfillsTest extends TestCase
{
/** @test */
public function promise_fulfills(): void
{
$deferred = new Deferred();
$deferred->reject();
$this->assertPromiseFulfills($deferred->promise(), 1);
}
}
```

```bash
PHPUnit 8.5.2 by Sebastian Bergmann and contributors.

F 1 / 1 (100%)

Time: 189 ms, Memory: 4.00MB

There was 1 failure:

1) seregazhuk\React\PromiseTesting\tests\PromiseFulfillTest::promise_fulfills
Failed asserting that promise fulfills. Promise was rejected.
```

### assertPromiseFulfillsWith()

`assertPromiseFulfillsWith(PromiseInterface $promise, $value, int $timeout = null): void`

The test fails if the `$promise` doesn't fulfills with a specified `$value`.

You can specify `$timeout` in seconds to wait for promise to be fulfilled.
If the promise was not fulfilled in specified timeout the test fails.
When not specified, timeout is set to 2 seconds.

```php
final class PromiseFulfillsWithTest extends TestCase
{
/** @test */
public function promise_fulfills_with_a_specified_value(): void
{
$deferred = new Deferred();
$deferred->resolve(1234);
$this->assertPromiseFulfillsWith($deferred->promise(), 1);
}
}
```

```bash
PHPUnit 8.5.2 by Sebastian Bergmann and contributors.

F 1 / 1 (100%)

Time: 180 ms, Memory: 4.00MB

There was 1 failure:

1) seregazhuk\React\PromiseTesting\tests\PromiseFulfillsWithTest::promise_fulfills_with_a_specified_value
Failed asserting that promise fulfills with a specified value.
Failed asserting that 1234 matches expected 1.
```

### assertPromiseFulfillsWithInstanceOf()

`assertPromiseFulfillsWithInstanceOf(PromiseInterface $promise, string $class, int $timeout = null): void`

The test fails if the `$promise` doesn't fulfills with an instance of specified `$class`.

You can specify `$timeout` in seconds to wait for promise to be fulfilled.
If the promise was not fulfilled in specified timeout the test fails.
When not specified, timeout is set to 2 seconds.

```php
final class PromiseFulfillsWithInstanceOfTest extends TestCase
{
/** @test */
public function promise_fulfills_with_an_instance_of_class(): void
{
$deferred = new Deferred();
$deferred->resolve(new MyClass);
$this->assertPromiseFulfillsWithInstanceOf($deferred->promise(), MyClass::class);
}
}
```

```bash
PHPUnit 8.5.2 by Sebastian Bergmann and contributors.

F 1 / 1 (100%)

Time: 180 ms, Memory: 4.00MB

There was 1 failure:

1) seregazhuk\React\PromiseTesting\tests\PromiseFulfillsWithWithInstanceOfTest::promise_fulfills_with_an_instance_of_class
Failed asserting that promise fulfills with a value of class MyClass.
```

### assertPromiseRejects()
`assertPromiseRejects(PromiseInterface $promise, int $timeout = null): void`

The test fails if the `$promise` fulfills.

You can specify `$timeout` in seconds to wait for promise to be resolved.
If the promise was not fulfilled in specified timeout, it rejects with `React\Promise\Timer\TimeoutException`.
When not specified, timeout is set to 2 seconds.

```php
final class PromiseRejectsTest extends TestCase
{
/** @test */
public function promise_rejects(): void
{
$deferred = new Deferred();
$deferred->resolve();
$this->assertPromiseRejects($deferred->promise());
}
}
```

```bash
PHPUnit 8.5.2 by Sebastian Bergmann and contributors.

F 1 / 1 (100%)

Time: 175 ms, Memory: 4.00MB

There was 1 failure:

1) seregazhuk\React\PromiseTesting\tests\PromiseRejectsTest::promise_rejects
Failed asserting that promise rejects. Promise was fulfilled.
```

### assertPromiseRejectsWith()
`assertPromiseRejectsWith(PromiseInterface $promise, string $reasonExceptionClass, int $timeout = null): void`

The test fails if the `$promise` doesn't reject with a specified exception class.

You can specify `$timeout` in seconds to wait for promise to be resolved.
If the promise was not fulfilled in specified timeout, it rejects with `React\Promise\Timer\TimeoutException`.
When not specified, timeout is set to 2 seconds.

```php
final class PromiseRejectsWithTest extends TestCase
{
/** @test */
public function promise_rejects_with_a_specified_reason(): void
{
$deferred = new Deferred();
$deferred->reject(new \LogicException());
$this->assertPromiseRejectsWith($deferred->promise(), \InvalidArgumentException::class);
}
}
```

```bash
PHPUnit 8.5.2 by Sebastian Bergmann and contributors.

F 1 / 1 (100%)

Time: 136 ms, Memory: 4.00MB

There was 1 failure:

1) seregazhuk\React\PromiseTesting\tests\PromiseRejectsWithTest::promise_rejects_with_a_specified_reason
Failed asserting that promise rejects with a specified reason.
Failed asserting that LogicException Object (...) is an instance of class "InvalidArgumentException".
```

### assertTrueAboutPromise()
`assertTrueAboutPromise(PromiseInterface $promise, callable $predicate, int $timeout = null): void`

The test fails if the value encapsulated in the Promise does not conform to an arbitrary predicate.

You can specify `$timeout` in seconds to wait for promise to be resolved.
If the promise was not fulfilled in specified timeout, it rejects with `React\Promise\Timer\TimeoutException`.
When not specified, timeout is set to 2 seconds.

```php
final class AssertTrueAboutPromiseTest extends TestCase
{
/** @test */
public function promise_encapsulates_integer(): void
{
$deferred = new Deferred();
$deferred->resolve(23);

$this->assertTrueAboutPromise($deferred->promise(), function ($val) {
return is_object($val);
});
}
}
```

```bash
PHPUnit 8.5.2 by Sebastian Bergmann and contributors.

F 1 / 1 (100%)

Time: 136 ms, Memory: 4.00MB

There was 1 failure:

1) seregazhuk\React\PromiseTesting\tests\AssertTrueAboutPromiseTest::promise_encapsulates_integer
Failed asserting that false is true.
```

### assertFalseAboutPromise()
`assertFalseAboutPromise(PromiseInterface $promise, callable $predicate, int $timeout = null): void`

The test fails if the value encapsulated in the Promise conforms to an arbitrary predicate.

You can specify `$timeout` in seconds to wait for promise to be resolved.
If the promise was not fulfilled in specified timeout, it rejects with `React\Promise\Timer\TimeoutException`.
When not specified, timeout is set to 2 seconds.

```php
final class AssertFalseAboutPromiseTest extends TestCase
{
/** @test */
public function promise_encapsulates_object(): void
{
$deferred = new Deferred();
$deferred->resolve(23);

$this->assertFalseAboutPromise($deferred->promise(), function ($val) {
return is_int($val);
});
}
}
```

```bash
PHPUnit 8.5.2 by Sebastian Bergmann and contributors.

F 1 / 1 (100%)

Time: 136 ms, Memory: 4.00MB

There was 1 failure:

1) seregazhuk\React\PromiseTesting\tests\AssertFalseAboutPromiseTest::promise_encapsulates_object
Failed asserting that true is false.
```

## Helpers

### waitForPromiseToFulfill()
`function waitForPromiseToFulfill(PromiseInterface $promise, int $timeout = null)`.

This helper can be used when you want to resolve a promise and get the resolution value.

Tries to resolve a `$promise` in a specified `$timeout` seconds and returns resolved value. If `$timeout` is not
set uses 2 seconds by default. The test fails if the `$promise` doesn't fulfill.

```php
final class WaitForPromiseToFulfillTest extends TestCase
{
/** @test */
public function promise_fulfills(): void
{
$deferred = new Deferred();

$deferred->reject(new \Exception());
$value = $this->waitForPromiseToFulfill($deferred->promise());
}
}
```

```bash
PHPUnit 8.5.2 by Sebastian Bergmann and contributors.

F 1 / 1 (100%)

Time: 223 ms, Memory: 6.00MB

There was 1 failure:

1) seregazhuk\React\PromiseTesting\tests\WaitForPromiseToFulfillTest::promise_fulfills
Failed to fulfill a promise. It was rejected with Exception.
```

### waitForPromise()
`function waitForPromise(PromiseInterface $promise, int $timeout = null)`.

Tries to resolve a specified `$promise` in a specified `$timeout` seconds. If `$timeout` is not set uses 2
seconds by default. If the promise fulfills returns a resolution value, otherwise throws an exception. If the
promise rejects throws the rejection reason, if the promise doesn't fulfill in a specified `$timeout` throws
`React\Promise\Timer\TimeoutException`.

This helper can be useful when you need to get the value from the fulfilled promise in a synchronous way:

```php
$value = $this->waitForPromise($cache->get('key'));
```