mirror of
https://github.com/pestphp/pest.git
synced 2026-03-10 17:57:23 +01:00
Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ba06c5a76d | |||
| 78ffc491e9 | |||
| 7f38de11b7 | |||
| a6e34d204c | |||
| 66d47e4922 | |||
| 7d70b6e95a | |||
| 076dcab4c5 | |||
| 6f42e336c9 | |||
| 0d72b5197c | |||
| 7691e3c602 | |||
| b43a59868d | |||
| 457972716f | |||
| ae029660e3 | |||
| dc12419078 | |||
| f0ddd10a54 | |||
| 4daf7ee4ab | |||
| d60f320382 | |||
| 3c3e6b160b | |||
| c99f8f196e | |||
| 9cc4ecd5ab | |||
| 8d96f975e0 | |||
| 7f214f9e12 | |||
| da258fa89f | |||
| f23f857903 | |||
| fec11928cf | |||
| f6131d042b | |||
| 543b9542ae | |||
| 1681c1f4f8 | |||
| f41c3ce9ba | |||
| 847b06e558 | |||
| 601c4b01fc | |||
| 05c1c82ae2 | |||
| 1bde49b3c4 | |||
| b22f5e0c85 | |||
| dd643faa5c | |||
| facbf05016 | |||
| 0b19672963 | |||
| a16a19e121 | |||
| 3dd10b3c7c | |||
| 12e63c7376 | |||
| 1d4c1a5359 | |||
| 8e32b88fc8 | |||
| 1a7baad338 |
5
.github/workflows/tests.yml
vendored
5
.github/workflows/tests.yml
vendored
@ -11,6 +11,11 @@ jobs:
|
|||||||
php: ['7.3', '7.4', '8.0', '8.1']
|
php: ['7.3', '7.4', '8.0', '8.1']
|
||||||
dependency-version: [prefer-lowest, prefer-stable]
|
dependency-version: [prefer-lowest, prefer-stable]
|
||||||
parallel: ['', '--parallel']
|
parallel: ['', '--parallel']
|
||||||
|
exclude:
|
||||||
|
- php: 8.1
|
||||||
|
os: macos-latest
|
||||||
|
- php: 8.1
|
||||||
|
os: windows-latest
|
||||||
|
|
||||||
name: PHP ${{ matrix.php }} - ${{ matrix.os }} - ${{ matrix.dependency-version }} - ${{ matrix.parallel }}
|
name: PHP ${{ matrix.php }} - ${{ matrix.os }} - ${{ matrix.dependency-version }} - ${{ matrix.parallel }}
|
||||||
|
|
||||||
|
|||||||
12
CHANGELOG.md
12
CHANGELOG.md
@ -4,9 +4,21 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
|
## [v1.20.0 (2021-09-25)](https://github.com/pestphp/pest/compare/v1.19.0...v1.20.0)
|
||||||
|
### Added
|
||||||
|
- `throwsIf` test call ([#371](https://github.com/pestphp/pest/pull/371))
|
||||||
|
- `--ci` CLI option to ignore development options like `->local()` ([#405](https://github.com/pestphp/pest/pull/405))
|
||||||
|
- `when` conditional expectation ([#406](https://github.com/pestphp/pest/pull/406))
|
||||||
|
- `unless` conditional expectation ([b43a598](https://github.com/pestphp/pest/commit/b43a59868d5b790a28cbb29c6110c9f068b0b812))
|
||||||
|
- `match` conditional expectation ([#407](https://github.com/pestphp/pest/pull/407))
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- `sequence` with more expectations than iterable elements ([#399](https://github.com/pestphp/pest/pull/399))
|
||||||
|
|
||||||
## [v1.19.0 (2021-09-20)](https://github.com/pestphp/pest/compare/v1.18.0...v1.19.0)
|
## [v1.19.0 (2021-09-20)](https://github.com/pestphp/pest/compare/v1.18.0...v1.19.0)
|
||||||
### Added
|
### Added
|
||||||
- PHP 8.1 support ([e6c7d68](https://github.com/pestphp/pest/commit/e6c7d68defaec8efe01e71e15dd8d8c45b0cf60f))
|
- PHP 8.1 support ([e6c7d68](https://github.com/pestphp/pest/commit/e6c7d68defaec8efe01e71e15dd8d8c45b0cf60f))
|
||||||
|
- `toHaveProperties` expectation ([#391](https://github.com/pestphp/pest/pull/391))
|
||||||
|
|
||||||
## [v1.18.0 (2021-08-30)](https://github.com/pestphp/pest/compare/v1.17.0...v1.18.0)
|
## [v1.18.0 (2021-08-30)](https://github.com/pestphp/pest/compare/v1.17.0...v1.18.0)
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@ -79,7 +79,8 @@
|
|||||||
"plugins": [
|
"plugins": [
|
||||||
"Pest\\Plugins\\Coverage",
|
"Pest\\Plugins\\Coverage",
|
||||||
"Pest\\Plugins\\Init",
|
"Pest\\Plugins\\Init",
|
||||||
"Pest\\Plugins\\Version"
|
"Pest\\Plugins\\Version",
|
||||||
|
"Pest\\Plugins\\Environment"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"laravel": {
|
"laravel": {
|
||||||
|
|||||||
@ -12,9 +12,6 @@ interface HandlesArguments
|
|||||||
/**
|
/**
|
||||||
* Allows to handle custom command line arguments.
|
* Allows to handle custom command line arguments.
|
||||||
*
|
*
|
||||||
* PLEASE NOTE: it is necessary to remove any custom argument from the array
|
|
||||||
* because otherwise the application will complain about them
|
|
||||||
*
|
|
||||||
* @param array<int, string> $arguments
|
* @param array<int, string> $arguments
|
||||||
*
|
*
|
||||||
* @return array<int, string> the updated list of arguments
|
* @return array<int, string> the updated list of arguments
|
||||||
|
|||||||
@ -154,9 +154,10 @@ final class Expectation
|
|||||||
throw new BadMethodCallException('Expectation value is not iterable.');
|
throw new BadMethodCallException('Expectation value is not iterable.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$value = is_array($this->value) ? $this->value : iterator_to_array($this->value);
|
$value = is_array($this->value) ? $this->value : iterator_to_array($this->value);
|
||||||
$keys = array_keys($value);
|
$keys = array_keys($value);
|
||||||
$values = array_values($value);
|
$values = array_values($value);
|
||||||
|
$callbacksCount = count($callbacks);
|
||||||
|
|
||||||
$index = 0;
|
$index = 0;
|
||||||
|
|
||||||
@ -165,6 +166,10 @@ final class Expectation
|
|||||||
$index = $index < count($values) - 1 ? $index + 1 : 0;
|
$index = $index < count($values) - 1 ? $index + 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($callbacksCount > count($values)) {
|
||||||
|
Assert::assertLessThanOrEqual(count($value), count($callbacks));
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($values as $key => $item) {
|
foreach ($values as $key => $item) {
|
||||||
if (is_callable($callbacks[$key])) {
|
if (is_callable($callbacks[$key])) {
|
||||||
call_user_func($callbacks[$key], new self($item), new self($keys[$key]));
|
call_user_func($callbacks[$key], new self($item), new self($keys[$key]));
|
||||||
@ -177,6 +182,88 @@ final class Expectation
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the subject matches one of the given "expressions", the expression callback will run.
|
||||||
|
*
|
||||||
|
* @template TMatchSubject of array-key
|
||||||
|
*
|
||||||
|
* @param callable(): TMatchSubject|TMatchSubject $subject
|
||||||
|
* @param array<TMatchSubject, (callable(Expectation<TValue>): mixed)|TValue> $expressions
|
||||||
|
*/
|
||||||
|
public function match($subject, array $expressions): Expectation
|
||||||
|
{
|
||||||
|
$subject = is_callable($subject)
|
||||||
|
? $subject
|
||||||
|
: function () use ($subject) {
|
||||||
|
return $subject;
|
||||||
|
};
|
||||||
|
|
||||||
|
$subject = $subject();
|
||||||
|
|
||||||
|
$matched = false;
|
||||||
|
|
||||||
|
foreach ($expressions as $key => $callback) {
|
||||||
|
if ($subject != $key) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$matched = true;
|
||||||
|
|
||||||
|
if (is_callable($callback)) {
|
||||||
|
$callback(new self($this->value));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->and($this->value)->toEqual($callback);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($matched === false) {
|
||||||
|
throw new ExpectationFailedException('Unhandled match value.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply the callback if the given "condition" is falsy.
|
||||||
|
*
|
||||||
|
* @param (callable(): bool)|bool $condition
|
||||||
|
* @param callable(Expectation<TValue>): mixed $callback
|
||||||
|
*/
|
||||||
|
public function unless($condition, callable $callback): Expectation
|
||||||
|
{
|
||||||
|
$condition = is_callable($condition)
|
||||||
|
? $condition
|
||||||
|
: static function () use ($condition): bool {
|
||||||
|
return (bool) $condition; // @phpstan-ignore-line
|
||||||
|
};
|
||||||
|
|
||||||
|
return $this->when(!$condition(), $callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply the callback if the given "condition" is truthy.
|
||||||
|
*
|
||||||
|
* @param (callable(): bool)|bool $condition
|
||||||
|
* @param callable(Expectation<TValue>): mixed $callback
|
||||||
|
*/
|
||||||
|
public function when($condition, callable $callback): Expectation
|
||||||
|
{
|
||||||
|
$condition = is_callable($condition)
|
||||||
|
? $condition
|
||||||
|
: static function () use ($condition): bool {
|
||||||
|
return (bool) $condition; // @phpstan-ignore-line
|
||||||
|
};
|
||||||
|
|
||||||
|
if ($condition()) {
|
||||||
|
$callback($this->and($this->value));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asserts that two variables have the same type and
|
* Asserts that two variables have the same type and
|
||||||
* value. Used on objects, it asserts that two
|
* value. Used on objects, it asserts that two
|
||||||
|
|||||||
@ -78,6 +78,26 @@ final class TestCall
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts that the test throws the given `$exceptionClass` when called if the given condition is true.
|
||||||
|
*
|
||||||
|
* @param (callable(): bool)|bool $condition
|
||||||
|
*/
|
||||||
|
public function throwsIf($condition, string $exception, string $exceptionMessage = null): TestCall
|
||||||
|
{
|
||||||
|
$condition = is_callable($condition)
|
||||||
|
? $condition
|
||||||
|
: static function () use ($condition): bool {
|
||||||
|
return (bool) $condition; // @phpstan-ignore-line
|
||||||
|
};
|
||||||
|
|
||||||
|
if ($condition()) {
|
||||||
|
return $this->throws($exception, $exceptionMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs the current test multiple times with
|
* Runs the current test multiple times with
|
||||||
* each item of the given `iterable`.
|
* each item of the given `iterable`.
|
||||||
|
|||||||
@ -6,7 +6,7 @@ namespace Pest;
|
|||||||
|
|
||||||
function version(): string
|
function version(): string
|
||||||
{
|
{
|
||||||
return '1.18.0';
|
return '1.20.0';
|
||||||
}
|
}
|
||||||
|
|
||||||
function testDirectory(string $file = ''): string
|
function testDirectory(string $file = ''): string
|
||||||
|
|||||||
67
src/Plugins/Environment.php
Normal file
67
src/Plugins/Environment.php
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Pest\Plugins;
|
||||||
|
|
||||||
|
use Pest\Contracts\Plugins\HandlesArguments;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
final class Environment implements HandlesArguments
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The continuous integration environment.
|
||||||
|
*/
|
||||||
|
public const CI = 'ci';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The local environment.
|
||||||
|
*/
|
||||||
|
public const LOCAL = 'local';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Pest\Plugins\Environment|null
|
||||||
|
*/
|
||||||
|
private static $instance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current environment.
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
private static $name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows to handle custom command line arguments.
|
||||||
|
*
|
||||||
|
* @param array<int, string> $arguments
|
||||||
|
*
|
||||||
|
* @return array<int, string> the updated list of arguments
|
||||||
|
*/
|
||||||
|
public function handleArguments(array $arguments): array
|
||||||
|
{
|
||||||
|
foreach ($arguments as $index => $argument) {
|
||||||
|
if ($argument === '--ci') {
|
||||||
|
unset($arguments[$index]);
|
||||||
|
|
||||||
|
self::$name = self::CI;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_values($arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the environment name.
|
||||||
|
*/
|
||||||
|
public static function name(string $name = null): string
|
||||||
|
{
|
||||||
|
if (is_string($name)) {
|
||||||
|
self::$name = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$name ?? self::LOCAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -11,6 +11,7 @@ use Pest\Exceptions\TestAlreadyExist;
|
|||||||
use Pest\Exceptions\TestCaseAlreadyInUse;
|
use Pest\Exceptions\TestCaseAlreadyInUse;
|
||||||
use Pest\Exceptions\TestCaseClassOrTraitNotFound;
|
use Pest\Exceptions\TestCaseClassOrTraitNotFound;
|
||||||
use Pest\Factories\TestCaseFactory;
|
use Pest\Factories\TestCaseFactory;
|
||||||
|
use Pest\Plugins\Environment;
|
||||||
use Pest\Support\Reflection;
|
use Pest\Support\Reflection;
|
||||||
use Pest\Support\Str;
|
use Pest\Support\Str;
|
||||||
use Pest\TestSuite;
|
use Pest\TestSuite;
|
||||||
@ -119,6 +120,10 @@ final class TestRepository
|
|||||||
*/
|
*/
|
||||||
private function testsUsingOnly(): array
|
private function testsUsingOnly(): array
|
||||||
{
|
{
|
||||||
|
if (Environment::name() === Environment::CI) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
return array_filter($this->state, function ($testFactory): bool {
|
return array_filter($this->state, function ($testFactory): bool {
|
||||||
return $testFactory->only;
|
return $testFactory->only;
|
||||||
});
|
});
|
||||||
|
|||||||
@ -91,8 +91,8 @@ final class TestSuite
|
|||||||
$this->afterEach = new AfterEachRepository();
|
$this->afterEach = new AfterEachRepository();
|
||||||
$this->afterAll = new AfterAllRepository();
|
$this->afterAll = new AfterAllRepository();
|
||||||
|
|
||||||
$this->rootPath = (string) realpath($rootPath);
|
$this->rootPath = (string) realpath($rootPath);
|
||||||
$this->testPath = $testPath;
|
$this->testPath = $testPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -107,6 +107,11 @@
|
|||||||
✓ it catch exceptions
|
✓ it catch exceptions
|
||||||
✓ it catch exceptions and messages
|
✓ it catch exceptions and messages
|
||||||
✓ it can just define the message
|
✓ it can just define the message
|
||||||
|
✓ it not catch exceptions if given condition is false
|
||||||
|
✓ it catch exceptions if given condition is true
|
||||||
|
✓ it catch exceptions and messages if given condition is true
|
||||||
|
✓ it can just define the message if given condition is true
|
||||||
|
✓ it can just define the message if given condition is 1
|
||||||
|
|
||||||
PASS Tests\Features\Expect\HigherOrder\methods
|
PASS Tests\Features\Expect\HigherOrder\methods
|
||||||
✓ it can access methods
|
✓ it can access methods
|
||||||
@ -158,6 +163,17 @@
|
|||||||
✓ it properly parses json string
|
✓ it properly parses json string
|
||||||
✓ fails with broken json string
|
✓ fails with broken json string
|
||||||
|
|
||||||
|
PASS Tests\Features\Expect\matchExpectation
|
||||||
|
✓ it pass
|
||||||
|
✓ it failures
|
||||||
|
✓ it runs with truthy
|
||||||
|
✓ it runs with falsy
|
||||||
|
✓ it runs with truthy closure condition
|
||||||
|
✓ it runs with falsy closure condition
|
||||||
|
✓ it can be passed non-callable values
|
||||||
|
✓ it fails with unhandled match
|
||||||
|
✓ it can be used in higher order tests
|
||||||
|
|
||||||
PASS Tests\Features\Expect\not
|
PASS Tests\Features\Expect\not
|
||||||
✓ not property calls
|
✓ not property calls
|
||||||
|
|
||||||
@ -168,7 +184,7 @@
|
|||||||
✓ an exception is thrown if the the type is not iterable
|
✓ an exception is thrown if the the type is not iterable
|
||||||
✓ allows for sequences of checks to be run on iterable data
|
✓ allows for sequences of checks to be run on iterable data
|
||||||
✓ loops back to the start if it runs out of sequence items
|
✓ loops back to the start if it runs out of sequence items
|
||||||
✓ it works if the number of items in the iterable is smaller than the number of expectations
|
✓ fails if the number of iterable items is greater than the number of expectations
|
||||||
✓ it works with associative arrays
|
✓ it works with associative arrays
|
||||||
✓ it can be passed non-callable values
|
✓ it can be passed non-callable values
|
||||||
✓ it can be passed a mixture of value types
|
✓ it can be passed a mixture of value types
|
||||||
@ -481,6 +497,24 @@
|
|||||||
✓ closure missing parameter
|
✓ closure missing parameter
|
||||||
✓ closure missing type-hint
|
✓ closure missing type-hint
|
||||||
|
|
||||||
|
PASS Tests\Features\Expect\unless
|
||||||
|
✓ it pass
|
||||||
|
✓ it failures
|
||||||
|
✓ it runs with truthy
|
||||||
|
✓ it skips with falsy
|
||||||
|
✓ it runs with truthy closure condition
|
||||||
|
✓ it skips with falsy closure condition
|
||||||
|
✓ it can be used in higher order tests
|
||||||
|
|
||||||
|
PASS Tests\Features\Expect\when
|
||||||
|
✓ it pass
|
||||||
|
✓ it failures
|
||||||
|
✓ it runs with truthy
|
||||||
|
✓ it skips with falsy
|
||||||
|
✓ it runs with truthy closure condition
|
||||||
|
✓ it skips with falsy closure condition
|
||||||
|
✓ it can be used in higher order tests
|
||||||
|
|
||||||
PASS Tests\Features\Helpers
|
PASS Tests\Features\Helpers
|
||||||
✓ it can set/get properties on $this
|
✓ it can set/get properties on $this
|
||||||
✓ it throws error if property do not exist
|
✓ it throws error if property do not exist
|
||||||
@ -623,6 +657,10 @@
|
|||||||
✓ it show the actual dataset of multiple non-named datasets in their description
|
✓ it show the actual dataset of multiple non-named datasets in their description
|
||||||
✓ it show the correct description for mixed named and not-named datasets
|
✓ it show the correct description for mixed named and not-named datasets
|
||||||
|
|
||||||
|
PASS Tests\Unit\Plugins\Environment
|
||||||
|
✓ environment is set to CI when --ci option is used
|
||||||
|
✓ environment is set to Local when --ci option is not used
|
||||||
|
|
||||||
PASS Tests\Unit\Plugins\Version
|
PASS Tests\Unit\Plugins\Version
|
||||||
✓ it outputs the version when --version is used
|
✓ it outputs the version when --version is used
|
||||||
✓ it do not outputs version when --version is not used
|
✓ it do not outputs version when --version is not used
|
||||||
@ -648,6 +686,7 @@
|
|||||||
✓ it alerts users about tests with arguments but no input
|
✓ it alerts users about tests with arguments but no input
|
||||||
✓ it can return an array of all test suite filenames
|
✓ it can return an array of all test suite filenames
|
||||||
✓ it can filter the test suite filenames to those with the only method
|
✓ it can filter the test suite filenames to those with the only method
|
||||||
|
✓ it does not filter the test suite filenames to those with the only method when working in CI pipeline
|
||||||
|
|
||||||
PASS Tests\Visual\Help
|
PASS Tests\Visual\Help
|
||||||
✓ visual snapshot of help command output
|
✓ visual snapshot of help command output
|
||||||
@ -681,5 +720,5 @@
|
|||||||
✓ it is a test
|
✓ it is a test
|
||||||
✓ it uses correct parent class
|
✓ it uses correct parent class
|
||||||
|
|
||||||
Tests: 4 incompleted, 9 skipped, 447 passed
|
Tests: 4 incompleted, 9 skipped, 478 passed
|
||||||
|
|
||||||
@ -17,3 +17,23 @@ it('catch exceptions and messages', function () {
|
|||||||
it('can just define the message', function () {
|
it('can just define the message', function () {
|
||||||
throw new Exception('Something bad happened');
|
throw new Exception('Something bad happened');
|
||||||
})->throws('Something bad happened');
|
})->throws('Something bad happened');
|
||||||
|
|
||||||
|
it('not catch exceptions if given condition is false', function () {
|
||||||
|
$this->assertTrue(true);
|
||||||
|
})->throwsIf(false, Exception::class);
|
||||||
|
|
||||||
|
it('catch exceptions if given condition is true', function () {
|
||||||
|
throw new Exception('Something bad happened');
|
||||||
|
})->throwsIf(function () { return true; }, Exception::class);
|
||||||
|
|
||||||
|
it('catch exceptions and messages if given condition is true', function () {
|
||||||
|
throw new Exception('Something bad happened');
|
||||||
|
})->throwsIf(true, Exception::class, 'Something bad happened');
|
||||||
|
|
||||||
|
it('can just define the message if given condition is true', function () {
|
||||||
|
throw new Exception('Something bad happened');
|
||||||
|
})->throwsIf(true, 'Something bad happened');
|
||||||
|
|
||||||
|
it('can just define the message if given condition is 1', function () {
|
||||||
|
throw new Exception('Something bad happened');
|
||||||
|
})->throwsIf(1, 'Something bad happened');
|
||||||
|
|||||||
148
tests/Features/Expect/matchExpectation.php
Normal file
148
tests/Features/Expect/matchExpectation.php
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use PHPUnit\Framework\ExpectationFailedException;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
$this->matched = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('pass', function () {
|
||||||
|
expect('baz')
|
||||||
|
->match('foo', [
|
||||||
|
'bar' => function ($value) {
|
||||||
|
$this->matched = 'bar';
|
||||||
|
|
||||||
|
return $value->toEqual('bar');
|
||||||
|
},
|
||||||
|
'foo' => function ($value) {
|
||||||
|
$this->matched = 'baz';
|
||||||
|
|
||||||
|
return $value->toEqual('baz');
|
||||||
|
},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
->toEqual($this->matched);
|
||||||
|
|
||||||
|
expect(static::getCount())->toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('failures', function () {
|
||||||
|
expect(true)
|
||||||
|
->match('foo', [
|
||||||
|
'bar' => function ($value) {
|
||||||
|
return $value->toBeTrue();
|
||||||
|
},
|
||||||
|
'foo' => function ($value) {
|
||||||
|
return $value->toBeFalse();
|
||||||
|
},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
})->throws(ExpectationFailedException::class, 'true is false');
|
||||||
|
|
||||||
|
it('runs with truthy', function () {
|
||||||
|
expect('foo')
|
||||||
|
->match(1, [
|
||||||
|
'bar' => function ($value) {
|
||||||
|
$this->matched = 'bar';
|
||||||
|
|
||||||
|
return $value->toEqual('bar');
|
||||||
|
},
|
||||||
|
true => function ($value) {
|
||||||
|
$this->matched = 'foo';
|
||||||
|
|
||||||
|
return $value->toEqual('foo');
|
||||||
|
},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
->toEqual($this->matched);
|
||||||
|
|
||||||
|
expect(static::getCount())->toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('runs with falsy', function () {
|
||||||
|
expect('foo')
|
||||||
|
->match(false, [
|
||||||
|
'bar' => function ($value) {
|
||||||
|
$this->matched = 'bar';
|
||||||
|
|
||||||
|
return $value->toEqual('bar');
|
||||||
|
},
|
||||||
|
false => function ($value) {
|
||||||
|
$this->matched = 'foo';
|
||||||
|
|
||||||
|
return $value->toEqual('foo');
|
||||||
|
},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
->toEqual($this->matched);
|
||||||
|
|
||||||
|
expect(static::getCount())->toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('runs with truthy closure condition', function () {
|
||||||
|
expect('foo')
|
||||||
|
->match(
|
||||||
|
function () { return '1'; }, [
|
||||||
|
'bar' => function ($value) {
|
||||||
|
$this->matched = 'bar';
|
||||||
|
|
||||||
|
return $value->toEqual('bar');
|
||||||
|
},
|
||||||
|
true => function ($value) {
|
||||||
|
$this->matched = 'foo';
|
||||||
|
|
||||||
|
return $value->toEqual('foo');
|
||||||
|
},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
->toEqual($this->matched);
|
||||||
|
|
||||||
|
expect(static::getCount())->toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('runs with falsy closure condition', function () {
|
||||||
|
expect('foo')
|
||||||
|
->match(
|
||||||
|
function () { return '0'; }, [
|
||||||
|
'bar' => function ($value) {
|
||||||
|
$this->matched = 'bar';
|
||||||
|
|
||||||
|
return $value->toEqual('bar');
|
||||||
|
},
|
||||||
|
false => function ($value) {
|
||||||
|
$this->matched = 'foo';
|
||||||
|
|
||||||
|
return $value->toEqual('foo');
|
||||||
|
},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
->toEqual($this->matched);
|
||||||
|
|
||||||
|
expect(static::getCount())->toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can be passed non-callable values', function () {
|
||||||
|
expect('foo')
|
||||||
|
->match('pest', [
|
||||||
|
'bar' => 'foo',
|
||||||
|
'pest' => 'baz',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
})->throws(ExpectationFailedException::class, 'two strings are equal');
|
||||||
|
|
||||||
|
it('fails with unhandled match', function () {
|
||||||
|
expect('foo')->match('bar', []);
|
||||||
|
})->throws(ExpectationFailedException::class, 'Unhandled match value.');
|
||||||
|
|
||||||
|
it('can be used in higher order tests')
|
||||||
|
->expect(true)
|
||||||
|
->match(
|
||||||
|
function () { return true; }, [
|
||||||
|
false => function ($value) {
|
||||||
|
return $value->toBeFalse();
|
||||||
|
},
|
||||||
|
true => function ($value) {
|
||||||
|
return $value->toBeTrue();
|
||||||
|
},
|
||||||
|
]
|
||||||
|
);
|
||||||
@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use PHPUnit\Framework\ExpectationFailedException;
|
||||||
|
|
||||||
test('an exception is thrown if the the type is not iterable', function () {
|
test('an exception is thrown if the the type is not iterable', function () {
|
||||||
expect('Foobar')->each->sequence();
|
expect('Foobar')->each->sequence();
|
||||||
})->throws(BadMethodCallException::class, 'Expectation value is not iterable.');
|
})->throws(BadMethodCallException::class, 'Expectation value is not iterable.');
|
||||||
@ -26,16 +28,14 @@ test('loops back to the start if it runs out of sequence items', function () {
|
|||||||
expect(static::getCount())->toBe(16);
|
expect(static::getCount())->toBe(16);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('it works if the number of items in the iterable is smaller than the number of expectations', function () {
|
test('fails if the number of iterable items is greater than the number of expectations', function () {
|
||||||
expect([1, 2])
|
expect([1, 2])
|
||||||
->sequence(
|
->sequence(
|
||||||
function ($expectation) { $expectation->toBeInt()->toEqual(1); },
|
function ($expectation) { $expectation->toBeInt()->toEqual(1); },
|
||||||
function ($expectation) { $expectation->toBeInt()->toEqual(2); },
|
function ($expectation) { $expectation->toBeInt()->toEqual(2); },
|
||||||
function ($expectation) { $expectation->toBeInt()->toEqual(3); },
|
function ($expectation) { $expectation->toBeInt()->toEqual(3); },
|
||||||
);
|
);
|
||||||
|
})->throws(ExpectationFailedException::class);
|
||||||
expect(static::getCount())->toBe(4);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('it works with associative arrays', function () {
|
test('it works with associative arrays', function () {
|
||||||
expect(['foo' => 'bar', 'baz' => 'boom'])
|
expect(['foo' => 'bar', 'baz' => 'boom'])
|
||||||
|
|||||||
101
tests/Features/Expect/unless.php
Normal file
101
tests/Features/Expect/unless.php
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use PHPUnit\Framework\ExpectationFailedException;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
$this->unlessObject = new stdClass();
|
||||||
|
$this->unlessObject->trueValue = true;
|
||||||
|
$this->unlessObject->foo = 'foo';
|
||||||
|
});
|
||||||
|
|
||||||
|
it('pass', function () {
|
||||||
|
expect('foo')
|
||||||
|
->unless(
|
||||||
|
true,
|
||||||
|
function ($value) {
|
||||||
|
return $value->toEqual('bar');
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->toEqual('foo');
|
||||||
|
|
||||||
|
expect(static::getCount())->toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('failures', function () {
|
||||||
|
expect('foo')
|
||||||
|
->unless(
|
||||||
|
false,
|
||||||
|
function ($value) {
|
||||||
|
return $value->toBeTrue();
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->toEqual('foo');
|
||||||
|
})->throws(ExpectationFailedException::class, 'is true');
|
||||||
|
|
||||||
|
it('runs with truthy', function () {
|
||||||
|
expect($this->unlessObject)
|
||||||
|
->unless(
|
||||||
|
0,
|
||||||
|
function ($value) {
|
||||||
|
return $value->trueValue->toBeTrue();
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->foo->toEqual('foo');
|
||||||
|
|
||||||
|
expect(static::getCount())->toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('skips with falsy', function () {
|
||||||
|
expect($this->unlessObject)
|
||||||
|
->unless(
|
||||||
|
1,
|
||||||
|
function ($value) {
|
||||||
|
return $value->trueValue->toBeFalse(); // fails
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->unless(
|
||||||
|
true,
|
||||||
|
function ($value) {
|
||||||
|
return $value->trueValue->toBeFalse(); // fails
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->foo->toEqual('foo');
|
||||||
|
|
||||||
|
expect(static::getCount())->toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('runs with truthy closure condition', function () {
|
||||||
|
expect($this->unlessObject)
|
||||||
|
->unless(
|
||||||
|
function () { return '0'; },
|
||||||
|
function ($value) {
|
||||||
|
return $value->trueValue->toBeTrue();
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->foo->toEqual('foo');
|
||||||
|
|
||||||
|
expect(static::getCount())->toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('skips with falsy closure condition', function () {
|
||||||
|
expect($this->unlessObject)
|
||||||
|
->unless(
|
||||||
|
function () { return '1'; },
|
||||||
|
function ($value) {
|
||||||
|
return $value->trueValue->toBeFalse(); // fails
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->foo->toEqual('foo');
|
||||||
|
|
||||||
|
expect(static::getCount())->toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can be used in higher order tests')
|
||||||
|
->expect(true)
|
||||||
|
->unless(
|
||||||
|
function () { return false; },
|
||||||
|
function ($value) {
|
||||||
|
return $value->toBeFalse();
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->throws(ExpectationFailedException::class, 'true is false');
|
||||||
101
tests/Features/Expect/when.php
Normal file
101
tests/Features/Expect/when.php
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use PHPUnit\Framework\ExpectationFailedException;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
$this->whenObject = new stdClass();
|
||||||
|
$this->whenObject->trueValue = true;
|
||||||
|
$this->whenObject->foo = 'foo';
|
||||||
|
});
|
||||||
|
|
||||||
|
it('pass', function () {
|
||||||
|
expect('foo')
|
||||||
|
->when(
|
||||||
|
true,
|
||||||
|
function ($value) {
|
||||||
|
return $value->toEqual('foo');
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->toEqual('foo');
|
||||||
|
|
||||||
|
expect(static::getCount())->toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('failures', function () {
|
||||||
|
expect('foo')
|
||||||
|
->when(
|
||||||
|
true,
|
||||||
|
function ($value) {
|
||||||
|
return $value->toBeTrue();
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->toEqual('foo');
|
||||||
|
})->throws(ExpectationFailedException::class, 'is true');
|
||||||
|
|
||||||
|
it('runs with truthy', function () {
|
||||||
|
expect($this->whenObject)
|
||||||
|
->when(
|
||||||
|
1,
|
||||||
|
function ($value) {
|
||||||
|
return $value->trueValue->toBeTrue();
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->foo->toEqual('foo');
|
||||||
|
|
||||||
|
expect(static::getCount())->toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('skips with falsy', function () {
|
||||||
|
expect($this->whenObject)
|
||||||
|
->when(
|
||||||
|
0,
|
||||||
|
function ($value) {
|
||||||
|
return $value->trueValue->toBeFalse(); // fails
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->when(
|
||||||
|
false,
|
||||||
|
function ($value) {
|
||||||
|
return $value->trueValue->toBeFalse(); // fails
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->foo->toEqual('foo');
|
||||||
|
|
||||||
|
expect(static::getCount())->toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('runs with truthy closure condition', function () {
|
||||||
|
expect($this->whenObject)
|
||||||
|
->when(
|
||||||
|
function () { return '1'; },
|
||||||
|
function ($value) {
|
||||||
|
return $value->trueValue->toBeTrue();
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->foo->toEqual('foo');
|
||||||
|
|
||||||
|
expect(static::getCount())->toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('skips with falsy closure condition', function () {
|
||||||
|
expect($this->whenObject)
|
||||||
|
->when(
|
||||||
|
function () { return '0'; },
|
||||||
|
function ($value) {
|
||||||
|
return $value->trueValue->toBeFalse(); // fails
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->foo->toEqual('foo');
|
||||||
|
|
||||||
|
expect(static::getCount())->toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can be used in higher order tests')
|
||||||
|
->expect(false)
|
||||||
|
->when(
|
||||||
|
function () { return true; },
|
||||||
|
function ($value) {
|
||||||
|
return $value->toBeTrue();
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->throws(ExpectationFailedException::class, 'false is true');
|
||||||
23
tests/Unit/Plugins/Environment.php
Normal file
23
tests/Unit/Plugins/Environment.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Pest\Plugins\Environment;
|
||||||
|
|
||||||
|
test('environment is set to CI when --ci option is used', function () {
|
||||||
|
$previousName = Environment::name();
|
||||||
|
|
||||||
|
$plugin = new Environment();
|
||||||
|
|
||||||
|
$plugin->handleArguments(['foo', '--ci', 'bar']);
|
||||||
|
|
||||||
|
expect(Environment::name())->toBe(Environment::CI);
|
||||||
|
|
||||||
|
Environment::name($previousName);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('environment is set to Local when --ci option is not used', function () {
|
||||||
|
$plugin = new Environment();
|
||||||
|
|
||||||
|
$plugin->handleArguments(['foo', 'bar', 'baz']);
|
||||||
|
|
||||||
|
expect(Environment::name())->toBe(Environment::LOCAL);
|
||||||
|
});
|
||||||
@ -2,13 +2,15 @@
|
|||||||
|
|
||||||
use Pest\Exceptions\DatasetMissing;
|
use Pest\Exceptions\DatasetMissing;
|
||||||
use Pest\Exceptions\TestAlreadyExist;
|
use Pest\Exceptions\TestAlreadyExist;
|
||||||
|
use Pest\Factories\TestCaseFactory;
|
||||||
|
use Pest\Plugins\Environment;
|
||||||
use Pest\TestSuite;
|
use Pest\TestSuite;
|
||||||
|
|
||||||
it('does not allow to add the same test description twice', function () {
|
it('does not allow to add the same test description twice', function () {
|
||||||
$testSuite = new TestSuite(getcwd(), 'tests');
|
$testSuite = new TestSuite(getcwd(), 'tests');
|
||||||
$test = function () {};
|
$test = function () {};
|
||||||
$testSuite->tests->set(new \Pest\Factories\TestCaseFactory(__FILE__, 'foo', $test));
|
$testSuite->tests->set(new TestCaseFactory(__FILE__, 'foo', $test));
|
||||||
$testSuite->tests->set(new \Pest\Factories\TestCaseFactory(__FILE__, 'foo', $test));
|
$testSuite->tests->set(new TestCaseFactory(__FILE__, 'foo', $test));
|
||||||
})->throws(
|
})->throws(
|
||||||
TestAlreadyExist::class,
|
TestAlreadyExist::class,
|
||||||
sprintf('A test with the description `%s` already exist in the filename `%s`.', 'foo', __FILE__),
|
sprintf('A test with the description `%s` already exist in the filename `%s`.', 'foo', __FILE__),
|
||||||
@ -17,17 +19,17 @@ it('does not allow to add the same test description twice', function () {
|
|||||||
it('alerts users about tests with arguments but no input', function () {
|
it('alerts users about tests with arguments but no input', function () {
|
||||||
$testSuite = new TestSuite(getcwd(), 'tests');
|
$testSuite = new TestSuite(getcwd(), 'tests');
|
||||||
$test = function (int $arg) {};
|
$test = function (int $arg) {};
|
||||||
$testSuite->tests->set(new \Pest\Factories\TestCaseFactory(__FILE__, 'foo', $test));
|
$testSuite->tests->set(new TestCaseFactory(__FILE__, 'foo', $test));
|
||||||
})->throws(
|
})->throws(
|
||||||
DatasetMissing::class,
|
DatasetMissing::class,
|
||||||
sprintf("A test with the description '%s' has %d argument(s) ([%s]) and no dataset(s) provided in %s", 'foo', 1, 'int $arg', __FILE__),
|
sprintf("A test with the description '%s' has %d argument(s) ([%s]) and no dataset(s) provided in %s", 'foo', 1, 'int $arg', __FILE__),
|
||||||
);
|
);
|
||||||
|
|
||||||
it('can return an array of all test suite filenames', function () {
|
it('can return an array of all test suite filenames', function () {
|
||||||
$testSuite = new TestSuite(getcwd(), 'tests');
|
$testSuite = TestSuite::getInstance(getcwd(), 'tests');
|
||||||
$test = function () {};
|
$test = function () {};
|
||||||
$testSuite->tests->set(new \Pest\Factories\TestCaseFactory(__FILE__, 'foo', $test));
|
$testSuite->tests->set(new TestCaseFactory(__FILE__, 'foo', $test));
|
||||||
$testSuite->tests->set(new \Pest\Factories\TestCaseFactory(__FILE__, 'bar', $test));
|
$testSuite->tests->set(new TestCaseFactory(__FILE__, 'bar', $test));
|
||||||
|
|
||||||
expect($testSuite->tests->getFilenames())->toEqual([
|
expect($testSuite->tests->getFilenames())->toEqual([
|
||||||
__FILE__,
|
__FILE__,
|
||||||
@ -39,13 +41,34 @@ it('can filter the test suite filenames to those with the only method', function
|
|||||||
$testSuite = new TestSuite(getcwd(), 'tests');
|
$testSuite = new TestSuite(getcwd(), 'tests');
|
||||||
$test = function () {};
|
$test = function () {};
|
||||||
|
|
||||||
$testWithOnly = new \Pest\Factories\TestCaseFactory(__FILE__, 'foo', $test);
|
$testWithOnly = new TestCaseFactory(__FILE__, 'foo', $test);
|
||||||
$testWithOnly->only = true;
|
$testWithOnly->only = true;
|
||||||
$testSuite->tests->set($testWithOnly);
|
$testSuite->tests->set($testWithOnly);
|
||||||
|
|
||||||
$testSuite->tests->set(new \Pest\Factories\TestCaseFactory('Baz/Bar/Boo.php', 'bar', $test));
|
$testSuite->tests->set(new TestCaseFactory('Baz/Bar/Boo.php', 'bar', $test));
|
||||||
|
|
||||||
expect($testSuite->tests->getFilenames())->toEqual([
|
expect($testSuite->tests->getFilenames())->toEqual([
|
||||||
__FILE__,
|
__FILE__,
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('does not filter the test suite filenames to those with the only method when working in CI pipeline', function () {
|
||||||
|
$previousEnvironment = Environment::name();
|
||||||
|
Environment::name(Environment::CI);
|
||||||
|
$testSuite = TestSuite::getInstance(getcwd(), 'tests');
|
||||||
|
|
||||||
|
$test = function () {};
|
||||||
|
|
||||||
|
$testWithOnly = new TestCaseFactory(__FILE__, 'foo', $test);
|
||||||
|
$testWithOnly->only = true;
|
||||||
|
$testSuite->tests->set($testWithOnly);
|
||||||
|
|
||||||
|
$testSuite->tests->set(new TestCaseFactory('Baz/Bar/Boo.php', 'bar', $test));
|
||||||
|
|
||||||
|
expect($testSuite->tests->getFilenames())->toEqual([
|
||||||
|
__FILE__,
|
||||||
|
'Baz/Bar/Boo.php',
|
||||||
|
]);
|
||||||
|
|
||||||
|
Environment::name($previousEnvironment);
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user