From 0c57142c03a796975a353f92237fb2f083bb8059 Mon Sep 17 00:00:00 2001 From: jshayes Date: Fri, 11 Oct 2024 21:24:08 -0400 Subject: [PATCH 1/6] Fix an issue where a describe block will prevent a beforeEach call from executing --- src/PendingCalls/DescribeCall.php | 10 ++++++---- tests/.snapshots/success.txt | 3 ++- tests/Features/Describe.php | 12 ++++++++++++ tests/Visual/Parallel.php | 2 +- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/PendingCalls/DescribeCall.php b/src/PendingCalls/DescribeCall.php index 267c875a..4735ecce 100644 --- a/src/PendingCalls/DescribeCall.php +++ b/src/PendingCalls/DescribeCall.php @@ -15,8 +15,10 @@ final class DescribeCall { /** * The current describe call. + * + * @var string[] */ - private static ?string $describing = null; + private static array $describing = []; /** * The describe "before each" call. @@ -40,7 +42,7 @@ final class DescribeCall */ public static function describing(): ?string { - return self::$describing; + return self::$describing[count(self::$describing) - 1] ?? null; } /** @@ -50,12 +52,12 @@ final class DescribeCall { unset($this->currentBeforeEachCall); - self::$describing = $this->description; + self::$describing[] = $this->description; try { ($this->tests)(); } finally { - self::$describing = null; + array_pop(self::$describing); } } diff --git a/tests/.snapshots/success.txt b/tests/.snapshots/success.txt index da75f2d2..d0e4c943 100644 --- a/tests/.snapshots/success.txt +++ b/tests/.snapshots/success.txt @@ -215,6 +215,7 @@ ✓ depends on describe → bar ✓ depends on describe using with → foo with (3) ✓ depends on describe using with → bar with (3) + ✓ with test after describe → it should run the before each PASS Tests\Features\DescriptionLess ✓ get 'foo' @@ -1584,4 +1585,4 @@ WARN Tests\Visual\Version - visual snapshot of help command output - Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 17 todos, 28 skipped, 1095 passed (2648 assertions) \ No newline at end of file + Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 17 todos, 28 skipped, 1096 passed (2649 assertions) \ No newline at end of file diff --git a/tests/Features/Describe.php b/tests/Features/Describe.php index 64bf3453..836b0fc8 100644 --- a/tests/Features/Describe.php +++ b/tests/Features/Describe.php @@ -96,3 +96,15 @@ describe('depends on describe using with', function () { expect($foo + $foo)->toBe(6); })->depends('foo'); })->with([3]); + +describe('with test after describe', function () { + beforeEach(function () { + $this->count++; + }); + + describe('foo', function () {}); + + it('should run the before each', function () { + expect($this->count)->toBe(2); + }); +}); diff --git a/tests/Visual/Parallel.php b/tests/Visual/Parallel.php index 59f7263a..8efb514c 100644 --- a/tests/Visual/Parallel.php +++ b/tests/Visual/Parallel.php @@ -16,7 +16,7 @@ $run = function () { test('parallel', function () use ($run) { expect($run('--exclude-group=integration')) - ->toContain('Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 17 todos, 19 skipped, 1085 passed (2624 assertions)') + ->toContain('Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 17 todos, 19 skipped, 1086 passed (2625 assertions)') ->toContain('Parallel: 3 processes'); })->skipOnWindows(); From a6cd83665cf607ada285426445d4e272b5bdf607 Mon Sep 17 00:00:00 2001 From: jshayes Date: Fri, 11 Oct 2024 23:32:45 -0400 Subject: [PATCH 2/6] Execute all parent beforeEach and afterEach functions for each test --- src/Concerns/Testable.php | 4 +++- src/Factories/TestCaseMethodFactory.php | 6 ++++-- src/Functions.php | 4 ++-- src/PendingCalls/AfterEachCall.php | 2 +- src/PendingCalls/BeforeEachCall.php | 10 +++++----- src/PendingCalls/Concerns/Describable.php | 8 ++++++-- src/PendingCalls/DescribeCall.php | 8 +++++--- src/PendingCalls/TestCall.php | 4 ++-- src/Support/Str.php | 8 ++++++-- tests/.snapshots/success.txt | 5 ++++- tests/Features/AfterEach.php | 22 ++++++++++++++++++++++ tests/Features/BeforeEach.php | 16 ++++++++++++++++ tests/Visual/Parallel.php | 2 +- 13 files changed, 77 insertions(+), 22 deletions(-) diff --git a/src/Concerns/Testable.php b/src/Concerns/Testable.php index 43b7785b..e94e80b7 100644 --- a/src/Concerns/Testable.php +++ b/src/Concerns/Testable.php @@ -61,8 +61,10 @@ trait Testable /** * The test's describing, if any. + * + * @var string[] */ - public ?string $__describing = null; + public array $__describing = []; /** * Whether the test has ran or not. diff --git a/src/Factories/TestCaseMethodFactory.php b/src/Factories/TestCaseMethodFactory.php index 086a9f3e..425d4950 100644 --- a/src/Factories/TestCaseMethodFactory.php +++ b/src/Factories/TestCaseMethodFactory.php @@ -31,8 +31,10 @@ final class TestCaseMethodFactory /** * The test's describing, if any. + * + * @var string[] */ - public ?string $describing = null; + public array $describing = []; /** * The test's description, if any. @@ -201,7 +203,7 @@ final class TestCaseMethodFactory ]; foreach ($this->depends as $depend) { - $depend = Str::evaluable($this->describing !== null ? Str::describe($this->describing, $depend) : $depend); + $depend = Str::evaluable($this->describing === [] ? $depend : Str::describe($this->describing, $depend)); $this->attributes[] = new Attribute( \PHPUnit\Framework\Attributes\Depends::class, diff --git a/src/Functions.php b/src/Functions.php index cdba1d0a..1e12fe7e 100644 --- a/src/Functions.php +++ b/src/Functions.php @@ -43,7 +43,7 @@ if (! function_exists('beforeAll')) { */ function beforeAll(Closure $closure): void { - if (! is_null(DescribeCall::describing())) { + if (DescribeCall::describing() !== []) { $filename = Backtrace::file(); throw new BeforeAllWithinDescribe($filename); @@ -205,7 +205,7 @@ if (! function_exists('afterAll')) { */ function afterAll(Closure $closure): void { - if (! is_null(DescribeCall::describing())) { + if (DescribeCall::describing() !== []) { $filename = Backtrace::file(); throw new AfterAllWithinDescribe($filename); diff --git a/src/PendingCalls/AfterEachCall.php b/src/PendingCalls/AfterEachCall.php index e6c0142d..643ab924 100644 --- a/src/PendingCalls/AfterEachCall.php +++ b/src/PendingCalls/AfterEachCall.php @@ -54,7 +54,7 @@ final class AfterEachCall $proxies = $this->proxies; $afterEachTestCase = ChainableClosure::boundWhen( - fn (): bool => is_null($describing) || $this->__describing === $describing, + fn (): bool => $describing === [] || in_array(end($describing), $this->__describing, true), ChainableClosure::bound(fn () => $proxies->chain($this), $this->closure)->bindTo($this, self::class), // @phpstan-ignore-line )->bindTo($this, self::class); diff --git a/src/PendingCalls/BeforeEachCall.php b/src/PendingCalls/BeforeEachCall.php index 96b7b1b6..4582cbbc 100644 --- a/src/PendingCalls/BeforeEachCall.php +++ b/src/PendingCalls/BeforeEachCall.php @@ -63,12 +63,12 @@ final class BeforeEachCall $beforeEachTestCall = function (TestCall $testCall) use ($describing): void { - if ($this->describing !== null) { - if ($describing !== $this->describing) { + if ($this->describing !== []) { + if (end($describing) !== end($this->describing)) { return; } - if ($describing !== $testCall->describing) { + if (! in_array(end($describing), $testCall->describing, true)) { return; } } @@ -77,7 +77,7 @@ final class BeforeEachCall }; $beforeEachTestCase = ChainableClosure::boundWhen( - fn (): bool => is_null($describing) || $this->__describing === $describing, + fn (): bool => $describing === [] || in_array(end($describing), $this->__describing, true), ChainableClosure::bound(fn () => $testCaseProxies->chain($this), $this->closure)->bindTo($this, self::class), // @phpstan-ignore-line )->bindTo($this, self::class); @@ -96,7 +96,7 @@ final class BeforeEachCall */ public function after(Closure $closure): self { - if ($this->describing === null) { + if ($this->describing === []) { throw new AfterBeforeTestFunction($this->filename); } diff --git a/src/PendingCalls/Concerns/Describable.php b/src/PendingCalls/Concerns/Describable.php index e70bcbb3..b114d15d 100644 --- a/src/PendingCalls/Concerns/Describable.php +++ b/src/PendingCalls/Concerns/Describable.php @@ -11,11 +11,15 @@ trait Describable { /** * Note: this is property is not used; however, it gets added automatically by rector php. + * + * @var string[] */ - public string $__describing; + public array $__describing; /** * The describing of the test case. + * + * @var string[] */ - public ?string $describing = null; + public array $describing = []; } diff --git a/src/PendingCalls/DescribeCall.php b/src/PendingCalls/DescribeCall.php index 4735ecce..decd6451 100644 --- a/src/PendingCalls/DescribeCall.php +++ b/src/PendingCalls/DescribeCall.php @@ -39,10 +39,12 @@ final class DescribeCall /** * What is the current describing. + * + * @return string[] */ - public static function describing(): ?string + public static function describing(): array { - return self::$describing[count(self::$describing) - 1] ?? null; + return self::$describing; } /** @@ -73,7 +75,7 @@ final class DescribeCall if (! $this->currentBeforeEachCall instanceof \Pest\PendingCalls\BeforeEachCall) { $this->currentBeforeEachCall = new BeforeEachCall(TestSuite::getInstance(), $filename); - $this->currentBeforeEachCall->describing = $this->description; + $this->currentBeforeEachCall->describing[] = $this->description; } $this->currentBeforeEachCall->{$name}(...$arguments); // @phpstan-ignore-line diff --git a/src/PendingCalls/TestCall.php b/src/PendingCalls/TestCall.php index c866eb31..a22ff11d 100644 --- a/src/PendingCalls/TestCall.php +++ b/src/PendingCalls/TestCall.php @@ -76,7 +76,7 @@ final class TestCall // @phpstan-ignore-line throw new TestDescriptionMissing($this->filename); } - $description = is_null($this->describing) + $description = $this->describing === [] ? $this->description : Str::describe($this->describing, $this->description); @@ -683,7 +683,7 @@ final class TestCall // @phpstan-ignore-line throw new TestDescriptionMissing($this->filename); } - if (! is_null($this->describing)) { + if ($this->describing !== []) { $this->testCaseMethod->describing = $this->describing; $this->testCaseMethod->description = Str::describe($this->describing, $this->description); } else { diff --git a/src/Support/Str.php b/src/Support/Str.php index 754749e7..570d58ea 100644 --- a/src/Support/Str.php +++ b/src/Support/Str.php @@ -103,10 +103,14 @@ final class Str /** * Creates a describe block as `$describeDescription` → `$testDescription` format. + * + * @param string[] $describeDescriptions */ - public static function describe(string $describeDescription, string $testDescription): string + public static function describe(array $describeDescriptions, string $testDescription): string { - return sprintf('`%s` → %s', $describeDescription, $testDescription); + $descriptionComponents = [...$describeDescriptions, $testDescription]; + + return sprintf(str_repeat('`%s` → ', count($describeDescriptions)).'%s', ...$descriptionComponents); } /** diff --git a/tests/.snapshots/success.txt b/tests/.snapshots/success.txt index d0e4c943..50b7226b 100644 --- a/tests/.snapshots/success.txt +++ b/tests/.snapshots/success.txt @@ -27,6 +27,8 @@ PASS Tests\Features\AfterEach ✓ it does not get executed before the test ✓ it gets executed after the test + ✓ outer → inner → it does not get executed before the test + ✓ outer → inner → it should call all parent afterEach functions PASS Tests\Features\Assignee ✓ it may be associated with an assignee [@nunomaduro, @taylorotwell] @@ -40,6 +42,7 @@ PASS Tests\Features\BeforeEach ✓ it gets executed before each test ✓ it gets executed before each test once again + ✓ outer → inner → it should call all parent beforeEach functions PASS Tests\Features\BeforeEachProxiesToTestCallWithExpectations ✓ runs 1 @@ -1585,4 +1588,4 @@ WARN Tests\Visual\Version - visual snapshot of help command output - Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 17 todos, 28 skipped, 1096 passed (2649 assertions) \ No newline at end of file + Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 17 todos, 28 skipped, 1099 passed (2656 assertions) \ No newline at end of file diff --git a/tests/Features/AfterEach.php b/tests/Features/AfterEach.php index 217eaf8d..ea0dd7ea 100644 --- a/tests/Features/AfterEach.php +++ b/tests/Features/AfterEach.php @@ -26,3 +26,25 @@ it('gets executed after the test', function () { afterEach(function () { $this->state->bar = 2; }); + +describe('outer', function () { + afterEach(function () { + $this->state->bar++; + }); + + describe('inner', function () { + afterEach(function () { + $this->state->bar++; + }); + + it('does not get executed before the test', function () { + expect($this->state)->toHaveProperty('bar'); + expect($this->state->bar)->toBe(2); + }); + + it('should call all parent afterEach functions', function () { + expect($this->state)->toHaveProperty('bar'); + expect($this->state->bar)->toBe(4); + }); + }); +}); diff --git a/tests/Features/BeforeEach.php b/tests/Features/BeforeEach.php index 7ef6144b..8ce78200 100644 --- a/tests/Features/BeforeEach.php +++ b/tests/Features/BeforeEach.php @@ -25,3 +25,19 @@ it('gets executed before each test once again', function () { beforeEach(function () { $this->bar++; }); + +describe('outer', function () { + beforeEach(function () { + $this->bar++; + }); + + describe('inner', function () { + beforeEach(function () { + $this->bar++; + }); + + it('should call all parent beforeEach functions', function () { + expect($this->bar)->toBe(3); + }); + }); +}); diff --git a/tests/Visual/Parallel.php b/tests/Visual/Parallel.php index 8efb514c..b3de6f5d 100644 --- a/tests/Visual/Parallel.php +++ b/tests/Visual/Parallel.php @@ -16,7 +16,7 @@ $run = function () { test('parallel', function () use ($run) { expect($run('--exclude-group=integration')) - ->toContain('Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 17 todos, 19 skipped, 1086 passed (2625 assertions)') + ->toContain('Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 17 todos, 19 skipped, 1089 passed (2632 assertions)') ->toContain('Parallel: 3 processes'); })->skipOnWindows(); From 7c639cdbbdb112ef24bce80fb0523278d0f9970a Mon Sep 17 00:00:00 2001 From: jshayes Date: Sun, 13 Oct 2024 00:41:04 -0400 Subject: [PATCH 3/6] Add more tests --- tests/.pest/snapshots/Visual/Todo/todo.snap | 8 ++- .../Visual/Todo/todo_in_parallel.snap | 8 ++- tests/.pest/snapshots/Visual/Todo/todos.snap | 8 ++- .../Visual/Todo/todos_in_parallel.snap | 8 ++- tests/.snapshots/success.txt | 58 ++++++++++++++- tests/Features/BeforeEach.php | 10 +++ tests/Features/DatasetsTests.php | 22 ++++++ tests/Features/Depends.php | 36 ++++++++++ tests/Features/Note.php | 16 +++++ tests/Features/Repeat.php | 36 ++++++++++ tests/Features/Skip.php | 70 +++++++++++++++++++ tests/Features/Todo.php | 70 +++++++++++++++++++ tests/Visual/Parallel.php | 2 +- 13 files changed, 341 insertions(+), 11 deletions(-) diff --git a/tests/.pest/snapshots/Visual/Todo/todo.snap b/tests/.pest/snapshots/Visual/Todo/todo.snap index f7a85c93..e9939bf8 100644 --- a/tests/.pest/snapshots/Visual/Todo/todo.snap +++ b/tests/.pest/snapshots/Visual/Todo/todo.snap @@ -15,7 +15,7 @@ ↓ todo on describe → should not fail ↓ todo on describe → should run - TODO Tests\Features\Todo - 7 todos + TODO Tests\Features\Todo - 11 todos ↓ something todo later ↓ something todo later chained ↓ something todo later chained and with function body @@ -24,6 +24,10 @@ ↓ it may have an associated PR #1 ↓ it may have an associated note // a note + ↓ todo on describe → todo block → nested inside todo block → it should not execute + ↓ todo on describe → todo block → it should not execute + ↓ todo on beforeEach → todo block → nested inside todo block → it should not execute + ↓ todo on beforeEach → todo block → it should not execute PASS Tests\CustomTestCase\ChildTest ✓ override method @@ -34,6 +38,6 @@ PASS Tests\CustomTestCase\ParentTest ✓ override method - Tests: 17 todos, 3 passed (3 assertions) + Tests: 21 todos, 3 passed (7 assertions) Duration: x.xxs diff --git a/tests/.pest/snapshots/Visual/Todo/todo_in_parallel.snap b/tests/.pest/snapshots/Visual/Todo/todo_in_parallel.snap index f7a85c93..e9939bf8 100644 --- a/tests/.pest/snapshots/Visual/Todo/todo_in_parallel.snap +++ b/tests/.pest/snapshots/Visual/Todo/todo_in_parallel.snap @@ -15,7 +15,7 @@ ↓ todo on describe → should not fail ↓ todo on describe → should run - TODO Tests\Features\Todo - 7 todos + TODO Tests\Features\Todo - 11 todos ↓ something todo later ↓ something todo later chained ↓ something todo later chained and with function body @@ -24,6 +24,10 @@ ↓ it may have an associated PR #1 ↓ it may have an associated note // a note + ↓ todo on describe → todo block → nested inside todo block → it should not execute + ↓ todo on describe → todo block → it should not execute + ↓ todo on beforeEach → todo block → nested inside todo block → it should not execute + ↓ todo on beforeEach → todo block → it should not execute PASS Tests\CustomTestCase\ChildTest ✓ override method @@ -34,6 +38,6 @@ PASS Tests\CustomTestCase\ParentTest ✓ override method - Tests: 17 todos, 3 passed (3 assertions) + Tests: 21 todos, 3 passed (7 assertions) Duration: x.xxs diff --git a/tests/.pest/snapshots/Visual/Todo/todos.snap b/tests/.pest/snapshots/Visual/Todo/todos.snap index f7a85c93..e9939bf8 100644 --- a/tests/.pest/snapshots/Visual/Todo/todos.snap +++ b/tests/.pest/snapshots/Visual/Todo/todos.snap @@ -15,7 +15,7 @@ ↓ todo on describe → should not fail ↓ todo on describe → should run - TODO Tests\Features\Todo - 7 todos + TODO Tests\Features\Todo - 11 todos ↓ something todo later ↓ something todo later chained ↓ something todo later chained and with function body @@ -24,6 +24,10 @@ ↓ it may have an associated PR #1 ↓ it may have an associated note // a note + ↓ todo on describe → todo block → nested inside todo block → it should not execute + ↓ todo on describe → todo block → it should not execute + ↓ todo on beforeEach → todo block → nested inside todo block → it should not execute + ↓ todo on beforeEach → todo block → it should not execute PASS Tests\CustomTestCase\ChildTest ✓ override method @@ -34,6 +38,6 @@ PASS Tests\CustomTestCase\ParentTest ✓ override method - Tests: 17 todos, 3 passed (3 assertions) + Tests: 21 todos, 3 passed (7 assertions) Duration: x.xxs diff --git a/tests/.pest/snapshots/Visual/Todo/todos_in_parallel.snap b/tests/.pest/snapshots/Visual/Todo/todos_in_parallel.snap index f7a85c93..e9939bf8 100644 --- a/tests/.pest/snapshots/Visual/Todo/todos_in_parallel.snap +++ b/tests/.pest/snapshots/Visual/Todo/todos_in_parallel.snap @@ -15,7 +15,7 @@ ↓ todo on describe → should not fail ↓ todo on describe → should run - TODO Tests\Features\Todo - 7 todos + TODO Tests\Features\Todo - 11 todos ↓ something todo later ↓ something todo later chained ↓ something todo later chained and with function body @@ -24,6 +24,10 @@ ↓ it may have an associated PR #1 ↓ it may have an associated note // a note + ↓ todo on describe → todo block → nested inside todo block → it should not execute + ↓ todo on describe → todo block → it should not execute + ↓ todo on beforeEach → todo block → nested inside todo block → it should not execute + ↓ todo on beforeEach → todo block → it should not execute PASS Tests\CustomTestCase\ChildTest ✓ override method @@ -34,6 +38,6 @@ PASS Tests\CustomTestCase\ParentTest ✓ override method - Tests: 17 todos, 3 passed (3 assertions) + Tests: 21 todos, 3 passed (7 assertions) Duration: x.xxs diff --git a/tests/.snapshots/success.txt b/tests/.snapshots/success.txt index 50b7226b..fbb39a1b 100644 --- a/tests/.snapshots/success.txt +++ b/tests/.snapshots/success.txt @@ -43,6 +43,8 @@ ✓ it gets executed before each test ✓ it gets executed before each test once again ✓ outer → inner → it should call all parent beforeEach functions + ✓ with expectations → nested block → test + ✓ with expectations → test PASS Tests\Features\BeforeEachProxiesToTestCallWithExpectations ✓ runs 1 @@ -181,6 +183,10 @@ ✓ it may be used with high order with dataset "informal" ✓ it may be used with high order even when bound with dataset "formal" ✓ it may be used with high order even when bound with dataset "informal" + ✓ with on nested describe → nested → before inner describe block with (1) + ✓ with on nested describe → nested → describe → it should include the with value from all parent describe blocks with (1) / (2) + ✓ with on nested describe → nested → describe → should include the with value from all parent describe blocks and the test with (1) / (2) / (3) + ✓ with on nested describe → nested → after inner describe block with (1) PASS Tests\Features\Depends ✓ first @@ -191,6 +197,12 @@ ✓ depends run test only once ✓ it asserts true is true ✓ depends works with the correct test name + ✓ describe block → first in describe + ✓ describe block → second in describe + ✓ describe block → third in describe + ✓ describe block → nested describe → first in nested describe + ✓ describe block → nested describe → second in nested describe + ✓ describe block → nested describe → third in nested describe PASS Tests\Features\DependsInheritance ✓ it is a test @@ -1071,9 +1083,22 @@ ✓ nested → it may have static note and runtime note // This is before each static note // This is describe static note + // This is before each describe static note // This is a static note within describe // This is before each runtime note + // This is before each describe runtime note // This is a runtime note within describe + ✓ nested → describe nested within describe → it may have a static note and runtime note + // This is before each static note + // This is describe static note + // This is before each describe static note + // This is a nested describe static note + // This is before each nested describe static note + // This is a static note within a nested describe + // This is before each runtime note + // This is before each describe runtime note + // This is before each nested describe runtime note + // This is a runtime note within a nested describe ✓ multiple notes // This is before each static note // This is before each runtime note @@ -1203,6 +1228,23 @@ ✓ multiple times with repeat iterator with multiple dataset ('c') / ('d') @ repetition 2 of 2 ✓ multiple times with repeat iterator with multiple dataset ('c') / ('e') @ repetition 2 of 2 ✓ multiple times with repeat iterator with multiple dataset ('c') / ('f') @ repetition 2 of 2 + ✓ describe blocks → multiple times @ repetition 1 of 3 + ✓ describe blocks → multiple times @ repetition 2 of 3 + ✓ describe blocks → multiple times @ repetition 3 of 3 + ✓ describe blocks → describe with repeat → test with no repeat should repeat the number of times specified in the parent describe block @ repetition 1 of 3 + ✓ describe blocks → describe with repeat → test with no repeat should repeat the number of times specified in the parent describe block @ repetition 2 of 3 + ✓ describe blocks → describe with repeat → test with no repeat should repeat the number of times specified in the parent describe block @ repetition 3 of 3 + ✓ describe blocks → describe with repeat → test with repeat should repeat the number of times specified in the test @ repetition 1 of 2 + ✓ describe blocks → describe with repeat → test with repeat should repeat the number of times specified in the test @ repetition 2 of 2 + ✓ describe blocks → describe with repeat → nested describe without repeat → test with no repeat should repeat the number of times specified in the parent's parent describe block @ repetition 1 of 3 + ✓ describe blocks → describe with repeat → nested describe without repeat → test with no repeat should repeat the number of times specified in the parent's parent describe block @ repetition 2 of 3 + ✓ describe blocks → describe with repeat → nested describe without repeat → test with no repeat should repeat the number of times specified in the parent's parent describe block @ repetition 3 of 3 + ✓ describe blocks → describe with repeat → nested describe without repeat → test with repeat should repeat the number of times specified in the test @ repetition 1 of 2 + ✓ describe blocks → describe with repeat → nested describe without repeat → test with repeat should repeat the number of times specified in the test @ repetition 2 of 2 + ✓ describe blocks → describe with repeat → nested describe with repeat → test with no repeat should repeat the number of times specified in the parent describe block @ repetition 1 of 2 + ✓ describe blocks → describe with repeat → nested describe with repeat → test with no repeat should repeat the number of times specified in the parent describe block @ repetition 2 of 2 + ✓ describe blocks → describe with repeat → nested describe with repeat → test with repeat should repeat the number of times specified in the test @ repetition 1 of 2 + ✓ describe blocks → describe with repeat → nested describe with repeat → test with repeat should repeat the number of times specified in the test @ repetition 2 of 2 PASS Tests\Features\ScopedDatasets\Directory\NestedDirectory1\TestFileInNestedDirectoryWithDatasetsFile ✓ uses dataset with (1) @@ -1259,6 +1301,12 @@ - it skips when skip after assertion - it can use something in the test case as a condition → This test was skipped - it can user higher order callables and skip + - skip on describe → skipped tests → nested inside skipped block → it should not execute + - skip on describe → skipped tests → it should not execute + ✓ skip on describe → it should execute + - skip on beforeEach → skipped tests → nested inside skipped block → it should not execute + - skip on beforeEach → skipped tests → it should not execute + ✓ skip on beforeEach → it should execute WARN Tests\Features\SkipOnPhp ✓ it can run on php version @@ -1279,7 +1327,7 @@ ✓ nested → it may be associated with an ticket #1, #4, #5, #6, #3 // an note between an the ticket - PASS Tests\Features\Todo - 7 todos + PASS Tests\Features\Todo - 11 todos ↓ something todo later ↓ something todo later chained ↓ something todo later chained and with function body @@ -1289,6 +1337,12 @@ ↓ it may have an associated PR #1 ↓ it may have an associated note // a note + ↓ todo on describe → todo block → nested inside todo block → it should not execute + ↓ todo on describe → todo block → it should not execute + ✓ todo on describe → it should execute + ↓ todo on beforeEach → todo block → nested inside todo block → it should not execute + ↓ todo on beforeEach → todo block → it should not execute + ✓ todo on beforeEach → it should execute WARN Tests\Features\Warnings ! warning → Undefined property: P\Tests\Features\Warnings::$fooqwdfwqdfqw @@ -1588,4 +1642,4 @@ WARN Tests\Visual\Version - visual snapshot of help command output - Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 17 todos, 28 skipped, 1099 passed (2656 assertions) \ No newline at end of file + Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 21 todos, 32 skipped, 1133 passed (2702 assertions) \ No newline at end of file diff --git a/tests/Features/BeforeEach.php b/tests/Features/BeforeEach.php index 8ce78200..04f0dd13 100644 --- a/tests/Features/BeforeEach.php +++ b/tests/Features/BeforeEach.php @@ -41,3 +41,13 @@ describe('outer', function () { }); }); }); + +describe('with expectations', function () { + beforeEach()->expect(true)->toBeTrue(); + + describe('nested block', function () { + test('test', function () {}); + }); + + test('test', function () {}); +}); diff --git a/tests/Features/DatasetsTests.php b/tests/Features/DatasetsTests.php index bba77ac2..a2ff44ee 100644 --- a/tests/Features/DatasetsTests.php +++ b/tests/Features/DatasetsTests.php @@ -392,3 +392,25 @@ it('may be used with high order even when bound') ->with('greeting-bound') ->expect(fn (string $greeting) => $greeting) ->throws(InvalidArgumentException::class); + +describe('with on nested describe', function () { + describe('nested', function () { + test('before inner describe block', function (...$args) { + expect($args)->toBe([1]); + }); + + describe('describe', function () { + it('should include the with value from all parent describe blocks', function (...$args) { + expect($args)->toBe([1, 2]); + }); + + test('should include the with value from all parent describe blocks and the test', function (...$args) { + expect($args)->toBe([1, 2, 3]); + })->with([3]); + })->with([2]); + + test('after inner describe block', function (...$args) { + expect($args)->toBe([1]); + }); + })->with([1]); +}); diff --git a/tests/Features/Depends.php b/tests/Features/Depends.php index 03ef85a8..0592b98b 100644 --- a/tests/Features/Depends.php +++ b/tests/Features/Depends.php @@ -36,3 +36,39 @@ test('depends run test only once', function () use (&$runCounter) { // Regression tests. See https://github.com/pestphp/pest/pull/216 it('asserts true is true')->assertTrue(true); test('depends works with the correct test name')->assertTrue(true)->depends('it asserts true is true'); + +describe('describe block', function () { + $runCounter = 0; + + test('first in describe', function () use (&$runCounter) { + $runCounter++; + expect(true)->toBeTrue(); + }); + + test('second in describe', function () use (&$runCounter) { + expect($runCounter)->toBe(1); + $runCounter++; + })->depends('first in describe'); + + test('third in describe', function () use (&$runCounter) { + expect($runCounter)->toBe(2); + })->depends('second in describe'); + + describe('nested describe', function () { + $runCounter = 0; + + test('first in nested describe', function () use (&$runCounter) { + $runCounter++; + expect(true)->toBeTrue(); + }); + + test('second in nested describe', function () use (&$runCounter) { + expect($runCounter)->toBe(1); + $runCounter++; + })->depends('first in nested describe'); + + test('third in nested describe', function () use (&$runCounter) { + expect($runCounter)->toBe(2); + })->depends('second in nested describe'); + }); +}); diff --git a/tests/Features/Note.php b/tests/Features/Note.php index 85868d48..571d7c85 100644 --- a/tests/Features/Note.php +++ b/tests/Features/Note.php @@ -21,11 +21,27 @@ it('may have static note and runtime note', function () { })->note('This is a static note'); describe('nested', function () { + beforeEach(function () { + $this->note('This is before each describe runtime note'); + })->note('This is before each describe static note'); + it('may have static note and runtime note', function () { expect(true)->toBeTrue(true); $this->note('This is a runtime note within describe'); })->note('This is a static note within describe'); + + describe('describe nested within describe', function () { + beforeEach(function () { + $this->note('This is before each nested describe runtime note'); + })->note('This is before each nested describe static note'); + + it('may have a static note and runtime note', function () { + expect(true)->toBeTrue(true); + + $this->note('This is a runtime note within a nested describe'); + })->note('This is a static note within a nested describe'); + })->note('This is a nested describe static note'); })->note('This is describe static note'); test('multiple notes', function () { diff --git a/tests/Features/Repeat.php b/tests/Features/Repeat.php index 811c1185..5a3370cd 100644 --- a/tests/Features/Repeat.php +++ b/tests/Features/Repeat.php @@ -43,3 +43,39 @@ test('multiple times with repeat iterator with multiple dataset', function (stri ->toBeNumeric() ->toBeGreaterThan(0); })->repeat(times: 2)->with(['a', 'b', 'c'], ['d', 'e', 'f']); + +describe('describe blocks', function () { + test('multiple times', function () { + expect(true)->toBeTrue(); + })->repeat(times: 3); + + describe('describe with repeat', function () { + test('test with no repeat should repeat the number of times specified in the parent describe block', function () { + expect(true)->toBeTrue(); + }); + + test('test with repeat should repeat the number of times specified in the test', function () { + expect(true)->toBeTrue(); + })->repeat(times: 2); + + describe('nested describe without repeat', function () { + test("test with no repeat should repeat the number of times specified in the parent's parent describe block", function () { + expect(true)->toBeTrue(); + }); + + test('test with repeat should repeat the number of times specified in the test', function () { + expect(true)->toBeTrue(); + })->repeat(times: 2); + }); + + describe('nested describe with repeat', function () { + test('test with no repeat should repeat the number of times specified in the parent describe block', function () { + expect(true)->toBeTrue(); + }); + + test('test with repeat should repeat the number of times specified in the test', function () { + expect(true)->toBeTrue(); + })->repeat(times: 2); + })->repeat(times: 2); + })->repeat(times: 3); +}); diff --git a/tests/Features/Skip.php b/tests/Features/Skip.php index 5ac559f9..de12cf02 100644 --- a/tests/Features/Skip.php +++ b/tests/Features/Skip.php @@ -54,3 +54,73 @@ it('can user higher order callables and skip') return $this->shouldSkip; }) ->toBeFalse(); + +describe('skip on describe', function () { + beforeEach(function () { + $this->ran = false; + }); + + afterEach(function () { + match ($this->name()) { + '__pest_evaluable__skip_on_describe__→__skipped_tests__→__nested_inside_skipped_block__→_it_should_not_execute' => expect($this->ran)->toBe(false), + '__pest_evaluable__skip_on_describe__→__skipped_tests__→_it_should_not_execute' => expect($this->ran)->toBe(false), + '__pest_evaluable__skip_on_describe__→_it_should_execute' => expect($this->ran)->toBe(true), + default => $this->fail('Unexpected test name: '.$this->name()), + }; + }); + + describe('skipped tests', function () { + describe('nested inside skipped block', function () { + it('should not execute', function () { + $this->ran = true; + $this->fail(); + }); + }); + + it('should not execute', function () { + $this->ran = true; + $this->fail(); + }); + })->skip(); + + it('should execute', function () { + $this->ran = true; + expect($this->ran)->toBe(true); + }); +}); + +describe('skip on beforeEach', function () { + beforeEach(function () { + $this->ran = false; + }); + + afterEach(function () { + match ($this->name()) { + '__pest_evaluable__skip_on_beforeEach__→__skipped_tests__→__nested_inside_skipped_block__→_it_should_not_execute' => expect($this->ran)->toBe(false), + '__pest_evaluable__skip_on_beforeEach__→__skipped_tests__→_it_should_not_execute' => expect($this->ran)->toBe(false), + '__pest_evaluable__skip_on_beforeEach__→_it_should_execute' => expect($this->ran)->toBe(true), + default => $this->fail('Unexpected test name: '.$this->name()), + }; + }); + + describe('skipped tests', function () { + beforeEach()->skip(); + + describe('nested inside skipped block', function () { + it('should not execute', function () { + $this->ran = true; + $this->fail(); + }); + }); + + it('should not execute', function () { + $this->ran = true; + $this->fail(); + }); + }); + + it('should execute', function () { + $this->ran = true; + expect($this->ran)->toBe(true); + }); +}); diff --git a/tests/Features/Todo.php b/tests/Features/Todo.php index 39f79e44..eaa6d025 100644 --- a/tests/Features/Todo.php +++ b/tests/Features/Todo.php @@ -27,3 +27,73 @@ it('may have an associated PR', function () { it('may have an associated note', function () { expect(true)->toBeTrue(); })->todo(note: 'a note'); + +describe('todo on describe', function () { + beforeEach(function () { + $this->ran = false; + }); + + afterEach(function () { + match ($this->name()) { + '__pest_evaluable__todo_on_describe__→__todo_block__→__nested_inside_todo_block__→_it_should_not_execute' => expect($this->ran)->toBe(false), + '__pest_evaluable__todo_on_describe__→__todo_block__→_it_should_not_execute' => expect($this->ran)->toBe(false), + '__pest_evaluable__todo_on_describe__→_it_should_execute' => expect($this->ran)->toBe(true), + default => $this->fail('Unexpected test name: '.$this->name()), + }; + }); + + describe('todo block', function () { + describe('nested inside todo block', function () { + it('should not execute', function () { + $this->ran = true; + $this->fail(); + }); + }); + + it('should not execute', function () { + $this->ran = true; + $this->fail(); + }); + })->todo(); + + it('should execute', function () { + $this->ran = true; + expect($this->ran)->toBe(true); + }); +}); + +describe('todo on beforeEach', function () { + beforeEach(function () { + $this->ran = false; + }); + + afterEach(function () { + match ($this->name()) { + '__pest_evaluable__todo_on_beforeEach__→__todo_block__→__nested_inside_todo_block__→_it_should_not_execute' => expect($this->ran)->toBe(false), + '__pest_evaluable__todo_on_beforeEach__→__todo_block__→_it_should_not_execute' => expect($this->ran)->toBe(false), + '__pest_evaluable__todo_on_beforeEach__→_it_should_execute' => expect($this->ran)->toBe(true), + default => $this->fail('Unexpected test name: '.$this->name()), + }; + }); + + describe('todo block', function () { + beforeEach()->todo(); + + describe('nested inside todo block', function () { + it('should not execute', function () { + $this->ran = true; + $this->fail(); + }); + }); + + it('should not execute', function () { + $this->ran = true; + $this->fail(); + }); + }); + + it('should execute', function () { + $this->ran = true; + expect($this->ran)->toBe(true); + }); +}); diff --git a/tests/Visual/Parallel.php b/tests/Visual/Parallel.php index b3de6f5d..eebfbec3 100644 --- a/tests/Visual/Parallel.php +++ b/tests/Visual/Parallel.php @@ -16,7 +16,7 @@ $run = function () { test('parallel', function () use ($run) { expect($run('--exclude-group=integration')) - ->toContain('Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 17 todos, 19 skipped, 1089 passed (2632 assertions)') + ->toContain('Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 21 todos, 23 skipped, 1123 passed (2678 assertions)') ->toContain('Parallel: 3 processes'); })->skipOnWindows(); From cd2eb3504b7dce1d3de14e5af8c3c2c04d72be8f Mon Sep 17 00:00:00 2001 From: jshayes Date: Sun, 13 Oct 2024 09:47:54 -0400 Subject: [PATCH 4/6] Add helper to get last element of array --- src/PendingCalls/AfterEachCall.php | 3 +- src/PendingCalls/BeforeEachCall.php | 7 +++-- src/Support/Arr.php | 10 ++++++ tests/.snapshots/success.txt | 9 +++++- tests/Unit/Support/Arr.php | 49 +++++++++++++++++++++++++++++ tests/Visual/Parallel.php | 2 +- 6 files changed, 74 insertions(+), 6 deletions(-) create mode 100644 tests/Unit/Support/Arr.php diff --git a/src/PendingCalls/AfterEachCall.php b/src/PendingCalls/AfterEachCall.php index 643ab924..2fdc6679 100644 --- a/src/PendingCalls/AfterEachCall.php +++ b/src/PendingCalls/AfterEachCall.php @@ -6,6 +6,7 @@ namespace Pest\PendingCalls; use Closure; use Pest\PendingCalls\Concerns\Describable; +use Pest\Support\Arr; use Pest\Support\Backtrace; use Pest\Support\ChainableClosure; use Pest\Support\HigherOrderMessageCollection; @@ -54,7 +55,7 @@ final class AfterEachCall $proxies = $this->proxies; $afterEachTestCase = ChainableClosure::boundWhen( - fn (): bool => $describing === [] || in_array(end($describing), $this->__describing, true), + fn (): bool => $describing === [] || in_array(Arr::last($describing), $this->__describing, true), ChainableClosure::bound(fn () => $proxies->chain($this), $this->closure)->bindTo($this, self::class), // @phpstan-ignore-line )->bindTo($this, self::class); diff --git a/src/PendingCalls/BeforeEachCall.php b/src/PendingCalls/BeforeEachCall.php index 4582cbbc..3170d8ea 100644 --- a/src/PendingCalls/BeforeEachCall.php +++ b/src/PendingCalls/BeforeEachCall.php @@ -7,6 +7,7 @@ namespace Pest\PendingCalls; use Closure; use Pest\Exceptions\AfterBeforeTestFunction; use Pest\PendingCalls\Concerns\Describable; +use Pest\Support\Arr; use Pest\Support\Backtrace; use Pest\Support\ChainableClosure; use Pest\Support\HigherOrderMessageCollection; @@ -64,11 +65,11 @@ final class BeforeEachCall $beforeEachTestCall = function (TestCall $testCall) use ($describing): void { if ($this->describing !== []) { - if (end($describing) !== end($this->describing)) { + if (Arr::last($describing) !== Arr::last($this->describing)) { return; } - if (! in_array(end($describing), $testCall->describing, true)) { + if (! in_array(Arr::last($describing), $testCall->describing, true)) { return; } } @@ -77,7 +78,7 @@ final class BeforeEachCall }; $beforeEachTestCase = ChainableClosure::boundWhen( - fn (): bool => $describing === [] || in_array(end($describing), $this->__describing, true), + fn (): bool => $describing === [] || in_array(Arr::last($describing), $this->__describing, true), ChainableClosure::bound(fn () => $testCaseProxies->chain($this), $this->closure)->bindTo($this, self::class), // @phpstan-ignore-line )->bindTo($this, self::class); diff --git a/src/Support/Arr.php b/src/Support/Arr.php index aed6c5a7..daf7e3a4 100644 --- a/src/Support/Arr.php +++ b/src/Support/Arr.php @@ -81,4 +81,14 @@ final class Arr return $results; } + + /** + * Returns the value of the last element or false for empty array + * + * @param array $array + */ + public static function last(array $array): mixed + { + return end($array); + } } diff --git a/tests/.snapshots/success.txt b/tests/.snapshots/success.txt index fbb39a1b..acf5bedf 100644 --- a/tests/.snapshots/success.txt +++ b/tests/.snapshots/success.txt @@ -1491,6 +1491,13 @@ ✓ preset invalid name ✓ preset → myFramework + PASS Tests\Unit\Support\Arr + ✓ last → it should return false for an empty arary + ✓ last → it should return the last element for an array with a single element + ✓ last → it should return the last element for an array without changing the internal pointer + ✓ last → it should return the last element for an associative array without changing the internal pointer + ✓ last → it should return the last element for an mixed key array without changing the internal pointer + PASS Tests\Unit\Support\Backtrace ✓ it gets file name from called file @@ -1642,4 +1649,4 @@ WARN Tests\Visual\Version - visual snapshot of help command output - Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 21 todos, 32 skipped, 1133 passed (2702 assertions) \ No newline at end of file + Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 21 todos, 32 skipped, 1138 passed (2719 assertions) \ No newline at end of file diff --git a/tests/Unit/Support/Arr.php b/tests/Unit/Support/Arr.php new file mode 100644 index 00000000..6dc6f3bb --- /dev/null +++ b/tests/Unit/Support/Arr.php @@ -0,0 +1,49 @@ +toBeFalse(); + }); + + it('should return the last element for an array with a single element', function () { + expect(Arr::last([1]))->toBe(1); + }); + + it('should return the last element for an array without changing the internal pointer', function () { + $array = [1, 2, 3]; + + expect(Arr::last($array))->toBe(3); + expect(current($array))->toBe(1); + + next($array); + expect(current($array))->toBe(2); + expect(Arr::last($array))->toBe(3); + expect(current($array))->toBe(2); + }); + + it('should return the last element for an associative array without changing the internal pointer', function () { + $array = ['first' => 1, 'second' => 2, 'third' => 3]; + + expect(Arr::last($array))->toBe(3); + expect(current($array))->toBe(1); + + next($array); + expect(current($array))->toBe(2); + expect(Arr::last($array))->toBe(3); + expect(current($array))->toBe(2); + }); + + it('should return the last element for an mixed key array without changing the internal pointer', function () { + $array = ['first' => 1, 2, 'third' => 3]; + + expect(Arr::last($array))->toBe(3); + expect(current($array))->toBe(1); + + next($array); + expect(current($array))->toBe(2); + expect(Arr::last($array))->toBe(3); + expect(current($array))->toBe(2); + }); +}); diff --git a/tests/Visual/Parallel.php b/tests/Visual/Parallel.php index eebfbec3..ae7e86f2 100644 --- a/tests/Visual/Parallel.php +++ b/tests/Visual/Parallel.php @@ -16,7 +16,7 @@ $run = function () { test('parallel', function () use ($run) { expect($run('--exclude-group=integration')) - ->toContain('Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 21 todos, 23 skipped, 1123 passed (2678 assertions)') + ->toContain('Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 21 todos, 23 skipped, 1128 passed (2695 assertions)') ->toContain('Parallel: 3 processes'); })->skipOnWindows(); From 9510d4a2f964dc19e68fb6505af3fbbfadd0c0c6 Mon Sep 17 00:00:00 2001 From: jshayes Date: Sun, 13 Oct 2024 09:54:19 -0400 Subject: [PATCH 5/6] Change array type hint --- src/Concerns/Testable.php | 2 +- src/Factories/TestCaseMethodFactory.php | 2 +- src/PendingCalls/Concerns/Describable.php | 4 ++-- src/PendingCalls/DescribeCall.php | 4 ++-- src/Support/Str.php | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Concerns/Testable.php b/src/Concerns/Testable.php index e94e80b7..37d3b175 100644 --- a/src/Concerns/Testable.php +++ b/src/Concerns/Testable.php @@ -62,7 +62,7 @@ trait Testable /** * The test's describing, if any. * - * @var string[] + * @var array */ public array $__describing = []; diff --git a/src/Factories/TestCaseMethodFactory.php b/src/Factories/TestCaseMethodFactory.php index 425d4950..fb763c75 100644 --- a/src/Factories/TestCaseMethodFactory.php +++ b/src/Factories/TestCaseMethodFactory.php @@ -32,7 +32,7 @@ final class TestCaseMethodFactory /** * The test's describing, if any. * - * @var string[] + * @var array */ public array $describing = []; diff --git a/src/PendingCalls/Concerns/Describable.php b/src/PendingCalls/Concerns/Describable.php index b114d15d..06a7eab7 100644 --- a/src/PendingCalls/Concerns/Describable.php +++ b/src/PendingCalls/Concerns/Describable.php @@ -12,14 +12,14 @@ trait Describable /** * Note: this is property is not used; however, it gets added automatically by rector php. * - * @var string[] + * @var array */ public array $__describing; /** * The describing of the test case. * - * @var string[] + * @var array */ public array $describing = []; } diff --git a/src/PendingCalls/DescribeCall.php b/src/PendingCalls/DescribeCall.php index decd6451..b015595c 100644 --- a/src/PendingCalls/DescribeCall.php +++ b/src/PendingCalls/DescribeCall.php @@ -16,7 +16,7 @@ final class DescribeCall /** * The current describe call. * - * @var string[] + * @var array */ private static array $describing = []; @@ -40,7 +40,7 @@ final class DescribeCall /** * What is the current describing. * - * @return string[] + * @return array */ public static function describing(): array { diff --git a/src/Support/Str.php b/src/Support/Str.php index 570d58ea..0e654bc8 100644 --- a/src/Support/Str.php +++ b/src/Support/Str.php @@ -104,7 +104,7 @@ final class Str /** * Creates a describe block as `$describeDescription` → `$testDescription` format. * - * @param string[] $describeDescriptions + * @param array $describeDescriptions */ public static function describe(array $describeDescriptions, string $testDescription): string { From 6968094e2b04624f508d594bebcb035ce1c71d66 Mon Sep 17 00:00:00 2001 From: jshayes Date: Sun, 13 Oct 2024 10:39:17 -0400 Subject: [PATCH 6/6] Add tests --- tests/.pest/snapshots/Visual/Todo/todo.snap | 46 +++++++- .../Visual/Todo/todo_in_parallel.snap | 46 +++++++- tests/.pest/snapshots/Visual/Todo/todos.snap | 46 +++++++- .../Visual/Todo/todos_in_parallel.snap | 46 +++++++- tests/.snapshots/success.txt | 53 ++++++++- tests/Features/DatasetsTests.php | 15 +++ tests/Features/Depends.php | 4 + tests/Features/Skip.php | 8 ++ tests/Features/Todo.php | 102 ++++++++++++++++++ tests/Visual/Parallel.php | 2 +- 10 files changed, 357 insertions(+), 11 deletions(-) diff --git a/tests/.pest/snapshots/Visual/Todo/todo.snap b/tests/.pest/snapshots/Visual/Todo/todo.snap index e9939bf8..5ab4f7fa 100644 --- a/tests/.pest/snapshots/Visual/Todo/todo.snap +++ b/tests/.pest/snapshots/Visual/Todo/todo.snap @@ -15,7 +15,7 @@ ↓ todo on describe → should not fail ↓ todo on describe → should run - TODO Tests\Features\Todo - 11 todos + TODO Tests\Features\Todo - 28 todos ↓ something todo later ↓ something todo later chained ↓ something todo later chained and with function body @@ -25,9 +25,51 @@ ↓ it may have an associated note // a note ↓ todo on describe → todo block → nested inside todo block → it should not execute + ↓ todo on describe → todo block → nested inside todo block → it should set the note + // hi + ↓ todo on describe → todo block → describe with note → it should apply the note to a test without a todo + // describe note + ↓ todo on describe → todo block → describe with note → it should apply the note to a test with a todo + // describe note + ↓ todo on describe → todo block → describe with note → it should apply the note as well as the note from the test + // describe note + // test note + ↓ todo on describe → todo block → describe with note → nested describe with note → it should apply all parent notes to a test without a todo + // describe note + // nested describe note + ↓ todo on describe → todo block → describe with note → nested describe with note → it should apply all parent notes to a test with a todo + // describe note + // nested describe note + ↓ todo on describe → todo block → describe with note → nested describe with note → it should apply all parent notes as well as the note from the test + // describe note + // nested describe note + // test note ↓ todo on describe → todo block → it should not execute + ↓ todo on test after describe block + ↓ todo with note on test after describe block + // test note ↓ todo on beforeEach → todo block → nested inside todo block → it should not execute + ↓ todo on beforeEach → todo block → describe with note → it should apply the note to a test without a todo + // describe note + ↓ todo on beforeEach → todo block → describe with note → it should apply the note to a test with a todo + // describe note + ↓ todo on beforeEach → todo block → describe with note → it should apply the note as well as the note from the test + // describe note + // test note + ↓ todo on beforeEach → todo block → describe with note → nested describe with note → it should apply all parent notes to a test without a todo + // describe note + // nested describe note + ↓ todo on beforeEach → todo block → describe with note → nested describe with note → it should apply all parent notes to a test with a todo + // describe note + // nested describe note + ↓ todo on beforeEach → todo block → describe with note → nested describe with note → it should apply all parent notes as well as the note from the test + // describe note + // nested describe note + // test note ↓ todo on beforeEach → todo block → it should not execute + ↓ todo on test after describe block with beforeEach + ↓ todo with note on test after describe block with beforeEach + // test note PASS Tests\CustomTestCase\ChildTest ✓ override method @@ -38,6 +80,6 @@ PASS Tests\CustomTestCase\ParentTest ✓ override method - Tests: 21 todos, 3 passed (7 assertions) + Tests: 38 todos, 3 passed (20 assertions) Duration: x.xxs diff --git a/tests/.pest/snapshots/Visual/Todo/todo_in_parallel.snap b/tests/.pest/snapshots/Visual/Todo/todo_in_parallel.snap index e9939bf8..5ab4f7fa 100644 --- a/tests/.pest/snapshots/Visual/Todo/todo_in_parallel.snap +++ b/tests/.pest/snapshots/Visual/Todo/todo_in_parallel.snap @@ -15,7 +15,7 @@ ↓ todo on describe → should not fail ↓ todo on describe → should run - TODO Tests\Features\Todo - 11 todos + TODO Tests\Features\Todo - 28 todos ↓ something todo later ↓ something todo later chained ↓ something todo later chained and with function body @@ -25,9 +25,51 @@ ↓ it may have an associated note // a note ↓ todo on describe → todo block → nested inside todo block → it should not execute + ↓ todo on describe → todo block → nested inside todo block → it should set the note + // hi + ↓ todo on describe → todo block → describe with note → it should apply the note to a test without a todo + // describe note + ↓ todo on describe → todo block → describe with note → it should apply the note to a test with a todo + // describe note + ↓ todo on describe → todo block → describe with note → it should apply the note as well as the note from the test + // describe note + // test note + ↓ todo on describe → todo block → describe with note → nested describe with note → it should apply all parent notes to a test without a todo + // describe note + // nested describe note + ↓ todo on describe → todo block → describe with note → nested describe with note → it should apply all parent notes to a test with a todo + // describe note + // nested describe note + ↓ todo on describe → todo block → describe with note → nested describe with note → it should apply all parent notes as well as the note from the test + // describe note + // nested describe note + // test note ↓ todo on describe → todo block → it should not execute + ↓ todo on test after describe block + ↓ todo with note on test after describe block + // test note ↓ todo on beforeEach → todo block → nested inside todo block → it should not execute + ↓ todo on beforeEach → todo block → describe with note → it should apply the note to a test without a todo + // describe note + ↓ todo on beforeEach → todo block → describe with note → it should apply the note to a test with a todo + // describe note + ↓ todo on beforeEach → todo block → describe with note → it should apply the note as well as the note from the test + // describe note + // test note + ↓ todo on beforeEach → todo block → describe with note → nested describe with note → it should apply all parent notes to a test without a todo + // describe note + // nested describe note + ↓ todo on beforeEach → todo block → describe with note → nested describe with note → it should apply all parent notes to a test with a todo + // describe note + // nested describe note + ↓ todo on beforeEach → todo block → describe with note → nested describe with note → it should apply all parent notes as well as the note from the test + // describe note + // nested describe note + // test note ↓ todo on beforeEach → todo block → it should not execute + ↓ todo on test after describe block with beforeEach + ↓ todo with note on test after describe block with beforeEach + // test note PASS Tests\CustomTestCase\ChildTest ✓ override method @@ -38,6 +80,6 @@ PASS Tests\CustomTestCase\ParentTest ✓ override method - Tests: 21 todos, 3 passed (7 assertions) + Tests: 38 todos, 3 passed (20 assertions) Duration: x.xxs diff --git a/tests/.pest/snapshots/Visual/Todo/todos.snap b/tests/.pest/snapshots/Visual/Todo/todos.snap index e9939bf8..5ab4f7fa 100644 --- a/tests/.pest/snapshots/Visual/Todo/todos.snap +++ b/tests/.pest/snapshots/Visual/Todo/todos.snap @@ -15,7 +15,7 @@ ↓ todo on describe → should not fail ↓ todo on describe → should run - TODO Tests\Features\Todo - 11 todos + TODO Tests\Features\Todo - 28 todos ↓ something todo later ↓ something todo later chained ↓ something todo later chained and with function body @@ -25,9 +25,51 @@ ↓ it may have an associated note // a note ↓ todo on describe → todo block → nested inside todo block → it should not execute + ↓ todo on describe → todo block → nested inside todo block → it should set the note + // hi + ↓ todo on describe → todo block → describe with note → it should apply the note to a test without a todo + // describe note + ↓ todo on describe → todo block → describe with note → it should apply the note to a test with a todo + // describe note + ↓ todo on describe → todo block → describe with note → it should apply the note as well as the note from the test + // describe note + // test note + ↓ todo on describe → todo block → describe with note → nested describe with note → it should apply all parent notes to a test without a todo + // describe note + // nested describe note + ↓ todo on describe → todo block → describe with note → nested describe with note → it should apply all parent notes to a test with a todo + // describe note + // nested describe note + ↓ todo on describe → todo block → describe with note → nested describe with note → it should apply all parent notes as well as the note from the test + // describe note + // nested describe note + // test note ↓ todo on describe → todo block → it should not execute + ↓ todo on test after describe block + ↓ todo with note on test after describe block + // test note ↓ todo on beforeEach → todo block → nested inside todo block → it should not execute + ↓ todo on beforeEach → todo block → describe with note → it should apply the note to a test without a todo + // describe note + ↓ todo on beforeEach → todo block → describe with note → it should apply the note to a test with a todo + // describe note + ↓ todo on beforeEach → todo block → describe with note → it should apply the note as well as the note from the test + // describe note + // test note + ↓ todo on beforeEach → todo block → describe with note → nested describe with note → it should apply all parent notes to a test without a todo + // describe note + // nested describe note + ↓ todo on beforeEach → todo block → describe with note → nested describe with note → it should apply all parent notes to a test with a todo + // describe note + // nested describe note + ↓ todo on beforeEach → todo block → describe with note → nested describe with note → it should apply all parent notes as well as the note from the test + // describe note + // nested describe note + // test note ↓ todo on beforeEach → todo block → it should not execute + ↓ todo on test after describe block with beforeEach + ↓ todo with note on test after describe block with beforeEach + // test note PASS Tests\CustomTestCase\ChildTest ✓ override method @@ -38,6 +80,6 @@ PASS Tests\CustomTestCase\ParentTest ✓ override method - Tests: 21 todos, 3 passed (7 assertions) + Tests: 38 todos, 3 passed (20 assertions) Duration: x.xxs diff --git a/tests/.pest/snapshots/Visual/Todo/todos_in_parallel.snap b/tests/.pest/snapshots/Visual/Todo/todos_in_parallel.snap index e9939bf8..5ab4f7fa 100644 --- a/tests/.pest/snapshots/Visual/Todo/todos_in_parallel.snap +++ b/tests/.pest/snapshots/Visual/Todo/todos_in_parallel.snap @@ -15,7 +15,7 @@ ↓ todo on describe → should not fail ↓ todo on describe → should run - TODO Tests\Features\Todo - 11 todos + TODO Tests\Features\Todo - 28 todos ↓ something todo later ↓ something todo later chained ↓ something todo later chained and with function body @@ -25,9 +25,51 @@ ↓ it may have an associated note // a note ↓ todo on describe → todo block → nested inside todo block → it should not execute + ↓ todo on describe → todo block → nested inside todo block → it should set the note + // hi + ↓ todo on describe → todo block → describe with note → it should apply the note to a test without a todo + // describe note + ↓ todo on describe → todo block → describe with note → it should apply the note to a test with a todo + // describe note + ↓ todo on describe → todo block → describe with note → it should apply the note as well as the note from the test + // describe note + // test note + ↓ todo on describe → todo block → describe with note → nested describe with note → it should apply all parent notes to a test without a todo + // describe note + // nested describe note + ↓ todo on describe → todo block → describe with note → nested describe with note → it should apply all parent notes to a test with a todo + // describe note + // nested describe note + ↓ todo on describe → todo block → describe with note → nested describe with note → it should apply all parent notes as well as the note from the test + // describe note + // nested describe note + // test note ↓ todo on describe → todo block → it should not execute + ↓ todo on test after describe block + ↓ todo with note on test after describe block + // test note ↓ todo on beforeEach → todo block → nested inside todo block → it should not execute + ↓ todo on beforeEach → todo block → describe with note → it should apply the note to a test without a todo + // describe note + ↓ todo on beforeEach → todo block → describe with note → it should apply the note to a test with a todo + // describe note + ↓ todo on beforeEach → todo block → describe with note → it should apply the note as well as the note from the test + // describe note + // test note + ↓ todo on beforeEach → todo block → describe with note → nested describe with note → it should apply all parent notes to a test without a todo + // describe note + // nested describe note + ↓ todo on beforeEach → todo block → describe with note → nested describe with note → it should apply all parent notes to a test with a todo + // describe note + // nested describe note + ↓ todo on beforeEach → todo block → describe with note → nested describe with note → it should apply all parent notes as well as the note from the test + // describe note + // nested describe note + // test note ↓ todo on beforeEach → todo block → it should not execute + ↓ todo on test after describe block with beforeEach + ↓ todo with note on test after describe block with beforeEach + // test note PASS Tests\CustomTestCase\ChildTest ✓ override method @@ -38,6 +80,6 @@ PASS Tests\CustomTestCase\ParentTest ✓ override method - Tests: 21 todos, 3 passed (7 assertions) + Tests: 38 todos, 3 passed (20 assertions) Duration: x.xxs diff --git a/tests/.snapshots/success.txt b/tests/.snapshots/success.txt index acf5bedf..1eaf4598 100644 --- a/tests/.snapshots/success.txt +++ b/tests/.snapshots/success.txt @@ -187,6 +187,10 @@ ✓ with on nested describe → nested → describe → it should include the with value from all parent describe blocks with (1) / (2) ✓ with on nested describe → nested → describe → should include the with value from all parent describe blocks and the test with (1) / (2) / (3) ✓ with on nested describe → nested → after inner describe block with (1) + ✓ after describe block with (5) + ✓ it may be used with high order after describe block with dataset "formal" + ✓ it may be used with high order after describe block with dataset "informal" + ✓ after describe block with named dataset with ('after') PASS Tests\Features\Depends ✓ first @@ -203,6 +207,7 @@ ✓ describe block → nested describe → first in nested describe ✓ describe block → nested describe → second in nested describe ✓ describe block → nested describe → third in nested describe + ✓ depends on test after describe block PASS Tests\Features\DependsInheritance ✓ it is a test @@ -1307,6 +1312,8 @@ - skip on beforeEach → skipped tests → nested inside skipped block → it should not execute - skip on beforeEach → skipped tests → it should not execute ✓ skip on beforeEach → it should execute + ✓ it does not skip after the describe block + - it can skip after the describe block WARN Tests\Features\SkipOnPhp ✓ it can run on php version @@ -1327,7 +1334,7 @@ ✓ nested → it may be associated with an ticket #1, #4, #5, #6, #3 // an note between an the ticket - PASS Tests\Features\Todo - 11 todos + PASS Tests\Features\Todo - 28 todos ↓ something todo later ↓ something todo later chained ↓ something todo later chained and with function body @@ -1338,11 +1345,53 @@ ↓ it may have an associated note // a note ↓ todo on describe → todo block → nested inside todo block → it should not execute + ↓ todo on describe → todo block → nested inside todo block → it should set the note + // hi + ↓ todo on describe → todo block → describe with note → it should apply the note to a test without a todo + // describe note + ↓ todo on describe → todo block → describe with note → it should apply the note to a test with a todo + // describe note + ↓ todo on describe → todo block → describe with note → it should apply the note as well as the note from the test + // describe note + // test note + ↓ todo on describe → todo block → describe with note → nested describe with note → it should apply all parent notes to a test without a todo + // describe note + // nested describe note + ↓ todo on describe → todo block → describe with note → nested describe with note → it should apply all parent notes to a test with a todo + // describe note + // nested describe note + ↓ todo on describe → todo block → describe with note → nested describe with note → it should apply all parent notes as well as the note from the test + // describe note + // nested describe note + // test note ↓ todo on describe → todo block → it should not execute ✓ todo on describe → it should execute + ↓ todo on test after describe block + ↓ todo with note on test after describe block + // test note ↓ todo on beforeEach → todo block → nested inside todo block → it should not execute + ↓ todo on beforeEach → todo block → describe with note → it should apply the note to a test without a todo + // describe note + ↓ todo on beforeEach → todo block → describe with note → it should apply the note to a test with a todo + // describe note + ↓ todo on beforeEach → todo block → describe with note → it should apply the note as well as the note from the test + // describe note + // test note + ↓ todo on beforeEach → todo block → describe with note → nested describe with note → it should apply all parent notes to a test without a todo + // describe note + // nested describe note + ↓ todo on beforeEach → todo block → describe with note → nested describe with note → it should apply all parent notes to a test with a todo + // describe note + // nested describe note + ↓ todo on beforeEach → todo block → describe with note → nested describe with note → it should apply all parent notes as well as the note from the test + // describe note + // nested describe note + // test note ↓ todo on beforeEach → todo block → it should not execute ✓ todo on beforeEach → it should execute + ↓ todo on test after describe block with beforeEach + ↓ todo with note on test after describe block with beforeEach + // test note WARN Tests\Features\Warnings ! warning → Undefined property: P\Tests\Features\Warnings::$fooqwdfwqdfqw @@ -1649,4 +1698,4 @@ WARN Tests\Visual\Version - visual snapshot of help command output - Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 21 todos, 32 skipped, 1138 passed (2719 assertions) \ No newline at end of file + Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 38 todos, 33 skipped, 1144 passed (2736 assertions) \ No newline at end of file diff --git a/tests/Features/DatasetsTests.php b/tests/Features/DatasetsTests.php index a2ff44ee..54cb77a8 100644 --- a/tests/Features/DatasetsTests.php +++ b/tests/Features/DatasetsTests.php @@ -414,3 +414,18 @@ describe('with on nested describe', function () { }); })->with([1]); }); + +test('after describe block', function (...$args) { + expect($args)->toBe([5]); +})->with([5]); + +it('may be used with high order after describe block') + ->with('greeting-string') + ->expect(fn (string $greeting) => $greeting) + ->throwsNoExceptions(); + +dataset('after-describe', ['after']); + +test('after describe block with named dataset', function (...$args) { + expect($args)->toBe(['after']); +})->with('after-describe'); diff --git a/tests/Features/Depends.php b/tests/Features/Depends.php index 0592b98b..82f45c05 100644 --- a/tests/Features/Depends.php +++ b/tests/Features/Depends.php @@ -72,3 +72,7 @@ describe('describe block', function () { })->depends('second in nested describe'); }); }); + +test('depends on test after describe block', function () use (&$runCounter) { + expect($runCounter)->toBe(2); +})->depends('first', 'second'); diff --git a/tests/Features/Skip.php b/tests/Features/Skip.php index de12cf02..35218945 100644 --- a/tests/Features/Skip.php +++ b/tests/Features/Skip.php @@ -124,3 +124,11 @@ describe('skip on beforeEach', function () { expect($this->ran)->toBe(true); }); }); + +it('does not skip after the describe block', function () { + expect(true)->toBeTrue(); +}); + +it('can skip after the describe block', function () { + expect(true)->toBeTrue(); +})->skip(); diff --git a/tests/Features/Todo.php b/tests/Features/Todo.php index eaa6d025..f979a2ff 100644 --- a/tests/Features/Todo.php +++ b/tests/Features/Todo.php @@ -36,6 +36,13 @@ describe('todo on describe', function () { afterEach(function () { match ($this->name()) { '__pest_evaluable__todo_on_describe__→__todo_block__→__nested_inside_todo_block__→_it_should_not_execute' => expect($this->ran)->toBe(false), + '__pest_evaluable__todo_on_describe__→__todo_block__→__nested_inside_todo_block__→_it_should_set_the_note' => expect($this->ran)->toBe(false), + '__pest_evaluable__todo_on_describe__→__todo_block__→__describe_with_note__→_it_should_apply_the_note_to_a_test_without_a_todo' => expect($this->ran)->toBe(false), + '__pest_evaluable__todo_on_describe__→__todo_block__→__describe_with_note__→_it_should_apply_the_note_to_a_test_with_a_todo' => expect($this->ran)->toBe(false), + '__pest_evaluable__todo_on_describe__→__todo_block__→__describe_with_note__→_it_should_apply_the_note_as_well_as_the_note_from_the_test' => expect($this->ran)->toBe(false), + '__pest_evaluable__todo_on_describe__→__todo_block__→__describe_with_note__→__nested_describe_with_note__→_it_should_apply_all_parent_notes_to_a_test_without_a_todo' => expect($this->ran)->toBe(false), + '__pest_evaluable__todo_on_describe__→__todo_block__→__describe_with_note__→__nested_describe_with_note__→_it_should_apply_all_parent_notes_to_a_test_with_a_todo' => expect($this->ran)->toBe(false), + '__pest_evaluable__todo_on_describe__→__todo_block__→__describe_with_note__→__nested_describe_with_note__→_it_should_apply_all_parent_notes_as_well_as_the_note_from_the_test' => expect($this->ran)->toBe(false), '__pest_evaluable__todo_on_describe__→__todo_block__→_it_should_not_execute' => expect($this->ran)->toBe(false), '__pest_evaluable__todo_on_describe__→_it_should_execute' => expect($this->ran)->toBe(true), default => $this->fail('Unexpected test name: '.$this->name()), @@ -48,8 +55,47 @@ describe('todo on describe', function () { $this->ran = true; $this->fail(); }); + + it('should set the note', function () { + $this->ran = true; + $this->fail(); + })->todo(note: 'hi'); }); + describe('describe with note', function () { + it('should apply the note to a test without a todo', function () { + $this->ran = true; + $this->fail(); + }); + + it('should apply the note to a test with a todo', function () { + $this->ran = true; + $this->fail(); + })->todo(); + + it('should apply the note as well as the note from the test', function () { + $this->ran = true; + $this->fail(); + })->todo(note: 'test note'); + + describe('nested describe with note', function () { + it('should apply all parent notes to a test without a todo', function () { + $this->ran = true; + $this->fail(); + }); + + it('should apply all parent notes to a test with a todo', function () { + $this->ran = true; + $this->fail(); + })->todo(); + + it('should apply all parent notes as well as the note from the test', function () { + $this->ran = true; + $this->fail(); + })->todo(note: 'test note'); + })->todo(note: 'nested describe note'); + })->todo(note: 'describe note'); + it('should not execute', function () { $this->ran = true; $this->fail(); @@ -62,6 +108,14 @@ describe('todo on describe', function () { }); }); +test('todo on test after describe block', function () { + $this->fail(); +})->todo(); + +test('todo with note on test after describe block', function () { + $this->fail(); +})->todo(note: 'test note'); + describe('todo on beforeEach', function () { beforeEach(function () { $this->ran = false; @@ -71,6 +125,12 @@ describe('todo on beforeEach', function () { match ($this->name()) { '__pest_evaluable__todo_on_beforeEach__→__todo_block__→__nested_inside_todo_block__→_it_should_not_execute' => expect($this->ran)->toBe(false), '__pest_evaluable__todo_on_beforeEach__→__todo_block__→_it_should_not_execute' => expect($this->ran)->toBe(false), + '__pest_evaluable__todo_on_beforeEach__→__todo_block__→__describe_with_note__→_it_should_apply_the_note_to_a_test_without_a_todo' => expect($this->ran)->toBe(false), + '__pest_evaluable__todo_on_beforeEach__→__todo_block__→__describe_with_note__→_it_should_apply_the_note_to_a_test_with_a_todo' => expect($this->ran)->toBe(false), + '__pest_evaluable__todo_on_beforeEach__→__todo_block__→__describe_with_note__→_it_should_apply_the_note_as_well_as_the_note_from_the_test' => expect($this->ran)->toBe(false), + '__pest_evaluable__todo_on_beforeEach__→__todo_block__→__describe_with_note__→__nested_describe_with_note__→_it_should_apply_all_parent_notes_to_a_test_without_a_todo' => expect($this->ran)->toBe(false), + '__pest_evaluable__todo_on_beforeEach__→__todo_block__→__describe_with_note__→__nested_describe_with_note__→_it_should_apply_all_parent_notes_to_a_test_with_a_todo' => expect($this->ran)->toBe(false), + '__pest_evaluable__todo_on_beforeEach__→__todo_block__→__describe_with_note__→__nested_describe_with_note__→_it_should_apply_all_parent_notes_as_well_as_the_note_from_the_test' => expect($this->ran)->toBe(false), '__pest_evaluable__todo_on_beforeEach__→_it_should_execute' => expect($this->ran)->toBe(true), default => $this->fail('Unexpected test name: '.$this->name()), }; @@ -86,6 +146,40 @@ describe('todo on beforeEach', function () { }); }); + describe('describe with note', function () { + it('should apply the note to a test without a todo', function () { + $this->ran = true; + $this->fail(); + }); + + it('should apply the note to a test with a todo', function () { + $this->ran = true; + $this->fail(); + })->todo(); + + it('should apply the note as well as the note from the test', function () { + $this->ran = true; + $this->fail(); + })->todo(note: 'test note'); + + describe('nested describe with note', function () { + it('should apply all parent notes to a test without a todo', function () { + $this->ran = true; + $this->fail(); + }); + + it('should apply all parent notes to a test with a todo', function () { + $this->ran = true; + $this->fail(); + })->todo(); + + it('should apply all parent notes as well as the note from the test', function () { + $this->ran = true; + $this->fail(); + })->todo(note: 'test note'); + })->todo(note: 'nested describe note'); + })->todo(note: 'describe note'); + it('should not execute', function () { $this->ran = true; $this->fail(); @@ -97,3 +191,11 @@ describe('todo on beforeEach', function () { expect($this->ran)->toBe(true); }); }); + +test('todo on test after describe block with beforeEach', function () { + $this->fail(); +})->todo(); + +test('todo with note on test after describe block with beforeEach', function () { + $this->fail(); +})->todo(note: 'test note'); diff --git a/tests/Visual/Parallel.php b/tests/Visual/Parallel.php index ae7e86f2..313f8208 100644 --- a/tests/Visual/Parallel.php +++ b/tests/Visual/Parallel.php @@ -16,7 +16,7 @@ $run = function () { test('parallel', function () use ($run) { expect($run('--exclude-group=integration')) - ->toContain('Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 21 todos, 23 skipped, 1128 passed (2695 assertions)') + ->toContain('Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 38 todos, 24 skipped, 1134 passed (2712 assertions)') ->toContain('Parallel: 3 processes'); })->skipOnWindows();