From 4f67eff619759caa6ae21ead5eff7bb644dd7940 Mon Sep 17 00:00:00 2001 From: luke Date: Thu, 24 Jun 2021 21:38:02 +0100 Subject: [PATCH 01/31] Start of work --- tests/Features/HigherOrderTests.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/Features/HigherOrderTests.php b/tests/Features/HigherOrderTests.php index 77e87ce4..d01a18e5 100644 --- a/tests/Features/HigherOrderTests.php +++ b/tests/Features/HigherOrderTests.php @@ -8,4 +8,7 @@ it('is capable doing multiple assertions') ->assertTrue(true) ->assertFalse(false); +//it('can tap into the test') + + afterEach()->assertTrue(true); From acef002a2d53fc0b1c810fb6e217883955920d2f Mon Sep 17 00:00:00 2001 From: luke Date: Thu, 24 Jun 2021 22:57:26 +0100 Subject: [PATCH 02/31] Adds `tap` for Higher Order tests --- src/Support/HigherOrderCallables.php | 33 ++++++++++++++++++++++++++++ src/Support/HigherOrderMessage.php | 19 ++++++++++++++++ src/Support/Reflection.php | 16 +++++++++++--- tests/.snapshots/success.txt | 4 +++- tests/Features/HigherOrderTests.php | 11 +++++++++- 5 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 src/Support/HigherOrderCallables.php diff --git a/src/Support/HigherOrderCallables.php b/src/Support/HigherOrderCallables.php new file mode 100644 index 00000000..08231c76 --- /dev/null +++ b/src/Support/HigherOrderCallables.php @@ -0,0 +1,33 @@ +target = $target; + } + + /** + * @template TValue + * + * @param callable(): TValue $callable + * + * @return TValue|object + */ + public function tap(callable $callable) + { + return Reflection::bindCallable($callable) ?? $this->target; + } +} diff --git a/src/Support/HigherOrderMessage.php b/src/Support/HigherOrderMessage.php index 9f363b5a..5c5ddd07 100644 --- a/src/Support/HigherOrderMessage.php +++ b/src/Support/HigherOrderMessage.php @@ -70,6 +70,10 @@ final class HigherOrderMessage */ public function call(object $target) { + if (($value = $this->retrieveHigherOrderCallable($target)) !== null) { + return $value; + } + try { return Reflection::call($target, $this->methodName, $this->arguments); } catch (Throwable $throwable) { @@ -88,6 +92,21 @@ final class HigherOrderMessage } } + /** + * Attempts to call one of the available Higher Order callables if it exists. + * + * @return mixed|null + */ + private function retrieveHigherOrderCallable(object $target) + { + if (in_array($this->methodName, get_class_methods(HigherOrderCallables::class), true)) { + /* @phpstan-ignore-next-line */ + return (new HigherOrderCallables($target))->{$this->methodName}(...$this->arguments); + } + + return null; + } + private static function getUndefinedMethodMessage(object $target, string $methodName): string { if (\PHP_MAJOR_VERSION >= 8) { diff --git a/src/Support/Reflection.php b/src/Support/Reflection.php index c25709b9..fbe7ba40 100644 --- a/src/Support/Reflection.php +++ b/src/Support/Reflection.php @@ -41,15 +41,25 @@ final class Reflection } if (is_callable($method)) { - return Closure::fromCallable($method)->bindTo( - TestSuite::getInstance()->test - )(...$args); + return static::bindCallable($method, $args); } throw $exception; } } + /** + * Bind a callable to the TestCase and return the result. + * + * @param array $args + * + * @return mixed + */ + public static function bindCallable(callable $callable, array $args = []) + { + return Closure::fromCallable($callable)->bindTo(TestSuite::getInstance()->test)(...$args); + } + /** * Infers the file name from the given closure. */ diff --git a/tests/.snapshots/success.txt b/tests/.snapshots/success.txt index e7ecc1a0..36099b43 100644 --- a/tests/.snapshots/success.txt +++ b/tests/.snapshots/success.txt @@ -409,6 +409,8 @@ PASS Tests\Features\HigherOrderTests ✓ it proxies calls to object ✓ it is capable doing multiple assertions + ✓ it can tap into the test + ✓ it can use the returned instance from a tap WARN Tests\Features\Incompleted … incompleted @@ -578,5 +580,5 @@ ✓ it is a test ✓ it uses correct parent class - Tests: 4 incompleted, 7 skipped, 362 passed + Tests: 4 incompleted, 7 skipped, 364 passed \ No newline at end of file diff --git a/tests/Features/HigherOrderTests.php b/tests/Features/HigherOrderTests.php index d01a18e5..ea5b80e1 100644 --- a/tests/Features/HigherOrderTests.php +++ b/tests/Features/HigherOrderTests.php @@ -1,5 +1,7 @@ assertTrue(true); it('proxies calls to object')->assertTrue(true); @@ -8,7 +10,14 @@ it('is capable doing multiple assertions') ->assertTrue(true) ->assertFalse(false); -//it('can tap into the test') +it('can tap into the test') + ->expect('foo')->toBeString()->toBe('foo') + ->tap(function () { expect($this)->toBeInstanceOf(TestCase::class); }) + ->and('hello world')->toBeString(); +it('can use the returned instance from a tap') + ->expect('foo')->toBeString()->toBe('foo') + ->tap(function () { return expect($this); }) + ->toBeInstanceOf(TestCase::class); afterEach()->assertTrue(true); From f2e56da2da9d88d6851b562fe2b4e113bb93eda9 Mon Sep 17 00:00:00 2001 From: luke Date: Thu, 24 Jun 2021 22:58:29 +0100 Subject: [PATCH 03/31] Updates snapshots --- tests/.snapshots/success.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/.snapshots/success.txt b/tests/.snapshots/success.txt index 9b0a5c44..96cd47ea 100644 --- a/tests/.snapshots/success.txt +++ b/tests/.snapshots/success.txt @@ -410,6 +410,8 @@ PASS Tests\Features\HigherOrderTests ✓ it proxies calls to object ✓ it is capable doing multiple assertions + ✓ it can tap into the test + ✓ it can use the returned instance from a tap WARN Tests\Features\Incompleted … incompleted @@ -579,5 +581,5 @@ ✓ it is a test ✓ it uses correct parent class - Tests: 4 incompleted, 7 skipped, 363 passed + Tests: 4 incompleted, 7 skipped, 365 passed \ No newline at end of file From c290909eb3ea47544cdfae6e1119492b1a0699a6 Mon Sep 17 00:00:00 2001 From: luke Date: Fri, 25 Jun 2021 09:24:16 +0100 Subject: [PATCH 04/31] Adds @mixin for HigherOrderCallables class --- src/PendingObjects/TestCall.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/PendingObjects/TestCall.php b/src/PendingObjects/TestCall.php index 39486565..69227aa6 100644 --- a/src/PendingObjects/TestCall.php +++ b/src/PendingObjects/TestCall.php @@ -11,7 +11,8 @@ use Pest\Support\NullClosure; use Pest\TestSuite; use SebastianBergmann\Exporter\Exporter; -/** +/* + * @mixin \Pest\Support\HigherOrderCallables * @method \Pest\Expectations\Expectation expect(mixed $value) * * @internal From 7e9edecc7f0a0ea369650161735b35df310bcd0e Mon Sep 17 00:00:00 2001 From: luke Date: Tue, 6 Jul 2021 14:05:40 +0100 Subject: [PATCH 05/31] Higher Order Tests now resolve callable expectations. The `tap` method now always returns the test case. --- src/PendingObjects/TestCall.php | 8 +++---- src/Plugins/Coverage.php | 1 - src/Support/HigherOrderCallables.php | 34 +++++++++++++++++++++++++++- tests/.snapshots/success.txt | 2 +- tests/Features/HigherOrderTests.php | 16 ++++++++----- 5 files changed, 48 insertions(+), 13 deletions(-) diff --git a/src/PendingObjects/TestCall.php b/src/PendingObjects/TestCall.php index 69227aa6..40574ed1 100644 --- a/src/PendingObjects/TestCall.php +++ b/src/PendingObjects/TestCall.php @@ -7,15 +7,15 @@ namespace Pest\PendingObjects; use Closure; use Pest\Factories\TestCaseFactory; use Pest\Support\Backtrace; +use Pest\Support\HigherOrderCallables; use Pest\Support\NullClosure; use Pest\TestSuite; use SebastianBergmann\Exporter\Exporter; -/* - * @mixin \Pest\Support\HigherOrderCallables - * @method \Pest\Expectations\Expectation expect(mixed $value) - * +/** * @internal + * + * @mixin HigherOrderCallables */ final class TestCall { diff --git a/src/Plugins/Coverage.php b/src/Plugins/Coverage.php index cc03bd17..6d993717 100644 --- a/src/Plugins/Coverage.php +++ b/src/Plugins/Coverage.php @@ -81,7 +81,6 @@ final class Coverage implements AddsOutput, HandlesArguments } if ($input->getOption(self::MIN_OPTION) !== null) { - /* @phpstan-ignore-next-line */ $this->coverageMin = (float) $input->getOption(self::MIN_OPTION); } diff --git a/src/Support/HigherOrderCallables.php b/src/Support/HigherOrderCallables.php index 08231c76..46503e67 100644 --- a/src/Support/HigherOrderCallables.php +++ b/src/Support/HigherOrderCallables.php @@ -4,6 +4,8 @@ declare(strict_types=1); namespace Pest\Support; +use Pest\Expectation; + /** * @internal */ @@ -19,6 +21,34 @@ final class HigherOrderCallables $this->target = $target; } + /** + * @template TValue + * + * Create a new expectation. Callable values will be executed prior to returning the new expectation. + * + * @param callable|TValue $value + * + * @return Expectation + */ + public function expect($value) + { + return new Expectation(is_callable($value) ? Reflection::bindCallable($value) : $value); + } + + /** + * @template TValue + * + * Create a new expectation. Callable values will be executed prior to returning the new expectation. + * + * @param callable|TValue $value + * + * @return Expectation + */ + public function and($value) + { + return $this->expect($value); + } + /** * @template TValue * @@ -28,6 +58,8 @@ final class HigherOrderCallables */ public function tap(callable $callable) { - return Reflection::bindCallable($callable) ?? $this->target; + Reflection::bindCallable($callable); + + return $this->target; } } diff --git a/tests/.snapshots/success.txt b/tests/.snapshots/success.txt index 96cd47ea..d943da92 100644 --- a/tests/.snapshots/success.txt +++ b/tests/.snapshots/success.txt @@ -410,8 +410,8 @@ PASS Tests\Features\HigherOrderTests ✓ it proxies calls to object ✓ it is capable doing multiple assertions + ✓ it resolves expect callables correctly ✓ it can tap into the test - ✓ it can use the returned instance from a tap WARN Tests\Features\Incompleted … incompleted diff --git a/tests/Features/HigherOrderTests.php b/tests/Features/HigherOrderTests.php index ea5b80e1..f871d919 100644 --- a/tests/Features/HigherOrderTests.php +++ b/tests/Features/HigherOrderTests.php @@ -10,14 +10,18 @@ it('is capable doing multiple assertions') ->assertTrue(true) ->assertFalse(false); +it('resolves expect callables correctly') + ->expect(function () { return 'foo'; }) + ->toBeString() + ->toBe('foo') + ->and('bar') + ->toBeString() + ->toBe('bar'); + it('can tap into the test') - ->expect('foo')->toBeString()->toBe('foo') + ->expect('foo')->toBeString() ->tap(function () { expect($this)->toBeInstanceOf(TestCase::class); }) + ->toBe('foo') ->and('hello world')->toBeString(); -it('can use the returned instance from a tap') - ->expect('foo')->toBeString()->toBe('foo') - ->tap(function () { return expect($this); }) - ->toBeInstanceOf(TestCase::class); - afterEach()->assertTrue(true); From b97e206f7a2cb094d4adaba0ca554d49a3040446 Mon Sep 17 00:00:00 2001 From: luke Date: Thu, 8 Jul 2021 09:44:28 +0100 Subject: [PATCH 06/31] Closures passed to the `skip` method are now bound to the test case to allow for more complex logic. --- src/PendingObjects/TestCall.php | 8 +++---- src/Plugins/Coverage.php | 1 - src/Support/HigherOrderMessage.php | 23 +++++++++++++++++++- src/Support/HigherOrderMessageCollection.php | 10 +++++++++ tests/Features/Skip.php | 8 +++++++ 5 files changed, 43 insertions(+), 7 deletions(-) diff --git a/src/PendingObjects/TestCall.php b/src/PendingObjects/TestCall.php index 39486565..76df5dac 100644 --- a/src/PendingObjects/TestCall.php +++ b/src/PendingObjects/TestCall.php @@ -143,11 +143,9 @@ final class TestCall ? $conditionOrMessage : $message; - if ($condition() !== false) { - $this->testCaseFactory - ->chains - ->add(Backtrace::file(), Backtrace::line(), 'markTestSkipped', [$message]); - } + $this->testCaseFactory + ->chains + ->addWhen($condition, Backtrace::file(), Backtrace::line(), 'markTestSkipped', [$message]); return $this; } diff --git a/src/Plugins/Coverage.php b/src/Plugins/Coverage.php index cc03bd17..6d993717 100644 --- a/src/Plugins/Coverage.php +++ b/src/Plugins/Coverage.php @@ -81,7 +81,6 @@ final class Coverage implements AddsOutput, HandlesArguments } if ($input->getOption(self::MIN_OPTION) !== null) { - /* @phpstan-ignore-next-line */ $this->coverageMin = (float) $input->getOption(self::MIN_OPTION); } diff --git a/src/Support/HigherOrderMessage.php b/src/Support/HigherOrderMessage.php index 9f363b5a..4479b21d 100644 --- a/src/Support/HigherOrderMessage.php +++ b/src/Support/HigherOrderMessage.php @@ -4,6 +4,8 @@ declare(strict_types=1); namespace Pest\Support; +use Closure; +use const PHP_MAJOR_VERSION; use ReflectionClass; use Throwable; @@ -50,6 +52,13 @@ final class HigherOrderMessage */ public $arguments; + /** + * An optional condition that will determine if the message will be executed. + * + * @var callable|null + */ + public $condition = null; + /** * Creates a new higher order message. * @@ -70,6 +79,11 @@ final class HigherOrderMessage */ public function call(object $target) { + /* @phpstan-ignore-next-line */ + if (is_callable($this->condition) && call_user_func(Closure::bind($this->condition, $target)) === false) { + return $target; + } + try { return Reflection::call($target, $this->methodName, $this->arguments); } catch (Throwable $throwable) { @@ -88,9 +102,16 @@ final class HigherOrderMessage } } + public function when(callable $condition): self + { + $this->condition = $condition; + + return $this; + } + private static function getUndefinedMethodMessage(object $target, string $methodName): string { - if (\PHP_MAJOR_VERSION >= 8) { + if (PHP_MAJOR_VERSION >= 8) { return sprintf(sprintf(self::UNDEFINED_METHOD, sprintf('%s::%s()', get_class($target), $methodName))); } diff --git a/src/Support/HigherOrderMessageCollection.php b/src/Support/HigherOrderMessageCollection.php index f16765e1..4c6e9cd2 100644 --- a/src/Support/HigherOrderMessageCollection.php +++ b/src/Support/HigherOrderMessageCollection.php @@ -24,6 +24,16 @@ final class HigherOrderMessageCollection $this->messages[] = new HigherOrderMessage($filename, $line, $methodName, $arguments); } + /** + * Adds a new higher order message to the collection if the callable condition is does not return false. + * + * @param array $arguments + */ + public function addWhen(callable $condition, string $filename, int $line, string $methodName, array $arguments): void + { + $this->messages[] = (new HigherOrderMessage($filename, $line, $methodName, $arguments))->when($condition); + } + /** * Proxy all the messages starting from the target. */ diff --git a/tests/Features/Skip.php b/tests/Features/Skip.php index 66d6fe62..9102673b 100644 --- a/tests/Features/Skip.php +++ b/tests/Features/Skip.php @@ -1,5 +1,9 @@ shouldSkip = true; +}); + it('do not skips') ->skip(false) ->assertTrue(true); @@ -31,3 +35,7 @@ it('skips with condition and message') it('skips when skip after assertion') ->assertTrue(true) ->skip(); + +it('can use something in the test case as a condition') + ->skip(function () { return $this->shouldSkip; }, 'This test was skipped') + ->assertTrue(false); From fa3959db17c6b66b31116d902a6794b10d12bf0a Mon Sep 17 00:00:00 2001 From: luke Date: Thu, 8 Jul 2021 13:12:30 +0100 Subject: [PATCH 07/31] Type hints for callable --- src/Support/HigherOrderMessage.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Support/HigherOrderMessage.php b/src/Support/HigherOrderMessage.php index 4479b21d..952acf54 100644 --- a/src/Support/HigherOrderMessage.php +++ b/src/Support/HigherOrderMessage.php @@ -55,7 +55,7 @@ final class HigherOrderMessage /** * An optional condition that will determine if the message will be executed. * - * @var callable|null + * @var callable(): bool|null */ public $condition = null; @@ -102,6 +102,11 @@ final class HigherOrderMessage } } + /** + * Indicates that this message should only be called when the given condition is true. + * + * @param callable(): bool $condition + */ public function when(callable $condition): self { $this->condition = $condition; From e45c4ff4f1daaeb1b027c04fcfaf4591158f4034 Mon Sep 17 00:00:00 2001 From: luke Date: Thu, 8 Jul 2021 17:30:39 +0100 Subject: [PATCH 08/31] Refactors HigherOrderMessage --- src/Support/HigherOrderMessage.php | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/Support/HigherOrderMessage.php b/src/Support/HigherOrderMessage.php index 5c5ddd07..2a51b7ba 100644 --- a/src/Support/HigherOrderMessage.php +++ b/src/Support/HigherOrderMessage.php @@ -70,8 +70,9 @@ final class HigherOrderMessage */ public function call(object $target) { - if (($value = $this->retrieveHigherOrderCallable($target)) !== null) { - return $value; + if ($this->hasHigherOrderCallable()) { + /* @phpstan-ignore-next-line */ + return (new HigherOrderCallables($target))->{$this->methodName}(...$this->arguments); } try { @@ -93,18 +94,13 @@ final class HigherOrderMessage } /** - * Attempts to call one of the available Higher Order callables if it exists. + * Determines whether or not there exists a higher order callable with the message name. * - * @return mixed|null + * @return bool */ - private function retrieveHigherOrderCallable(object $target) + private function hasHigherOrderCallable() { - if (in_array($this->methodName, get_class_methods(HigherOrderCallables::class), true)) { - /* @phpstan-ignore-next-line */ - return (new HigherOrderCallables($target))->{$this->methodName}(...$this->arguments); - } - - return null; + return in_array($this->methodName, get_class_methods(HigherOrderCallables::class), true); } private static function getUndefinedMethodMessage(object $target, string $methodName): string From 6ce678d1c276b71c89fa91ab07a0368dd248ae8f Mon Sep 17 00:00:00 2001 From: luke Date: Thu, 8 Jul 2021 17:52:56 +0100 Subject: [PATCH 09/31] Adds an extra test to ensure that skipping takes place before higher order callables. --- tests/Features/Skip.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/Features/Skip.php b/tests/Features/Skip.php index 9102673b..f5d867ca 100644 --- a/tests/Features/Skip.php +++ b/tests/Features/Skip.php @@ -39,3 +39,8 @@ it('skips when skip after assertion') it('can use something in the test case as a condition') ->skip(function () { return $this->shouldSkip; }, 'This test was skipped') ->assertTrue(false); + +it('can user higher order callables and skip') + ->skip(function () { return $this->shouldSkip; }) + ->expect(function () { return $this->shouldSkip; }) + ->toBeFalse(); From 7d6a86adc7fb2d07323e1d4b61514a4253404272 Mon Sep 17 00:00:00 2001 From: luke Date: Thu, 8 Jul 2021 18:11:02 +0100 Subject: [PATCH 10/31] docs: update changelog --- CHANGELOG.md | 5 +++++ src/Pest.php | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d8a53e4..d6c0f324 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [v1.8.0 (2021-07-08)](https://github.com/pestphp/pest/compare/v1.7.1...v1.8.0) +### Added +- A new `tap` and test case aware `expect` methods for higher order tests ([#331](https://github.com/pestphp/pest/pull/331)) +- Access to test case methods and properties when using `skip` ([#338](https://github.com/pestphp/pest/pull/338)) + ## [v1.7.1 (2021-06-24)](https://github.com/pestphp/pest/compare/v1.7.0...v1.7.1) ### Fixed - The `and` method not being usable in Higher Order expectations ([#330](https://github.com/pestphp/pest/pull/330)) diff --git a/src/Pest.php b/src/Pest.php index d54a4413..069a71d0 100644 --- a/src/Pest.php +++ b/src/Pest.php @@ -6,7 +6,7 @@ namespace Pest; function version(): string { - return '1.7.1'; + return '1.8.0'; } function testDirectory(string $file = ''): string From 99ea9f42e585a13013ece7f28e9ce6f31211c62a Mon Sep 17 00:00:00 2001 From: luke Date: Thu, 8 Jul 2021 18:32:02 +0100 Subject: [PATCH 11/31] Allows you to just specify an exception message when calling `throws`. --- src/PendingObjects/TestCall.php | 10 +++++++--- tests/Features/Exceptions.php | 4 ++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/PendingObjects/TestCall.php b/src/PendingObjects/TestCall.php index 41d85826..4ad60bde 100644 --- a/src/PendingObjects/TestCall.php +++ b/src/PendingObjects/TestCall.php @@ -61,9 +61,13 @@ final class TestCall */ public function throws(string $exceptionClass, string $exceptionMessage = null): TestCall { - $this->testCaseFactory - ->proxies - ->add(Backtrace::file(), Backtrace::line(), 'expectException', [$exceptionClass]); + if (class_exists($exceptionClass)) { + $this->testCaseFactory + ->proxies + ->add(Backtrace::file(), Backtrace::line(), 'expectException', [$exceptionClass]); + } else { + $exceptionMessage = $exceptionClass; + } if (is_string($exceptionMessage)) { $this->testCaseFactory diff --git a/tests/Features/Exceptions.php b/tests/Features/Exceptions.php index 5e7e51a9..37eaaeb9 100644 --- a/tests/Features/Exceptions.php +++ b/tests/Features/Exceptions.php @@ -13,3 +13,7 @@ it('catch exceptions', function () { it('catch exceptions and messages', function () { throw new Exception('Something bad happened'); })->throws(Exception::class, 'Something bad happened'); + +it('can just define the message', function () { + throw new Exception('Something bad happened'); +})->throws('Something bad happened'); From dd05452eddc4e7ca761653c6168067f19fdef0bc Mon Sep 17 00:00:00 2001 From: luke Date: Thu, 8 Jul 2021 18:39:09 +0100 Subject: [PATCH 12/31] Renames a property to be more inclusive. --- src/PendingObjects/TestCall.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/PendingObjects/TestCall.php b/src/PendingObjects/TestCall.php index 4ad60bde..81349be1 100644 --- a/src/PendingObjects/TestCall.php +++ b/src/PendingObjects/TestCall.php @@ -59,14 +59,14 @@ final class TestCall /** * Asserts that the test throws the given `$exceptionClass` when called. */ - public function throws(string $exceptionClass, string $exceptionMessage = null): TestCall + public function throws(string $exception, string $exceptionMessage = null): TestCall { - if (class_exists($exceptionClass)) { + if (class_exists($exception)) { $this->testCaseFactory ->proxies - ->add(Backtrace::file(), Backtrace::line(), 'expectException', [$exceptionClass]); + ->add(Backtrace::file(), Backtrace::line(), 'expectException', [$exception]); } else { - $exceptionMessage = $exceptionClass; + $exceptionMessage = $exception; } if (is_string($exceptionMessage)) { From e4e9cb09e41c05b0d8ff50ec3c432daaa354695d Mon Sep 17 00:00:00 2001 From: luke Date: Fri, 9 Jul 2021 09:15:22 +0100 Subject: [PATCH 13/31] docs: update changelog --- CHANGELOG.md | 4 ++++ src/Pest.php | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6c0f324..a1a96255 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [v1.9.0 (2021-07-09)](https://github.com/pestphp/pest/compare/v1.8.0...v1.9.0) +### Changed +- You may now pass just an exception message when using the `throws` method ([#339](https://github.com/pestphp/pest/pull/339)) + ## [v1.8.0 (2021-07-08)](https://github.com/pestphp/pest/compare/v1.7.1...v1.8.0) ### Added - A new `tap` and test case aware `expect` methods for higher order tests ([#331](https://github.com/pestphp/pest/pull/331)) diff --git a/src/Pest.php b/src/Pest.php index 069a71d0..fa8f2242 100644 --- a/src/Pest.php +++ b/src/Pest.php @@ -6,7 +6,7 @@ namespace Pest; function version(): string { - return '1.8.0'; + return '1.9.0'; } function testDirectory(string $file = ''): string From 9c202fa2d74d11149c2171c04ddb48e8b45edbca Mon Sep 17 00:00:00 2001 From: luke Date: Fri, 9 Jul 2021 16:07:37 +0100 Subject: [PATCH 14/31] Improves type-hinting for tap method --- src/Support/HigherOrderCallables.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Support/HigherOrderCallables.php b/src/Support/HigherOrderCallables.php index 46503e67..a6ecccf3 100644 --- a/src/Support/HigherOrderCallables.php +++ b/src/Support/HigherOrderCallables.php @@ -5,6 +5,8 @@ declare(strict_types=1); namespace Pest\Support; use Pest\Expectation; +use Pest\PendingObjects\TestCall; +use PHPUnit\Framework\TestCase; /** * @internal @@ -50,11 +52,9 @@ final class HigherOrderCallables } /** - * @template TValue + * Tap into the test case to perform an action and return the test case. * - * @param callable(): TValue $callable - * - * @return TValue|object + * @return TestCall|TestCase|object */ public function tap(callable $callable) { From 50ece576a715950cd8698942058d4e51067faed4 Mon Sep 17 00:00:00 2001 From: luke Date: Fri, 9 Jul 2021 16:09:53 +0100 Subject: [PATCH 15/31] Improves type-hinting for target in HigherOrderTapProxy --- src/Support/HigherOrderTapProxy.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Support/HigherOrderTapProxy.php b/src/Support/HigherOrderTapProxy.php index 4b5664d3..3c4f3968 100644 --- a/src/Support/HigherOrderTapProxy.php +++ b/src/Support/HigherOrderTapProxy.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace Pest\Support; +use PHPUnit\Framework\TestCase; use ReflectionClass; use Throwable; @@ -17,16 +18,14 @@ final class HigherOrderTapProxy /** * The target being tapped. * - * @var mixed + * @var TestCase */ public $target; /** * Create a new tap proxy instance. - * - * @param mixed $target */ - public function __construct($target) + public function __construct(TestCase $target) { $this->target = $target; } From 2a8de0565f16a8a72659b183fb8ae89c3b235851 Mon Sep 17 00:00:00 2001 From: luke Date: Fri, 9 Jul 2021 16:50:15 +0100 Subject: [PATCH 16/31] Adds support for Higher Order Expectations in Higher Order Tests --- src/PendingObjects/TestCall.php | 22 ++++++++++++++++- src/Support/HigherOrderMessage.php | 24 ++++++++++--------- src/Support/HigherOrderMessageCollection.php | 12 +++++----- tests/Features/Expect/HigherOrder/methods.php | 7 ++++++ .../HigherOrder/methodsAndProperties.php | 15 ++++++++++++ .../Expect/HigherOrder/properties.php | 5 ++++ 6 files changed, 67 insertions(+), 18 deletions(-) diff --git a/src/PendingObjects/TestCall.php b/src/PendingObjects/TestCall.php index 81349be1..81bf9243 100644 --- a/src/PendingObjects/TestCall.php +++ b/src/PendingObjects/TestCall.php @@ -155,12 +155,30 @@ final class TestCall return $this; } + /** + * Saves the property accessors to be used on the target. + */ + public function __get(string $name): self + { + return $this->addChain($name); + } + /** * Saves the calls to be used on the target. * * @param array $arguments */ public function __call(string $name, array $arguments): self + { + return $this->addChain($name, $arguments); + } + + /** + * Add a chain to the test case factory. Omitting the arguments will treat it as a property accessor. + * + * @param array|null $arguments + */ + private function addChain(string $name, array $arguments = null): self { $this->testCaseFactory ->chains @@ -171,7 +189,9 @@ final class TestCall if ($this->testCaseFactory->description !== null) { $this->testCaseFactory->description .= ' → '; } - $this->testCaseFactory->description .= sprintf('%s %s', $name, $exporter->shortenedRecursiveExport($arguments)); + $this->testCaseFactory->description .= $arguments === null + ? $name + : sprintf('%s %s', $name, $exporter->shortenedRecursiveExport($arguments)); } return $this; diff --git a/src/Support/HigherOrderMessage.php b/src/Support/HigherOrderMessage.php index 78820dc3..67993bc5 100644 --- a/src/Support/HigherOrderMessage.php +++ b/src/Support/HigherOrderMessage.php @@ -34,18 +34,18 @@ final class HigherOrderMessage public $line; /** - * The method name. + * The method or property name to access. * * @readonly * * @var string */ - public $methodName; + public $name; /** * The arguments. * - * @var array + * @var array|null * * @readonly */ @@ -61,13 +61,13 @@ final class HigherOrderMessage /** * Creates a new higher order message. * - * @param array $arguments + * @param array|null $arguments */ - public function __construct(string $filename, int $line, string $methodName, array $arguments) + public function __construct(string $filename, int $line, string $methodName, $arguments) { $this->filename = $filename; $this->line = $line; - $this->methodName = $methodName; + $this->name = $methodName; $this->arguments = $arguments; } @@ -85,21 +85,23 @@ final class HigherOrderMessage if ($this->hasHigherOrderCallable()) { /* @phpstan-ignore-next-line */ - return (new HigherOrderCallables($target))->{$this->methodName}(...$this->arguments); + return (new HigherOrderCallables($target))->{$this->name}(...$this->arguments); } try { - return Reflection::call($target, $this->methodName, $this->arguments); + return is_array($this->arguments) + ? Reflection::call($target, $this->name, $this->arguments) + : $target->{$this->name}; /* @phpstan-ignore-line */ } catch (Throwable $throwable) { Reflection::setPropertyValue($throwable, 'file', $this->filename); Reflection::setPropertyValue($throwable, 'line', $this->line); - if ($throwable->getMessage() === self::getUndefinedMethodMessage($target, $this->methodName)) { + if ($throwable->getMessage() === self::getUndefinedMethodMessage($target, $this->name)) { /** @var ReflectionClass $reflection */ $reflection = new ReflectionClass($target); /* @phpstan-ignore-next-line */ $reflection = $reflection->getParentClass() ?: $reflection; - Reflection::setPropertyValue($throwable, 'message', sprintf('Call to undefined method %s::%s()', $reflection->getName(), $this->methodName)); + Reflection::setPropertyValue($throwable, 'message', sprintf('Call to undefined method %s::%s()', $reflection->getName(), $this->name)); } throw $throwable; @@ -125,7 +127,7 @@ final class HigherOrderMessage */ private function hasHigherOrderCallable() { - return in_array($this->methodName, get_class_methods(HigherOrderCallables::class), true); + return in_array($this->name, get_class_methods(HigherOrderCallables::class), true); } private static function getUndefinedMethodMessage(object $target, string $methodName): string diff --git a/src/Support/HigherOrderMessageCollection.php b/src/Support/HigherOrderMessageCollection.php index 4c6e9cd2..b107bdba 100644 --- a/src/Support/HigherOrderMessageCollection.php +++ b/src/Support/HigherOrderMessageCollection.php @@ -17,21 +17,21 @@ final class HigherOrderMessageCollection /** * Adds a new higher order message to the collection. * - * @param array $arguments + * @param array|null $arguments */ - public function add(string $filename, int $line, string $methodName, array $arguments): void + public function add(string $filename, int $line, string $name, array $arguments = null): void { - $this->messages[] = new HigherOrderMessage($filename, $line, $methodName, $arguments); + $this->messages[] = new HigherOrderMessage($filename, $line, $name, $arguments); } /** * Adds a new higher order message to the collection if the callable condition is does not return false. * - * @param array $arguments + * @param array|null $arguments */ - public function addWhen(callable $condition, string $filename, int $line, string $methodName, array $arguments): void + public function addWhen(callable $condition, string $filename, int $line, string $name, array $arguments = null): void { - $this->messages[] = (new HigherOrderMessage($filename, $line, $methodName, $arguments))->when($condition); + $this->messages[] = (new HigherOrderMessage($filename, $line, $name, $arguments))->when($condition); } /** diff --git a/tests/Features/Expect/HigherOrder/methods.php b/tests/Features/Expect/HigherOrder/methods.php index 66329b73..d6da636b 100644 --- a/tests/Features/Expect/HigherOrder/methods.php +++ b/tests/Features/Expect/HigherOrder/methods.php @@ -67,6 +67,13 @@ it('can handle nested method calls', function () { ->books()->each->toBeArray(); }); +it('works with higher order tests') + ->expect(new HasMethods()) + ->newInstance()->newInstance()->name()->toEqual('Has Methods')->toBeString() + ->newInstance()->name()->toEqual('Has Methods')->not->toBeArray + ->name()->toEqual('Has Methods') + ->books()->each->toBeArray; + class HasMethods { public function name() diff --git a/tests/Features/Expect/HigherOrder/methodsAndProperties.php b/tests/Features/Expect/HigherOrder/methodsAndProperties.php index 08c4a3bc..b98c9f16 100644 --- a/tests/Features/Expect/HigherOrder/methodsAndProperties.php +++ b/tests/Features/Expect/HigherOrder/methodsAndProperties.php @@ -22,6 +22,13 @@ it('can handle nested methods and properties', function () { ->newInstance()->books()->toBeArray(); }); +it('works with higher order tests') + ->expect(new HasMethodsAndProperties()) + ->meta->foo->bar->toBeString()->toEqual('baz')->not->toBeInt + ->newInstance()->meta->foo->toBeArray + ->newInstance()->multiply(2, 2)->toEqual(4)->not->toEqual(5) + ->newInstance()->books()->toBeArray(); + it('can start a new higher order expectation using the and syntax', function () { expect(new HasMethodsAndProperties()) ->toBeInstanceOf(HasMethodsAndProperties::class) @@ -33,6 +40,14 @@ it('can start a new higher order expectation using the and syntax', function () expect(static::getCount())->toEqual(4); }); +it('can start a new higher order expectation using the and syntax in higher order tests') + ->expect(new HasMethodsAndProperties()) + ->toBeInstanceOf(HasMethodsAndProperties::class) + ->meta->toBeArray + ->and(['foo' => 'bar']) + ->toBeArray() + ->foo->toEqual('bar'); + class HasMethodsAndProperties { public $name = 'Has Methods and Properties'; diff --git a/tests/Features/Expect/HigherOrder/properties.php b/tests/Features/Expect/HigherOrder/properties.php index 154d17e4..5595b9ab 100644 --- a/tests/Features/Expect/HigherOrder/properties.php +++ b/tests/Features/Expect/HigherOrder/properties.php @@ -64,6 +64,11 @@ it('works with nested properties', function () { ->posts->toBeArray()->toHaveCount(2); }); +it('works with higher order tests') + ->expect(new HasProperties()) + ->nested->foo->bar->toBeString()->toEqual('baz') + ->posts->toBeArray()->toHaveCount(2); + class HasProperties { public $name = 'foo'; From c160d9742889015ad5c0503eed49580bdcfcb343 Mon Sep 17 00:00:00 2001 From: luke Date: Sun, 11 Jul 2021 07:56:02 +0100 Subject: [PATCH 17/31] Forces higher order test callable expects to be closures. --- src/Support/HigherOrderCallables.php | 3 ++- tests/Features/HigherOrderTests.php | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Support/HigherOrderCallables.php b/src/Support/HigherOrderCallables.php index a6ecccf3..8b4dc817 100644 --- a/src/Support/HigherOrderCallables.php +++ b/src/Support/HigherOrderCallables.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace Pest\Support; +use Closure; use Pest\Expectation; use Pest\PendingObjects\TestCall; use PHPUnit\Framework\TestCase; @@ -34,7 +35,7 @@ final class HigherOrderCallables */ public function expect($value) { - return new Expectation(is_callable($value) ? Reflection::bindCallable($value) : $value); + return new Expectation($value instanceof Closure ? Reflection::bindCallable($value) : $value); } /** diff --git a/tests/Features/HigherOrderTests.php b/tests/Features/HigherOrderTests.php index f871d919..b45568e9 100644 --- a/tests/Features/HigherOrderTests.php +++ b/tests/Features/HigherOrderTests.php @@ -18,6 +18,9 @@ it('resolves expect callables correctly') ->toBeString() ->toBe('bar'); +test('does not treat method names as callables') + ->expect('it')->toBeString(); + it('can tap into the test') ->expect('foo')->toBeString() ->tap(function () { expect($this)->toBeInstanceOf(TestCase::class); }) From eb6de433b7eab300185f8274d8aad9b2ea7a855d Mon Sep 17 00:00:00 2001 From: luke Date: Sun, 11 Jul 2021 09:08:31 +0100 Subject: [PATCH 18/31] docs: update changelog --- CHANGELOG.md | 4 ++++ src/Pest.php | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1a96255..9a6a7c0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [v1.9.1 (2021-07-11)](https://github.com/pestphp/pest/compare/v1.9.0...v1.9.1) +### Fixed +- Callable `expect` values in higher order tests failing if the value was an existing method name ([#334](https://github.com/pestphp/pest/pull/344)) + ## [v1.9.0 (2021-07-09)](https://github.com/pestphp/pest/compare/v1.8.0...v1.9.0) ### Changed - You may now pass just an exception message when using the `throws` method ([#339](https://github.com/pestphp/pest/pull/339)) diff --git a/src/Pest.php b/src/Pest.php index fa8f2242..f3ac5e45 100644 --- a/src/Pest.php +++ b/src/Pest.php @@ -6,7 +6,7 @@ namespace Pest; function version(): string { - return '1.9.0'; + return '1.9.1'; } function testDirectory(string $file = ''): string From d90ddf889cca8acf9f9a7ccbb36c34af8926f082 Mon Sep 17 00:00:00 2001 From: luke Date: Mon, 12 Jul 2021 11:54:40 +0100 Subject: [PATCH 19/31] docs: update changelog --- CHANGELOG.md | 4 ++++ src/Pest.php | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a6a7c0a..e602ee99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [v1.10.0 (2021-07-12)](https://github.com/pestphp/pest/compare/v1.9.1...v1.10.0) +### Added +- The ability to use higher order expectations inside higher order tests ([#341](https://github.com/pestphp/pest/pull/341)) + ## [v1.9.1 (2021-07-11)](https://github.com/pestphp/pest/compare/v1.9.0...v1.9.1) ### Fixed - Callable `expect` values in higher order tests failing if the value was an existing method name ([#334](https://github.com/pestphp/pest/pull/344)) diff --git a/src/Pest.php b/src/Pest.php index f3ac5e45..e694346c 100644 --- a/src/Pest.php +++ b/src/Pest.php @@ -6,7 +6,7 @@ namespace Pest; function version(): string { - return '1.9.1'; + return '1.10.0'; } function testDirectory(string $file = ''): string From bbe444525715593e98b64d2b7d28dcf36e479981 Mon Sep 17 00:00:00 2001 From: Joni Danino Date: Fri, 16 Jul 2021 12:40:57 +0200 Subject: [PATCH 20/31] Fix the unit test stub --- stubs/Unit.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stubs/Unit.php b/stubs/Unit.php index 0f429e88..2349e27c 100644 --- a/stubs/Unit.php +++ b/stubs/Unit.php @@ -1,5 +1,5 @@ assertTrue(true); }); From 7ddcc03ad9e7e7f5fb7ffc17fb26f1ea883bbd6c Mon Sep 17 00:00:00 2001 From: Nuno Maduro Date: Fri, 16 Jul 2021 13:00:32 +0100 Subject: [PATCH 21/31] Update stubs/Unit.php Co-authored-by: Owen Voke --- stubs/Unit.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stubs/Unit.php b/stubs/Unit.php index 2349e27c..8c2702d6 100644 --- a/stubs/Unit.php +++ b/stubs/Unit.php @@ -1,5 +1,5 @@ assertTrue(true); + expect(true)->toBeTrue(); }); From 164bad437a2496a79932de85f4d000e2ae4b8271 Mon Sep 17 00:00:00 2001 From: luke Date: Fri, 16 Jul 2021 13:10:30 +0100 Subject: [PATCH 22/31] Fixes the assertion output showing as 0 in the TeamCity logger. --- src/Logging/TeamCity.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Logging/TeamCity.php b/src/Logging/TeamCity.php index fded41e4..c482836c 100644 --- a/src/Logging/TeamCity.php +++ b/src/Logging/TeamCity.php @@ -4,6 +4,8 @@ declare(strict_types=1); namespace Pest\Logging; +use PHPUnit\Framework\TestCase; +use PHPUnit\Runner\PhptTestCase; use function getmypid; use Pest\Concerns\Testable; use PHPUnit\Framework\AssertionFailedError; @@ -137,6 +139,12 @@ final class TeamCity extends DefaultResultPrinter return; } + if ($test instanceof TestCase) { + $this->numAssertions += $test->getNumAssertions(); + } elseif ($test instanceof PhptTestCase) { + $this->numAssertions++; + } + $this->printEvent('testFinished', [ self::NAME => $test->getName(), self::DURATION => self::toMilliseconds($time), From 13781dcd1437297f1b1e3cd382af494e2e622310 Mon Sep 17 00:00:00 2001 From: luke Date: Fri, 16 Jul 2021 13:17:33 +0100 Subject: [PATCH 23/31] Fixes the assertion output showing as 0 in the TeamCity logger. --- src/Logging/TeamCity.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Logging/TeamCity.php b/src/Logging/TeamCity.php index c482836c..14704aab 100644 --- a/src/Logging/TeamCity.php +++ b/src/Logging/TeamCity.php @@ -4,15 +4,15 @@ declare(strict_types=1); namespace Pest\Logging; -use PHPUnit\Framework\TestCase; -use PHPUnit\Runner\PhptTestCase; use function getmypid; use Pest\Concerns\Testable; use PHPUnit\Framework\AssertionFailedError; use PHPUnit\Framework\Test; +use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestResult; use PHPUnit\Framework\TestSuite; use PHPUnit\Framework\Warning; +use PHPUnit\Runner\PhptTestCase; use PHPUnit\TextUI\DefaultResultPrinter; use function round; use function str_replace; From 771b5b2e53a2979169d7969194b1158c108de921 Mon Sep 17 00:00:00 2001 From: Nuno Maduro Date: Fri, 16 Jul 2021 22:12:19 +0100 Subject: [PATCH 24/31] Adds Spatie --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 765fcafe..d3e3f16c 100644 --- a/README.md +++ b/README.md @@ -21,8 +21,9 @@ We would like to extend our thanks to the following sponsors for funding Pest de ### Premium Sponsors -- **[Scout APM](https://scoutapm.com)** - **[Akaunting](https://akaunting.com)** +- **[Scout APM](https://scoutapm.com)** - **[Meema](https://meema.io/)** - +- **[Spatie](https://spatie.be/)** +- Pest was created by **[Nuno Maduro](https://twitter.com/enunomaduro)** under the **[Sponsorware license](https://github.com/sponsorware/docs)**. It got open-sourced and is now licensed under the **[MIT license](https://opensource.org/licenses/MIT)**. From 47ceb2419bd1e3211b2a212e4168becaece5e58e Mon Sep 17 00:00:00 2001 From: Nuno Maduro Date: Fri, 16 Jul 2021 22:12:31 +0100 Subject: [PATCH 25/31] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d3e3f16c..6823ffee 100644 --- a/README.md +++ b/README.md @@ -25,5 +25,5 @@ We would like to extend our thanks to the following sponsors for funding Pest de - **[Scout APM](https://scoutapm.com)** - **[Meema](https://meema.io/)** - **[Spatie](https://spatie.be/)** -- + Pest was created by **[Nuno Maduro](https://twitter.com/enunomaduro)** under the **[Sponsorware license](https://github.com/sponsorware/docs)**. It got open-sourced and is now licensed under the **[MIT license](https://opensource.org/licenses/MIT)**. From 371620d16147e1e562a1c65e2b1f2912d06a02c1 Mon Sep 17 00:00:00 2001 From: luke Date: Wed, 21 Jul 2021 07:40:19 +0100 Subject: [PATCH 26/31] Adds support for receiving datasets in higher order tests --- src/Support/HigherOrderCallables.php | 4 ++-- src/Support/Reflection.php | 15 +++++++++++++++ tests/Features/HigherOrderTests.php | 9 +++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/Support/HigherOrderCallables.php b/src/Support/HigherOrderCallables.php index 8b4dc817..b3bb633e 100644 --- a/src/Support/HigherOrderCallables.php +++ b/src/Support/HigherOrderCallables.php @@ -35,7 +35,7 @@ final class HigherOrderCallables */ public function expect($value) { - return new Expectation($value instanceof Closure ? Reflection::bindCallable($value) : $value); + return new Expectation($value instanceof Closure ? Reflection::bindCallableWithData($value) : $value); } /** @@ -59,7 +59,7 @@ final class HigherOrderCallables */ public function tap(callable $callable) { - Reflection::bindCallable($callable); + Reflection::bindCallableWithData($callable); return $this->target; } diff --git a/src/Support/Reflection.php b/src/Support/Reflection.php index fbe7ba40..e06b0280 100644 --- a/src/Support/Reflection.php +++ b/src/Support/Reflection.php @@ -60,6 +60,21 @@ final class Reflection return Closure::fromCallable($callable)->bindTo(TestSuite::getInstance()->test)(...$args); } + /** + * Bind a callable to the TestCase and return the result, + * passing in the current dataset values as arguments. + * + * @return mixed + */ + public static function bindCallableWithData(callable $callable) + { + $test = TestSuite::getInstance()->test; + + return $test === null + ? static::bindCallable($callable) + : Closure::fromCallable($callable)->bindTo($test)(...$test->getProvidedData()); + } + /** * Infers the file name from the given closure. */ diff --git a/tests/Features/HigherOrderTests.php b/tests/Features/HigherOrderTests.php index b45568e9..ba716f17 100644 --- a/tests/Features/HigherOrderTests.php +++ b/tests/Features/HigherOrderTests.php @@ -27,4 +27,13 @@ it('can tap into the test') ->toBe('foo') ->and('hello world')->toBeString(); +it('can pass datasets into the expect callables') + ->with([[1, 2, 3]]) + ->expect(function (...$numbers) { return $numbers; })->toBe([1, 2, 3]) + ->and(function (...$numbers) { return $numbers; })->toBe([1, 2, 3]); + +it('can pass datasets into the tap callable') + ->with([[1, 2, 3]]) + ->tap(function (...$numbers) { expect($numbers)->toBe([1, 2, 3]); }); + afterEach()->assertTrue(true); From 3bdba9210d19575bec6613f3af430ba72fbd0e3a Mon Sep 17 00:00:00 2001 From: luke Date: Wed, 21 Jul 2021 07:44:05 +0100 Subject: [PATCH 27/31] Adds another test --- tests/Features/HigherOrderTests.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/Features/HigherOrderTests.php b/tests/Features/HigherOrderTests.php index ba716f17..e2ff0686 100644 --- a/tests/Features/HigherOrderTests.php +++ b/tests/Features/HigherOrderTests.php @@ -36,4 +36,11 @@ it('can pass datasets into the tap callable') ->with([[1, 2, 3]]) ->tap(function (...$numbers) { expect($numbers)->toBe([1, 2, 3]); }); +it('can pass shared datasets into callables') + ->with('numbers.closure.wrapped') + ->expect(function ($value) { return $value; }) + ->and(function ($value) { return $value; }) + ->tap(function ($value) { expect($value)->toBeInt(); }) + ->toBeInt(); + afterEach()->assertTrue(true); From 82c18d38486fa16042efd9f2f7b2d77d07d0e2db Mon Sep 17 00:00:00 2001 From: luke Date: Wed, 21 Jul 2021 07:58:05 +0100 Subject: [PATCH 28/31] Type fixes --- src/Support/Reflection.php | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/Support/Reflection.php b/src/Support/Reflection.php index e06b0280..819ad4a5 100644 --- a/src/Support/Reflection.php +++ b/src/Support/Reflection.php @@ -109,10 +109,6 @@ final class Reflection } } - if ($reflectionProperty === null) { - throw ShouldNotHappen::fromMessage('Reflection property not found.'); - } - $reflectionProperty->setAccessible(true); return $reflectionProperty->getValue($object); @@ -143,10 +139,6 @@ final class Reflection } } - if ($reflectionProperty === null) { - throw ShouldNotHappen::fromMessage('Reflection property not found.'); - } - $reflectionProperty->setAccessible(true); $reflectionProperty->setValue($object, $value); } From 09682dd393225c9d1cb29b9439ec500531c09dfc Mon Sep 17 00:00:00 2001 From: luke Date: Wed, 21 Jul 2021 08:16:54 +0100 Subject: [PATCH 29/31] Alters test to prove order doesn't matter --- tests/Features/HigherOrderTests.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Features/HigherOrderTests.php b/tests/Features/HigherOrderTests.php index e2ff0686..5505c8a0 100644 --- a/tests/Features/HigherOrderTests.php +++ b/tests/Features/HigherOrderTests.php @@ -37,10 +37,10 @@ it('can pass datasets into the tap callable') ->tap(function (...$numbers) { expect($numbers)->toBe([1, 2, 3]); }); it('can pass shared datasets into callables') - ->with('numbers.closure.wrapped') ->expect(function ($value) { return $value; }) ->and(function ($value) { return $value; }) ->tap(function ($value) { expect($value)->toBeInt(); }) - ->toBeInt(); + ->toBeInt() + ->with('numbers.closure.wrapped'); afterEach()->assertTrue(true); From 4c8c42cd203dd14de90b4a5d3169d2a5147ec0c3 Mon Sep 17 00:00:00 2001 From: luke Date: Wed, 21 Jul 2021 08:47:55 +0100 Subject: [PATCH 30/31] Refactor --- tests/Features/HigherOrderTests.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Features/HigherOrderTests.php b/tests/Features/HigherOrderTests.php index 5505c8a0..e2ff0686 100644 --- a/tests/Features/HigherOrderTests.php +++ b/tests/Features/HigherOrderTests.php @@ -37,10 +37,10 @@ it('can pass datasets into the tap callable') ->tap(function (...$numbers) { expect($numbers)->toBe([1, 2, 3]); }); it('can pass shared datasets into callables') + ->with('numbers.closure.wrapped') ->expect(function ($value) { return $value; }) ->and(function ($value) { return $value; }) ->tap(function ($value) { expect($value)->toBeInt(); }) - ->toBeInt() - ->with('numbers.closure.wrapped'); + ->toBeInt(); afterEach()->assertTrue(true); From 328427bfdb1c21687afff0eb83c64e417b4539c6 Mon Sep 17 00:00:00 2001 From: luke Date: Wed, 21 Jul 2021 12:59:45 +0100 Subject: [PATCH 31/31] docs: update changelog --- CHANGELOG.md | 10 ++++++++++ src/Pest.php | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e602ee99..51343a9f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [v1.11.0 (2021-07-21)](https://github.com/pestphp/pest/compare/v1.10.0...v1.11.0) +### Added +- Support for interacting with datasets in higher order tests ([#352](https://github.com/pestphp/pest/pull/352)) + +### Changed +- The unit test stub now uses the expectation API ([#348](https://github.com/pestphp/pest/pull/348)) + +### Fixed +- PhpStorm will no longer show 0 assertions in the output ([#349](https://github.com/pestphp/pest/pull/349)) + ## [v1.10.0 (2021-07-12)](https://github.com/pestphp/pest/compare/v1.9.1...v1.10.0) ### Added - The ability to use higher order expectations inside higher order tests ([#341](https://github.com/pestphp/pest/pull/341)) diff --git a/src/Pest.php b/src/Pest.php index e694346c..cdc57677 100644 --- a/src/Pest.php +++ b/src/Pest.php @@ -6,7 +6,7 @@ namespace Pest; function version(): string { - return '1.10.0'; + return '1.11.0'; } function testDirectory(string $file = ''): string