From dc9a1e8acef05e2bb5325faeab8d881a1f5b7d36 Mon Sep 17 00:00:00 2001
From: Malico
Date: Sat, 20 Sep 2025 19:06:23 +0100
Subject: [PATCH 01/50] BugFix: Fix toUseTrait to detect inherited and nested
traits
---
src/Expectation.php | 17 ++++++++++++++++-
tests/Features/Expect/toUseTrait.php | 16 ++++++++++++++++
.../ChildClassExtendingParent.php | 11 +++++++++++
.../ToUseTrait/HasNestedTrait/NestedTrait.php | 13 +++++++++++++
.../HasTrait/ParentClassWithTrait.php | 10 ++++++++++
.../HasTrait/TestTraitForInheritance.php | 17 +++++++++++++++++
6 files changed, 83 insertions(+), 1 deletion(-)
create mode 100644 tests/Fixtures/Arch/ToUseTrait/HasInheritedTrait/ChildClassExtendingParent.php
create mode 100644 tests/Fixtures/Arch/ToUseTrait/HasNestedTrait/NestedTrait.php
create mode 100644 tests/Fixtures/Arch/ToUseTrait/HasTrait/ParentClassWithTrait.php
create mode 100644 tests/Fixtures/Arch/ToUseTrait/HasTrait/TestTraitForInheritance.php
diff --git a/src/Expectation.php b/src/Expectation.php
index 5c8a076b..f03a6c4b 100644
--- a/src/Expectation.php
+++ b/src/Expectation.php
@@ -781,7 +781,22 @@ final class Expectation
return false;
}
- if (! in_array($trait, $object->reflectionClass->getTraitNames(), true)) {
+ $currentClass = $object->reflectionClass;
+ $usedTraits = [];
+
+ do {
+ $classTraits = $currentClass->getTraits();
+ foreach ($classTraits as $traitReflection) {
+ $usedTraits[$traitReflection->getName()] = $traitReflection->getName();
+
+ $nestedTraits = $traitReflection->getTraits();
+ foreach ($nestedTraits as $nestedTrait) {
+ $usedTraits[$nestedTrait->getName()] = $nestedTrait->getName();
+ }
+ }
+ } while ($currentClass = $currentClass->getParentClass());
+
+ if (! array_key_exists($trait, $usedTraits)) {
return false;
}
}
diff --git a/tests/Features/Expect/toUseTrait.php b/tests/Features/Expect/toUseTrait.php
index fd9c933f..806490b3 100644
--- a/tests/Features/Expect/toUseTrait.php
+++ b/tests/Features/Expect/toUseTrait.php
@@ -14,3 +14,19 @@ test('failures', function () {
test('not failures', function () {
expect('Pest\Expectations\HigherOrderExpectation')->not->toUseTrait('Pest\Concerns\Retrievable');
})->throws(ArchExpectationFailedException::class);
+
+test('trait inheritance - direct usage', function () {
+ expect('Tests\Fixtures\Arch\ToUseTrait\HasTrait\ParentClassWithTrait')->toUseTrait('Tests\Fixtures\Arch\ToUseTrait\HasTrait\TestTraitForInheritance');
+});
+
+test('trait inheritance - inherited usage', function () {
+ expect('Tests\Fixtures\Arch\ToUseTrait\HasInheritedTrait\ChildClassExtendingParent')->toUseTrait('Tests\Fixtures\Arch\ToUseTrait\HasTrait\TestTraitForInheritance');
+});
+
+test('trait inheritance - negative case', function () {
+ expect('Tests\Fixtures\Arch\ToUseTrait\HasInheritedTrait\ChildClassExtendingParent')->not->toUseTrait('NonExistentTrait');
+});
+
+test('nested trait inheritance', function () {
+ expect('Tests\Fixtures\Arch\ToUseTrait\HasInheritedTrait\ChildClassExtendingParent')->toUseTrait('Tests\Fixtures\Arch\ToUseTrait\HasNestedTrait\NestedTrait');
+});
diff --git a/tests/Fixtures/Arch/ToUseTrait/HasInheritedTrait/ChildClassExtendingParent.php b/tests/Fixtures/Arch/ToUseTrait/HasInheritedTrait/ChildClassExtendingParent.php
new file mode 100644
index 00000000..df7ce9ec
--- /dev/null
+++ b/tests/Fixtures/Arch/ToUseTrait/HasInheritedTrait/ChildClassExtendingParent.php
@@ -0,0 +1,11 @@
+
Date: Wed, 29 Oct 2025 11:13:50 +0100
Subject: [PATCH 02/50] Specify closure this for extend
---
src/Concerns/Extendable.php | 4 ++++
src/Expectation.php | 2 ++
2 files changed, 6 insertions(+)
diff --git a/src/Concerns/Extendable.php b/src/Concerns/Extendable.php
index a2f7e40b..1ff6626b 100644
--- a/src/Concerns/Extendable.php
+++ b/src/Concerns/Extendable.php
@@ -8,6 +8,8 @@ use Closure;
/**
* @internal
+ *
+ * @template T of object
*/
trait Extendable
{
@@ -20,6 +22,8 @@ trait Extendable
/**
* Register a new extend.
+ *
+ * @param-closure-this T $extend
*/
public function extend(string $name, Closure $extend): void
{
diff --git a/src/Expectation.php b/src/Expectation.php
index 5c8a076b..5182b4be 100644
--- a/src/Expectation.php
+++ b/src/Expectation.php
@@ -52,7 +52,9 @@ use ReflectionProperty;
*/
final class Expectation
{
+ /** @use Extendable> */
use Extendable;
+
use Pipeable;
use Retrievable;
From ae1da79ac1f676915de67de6287b291dfddb1256 Mon Sep 17 00:00:00 2001
From: Michael Withagen
Date: Wed, 5 Nov 2025 17:15:51 +0100
Subject: [PATCH 03/50] Pass test dir to worker
#1444
Test directory argument is lost when spawning workers, add it again.
---
src/Plugins/Parallel/Paratest/WrapperRunner.php | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/Plugins/Parallel/Paratest/WrapperRunner.php b/src/Plugins/Parallel/Paratest/WrapperRunner.php
index 469f2aa6..1d73e2db 100644
--- a/src/Plugins/Parallel/Paratest/WrapperRunner.php
+++ b/src/Plugins/Parallel/Paratest/WrapperRunner.php
@@ -131,6 +131,7 @@ final class WrapperRunner implements RunnerInterface
$parameters = $this->handleLaravelHerd($parameters);
$parameters[] = $wrapper;
+ $parameters[] = '--test-directory='.TestSuite::getInstance()->testPath;
$this->parameters = $parameters;
$this->codeCoverageFilterRegistry = new CodeCoverageFilterRegistry;
From 1a39826935b730b0bcad805013d4b2607b83fe3f Mon Sep 17 00:00:00 2001
From: Nuno Maduro
Date: Thu, 20 Nov 2025 02:59:27 +0000
Subject: [PATCH 04/50] ci: tests against php 8.5
---
.github/workflows/tests.yml | 2 +-
rector.php | 2 ++
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index bbc468ab..7f843130 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -14,7 +14,7 @@ jobs:
matrix:
os: [ubuntu-latest, macos-latest] # windows-latest
symfony: ['7.3']
- php: ['8.3', '8.4']
+ php: ['8.3', '8.4', '8.5']
dependency_version: [prefer-stable]
name: PHP ${{ matrix.php }} - Symfony ^${{ matrix.symfony }} - ${{ matrix.os }} - ${{ matrix.dependency_version }}
diff --git a/rector.php b/rector.php
index 49c56f8a..3ec9fb23 100644
--- a/rector.php
+++ b/rector.php
@@ -4,6 +4,7 @@ declare(strict_types=1);
use Rector\CodingStyle\Rector\FunctionLike\FunctionLikeToFirstClassCallableRector;
use Rector\Config\RectorConfig;
+use Rector\TypeDeclaration\Rector\ClassMethod\NarrowObjectReturnTypeRector;
use Rector\TypeDeclaration\Rector\ClassMethod\ReturnNeverTypeRector;
return RectorConfig::configure()
@@ -14,6 +15,7 @@ return RectorConfig::configure()
__DIR__.'/src/Plugins/Parallel/Paratest/WrapperRunner.php',
ReturnNeverTypeRector::class,
FunctionLikeToFirstClassCallableRector::class,
+ NarrowObjectReturnTypeRector::class,
])
->withPreparedSets(
deadCode: true,
From 51340439e8bda6245bd883716ba97eecfdc3d91e Mon Sep 17 00:00:00 2001
From: Christopher Georg
Date: Sat, 22 Nov 2025 12:12:15 +0100
Subject: [PATCH 05/50] ci: bump actions/checkout 4 => 5
---
.github/workflows/static.yml | 2 +-
.github/workflows/tests.yml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml
index 5b9b0df5..ee71d41f 100644
--- a/.github/workflows/static.yml
+++ b/.github/workflows/static.yml
@@ -19,7 +19,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
- name: Setup PHP
uses: shivammathur/setup-php@v2
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 7f843130..3879145c 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -21,7 +21,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
- name: Setup PHP
uses: shivammathur/setup-php@v2
From 41fd8311539642c49765345f87001ef25640a862 Mon Sep 17 00:00:00 2001
From: Nuno Maduro
Date: Mon, 24 Nov 2025 10:25:45 +0000
Subject: [PATCH 06/50] release: 4.1.4
---
composer.json | 16 ++++++++--------
src/Pest.php | 2 +-
.../visual_snapshot_of_help_command_output.snap | 2 +-
.../visual_snapshot_of_help_command_output.snap | 2 +-
4 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/composer.json b/composer.json
index 5859b378..d6dfa44f 100644
--- a/composer.json
+++ b/composer.json
@@ -18,19 +18,19 @@
],
"require": {
"php": "^8.3.0",
- "brianium/paratest": "^7.14.0",
- "nunomaduro/collision": "^8.8.2",
- "nunomaduro/termwind": "^2.3.1",
+ "brianium/paratest": "^7.14.2",
+ "nunomaduro/collision": "^8.8.3",
+ "nunomaduro/termwind": "^2.3.3",
"pestphp/pest-plugin": "^4.0.0",
"pestphp/pest-plugin-arch": "^4.0.0",
"pestphp/pest-plugin-mutate": "^4.0.1",
- "pestphp/pest-plugin-profanity": "^4.1.0",
- "phpunit/phpunit": "^12.4.1",
+ "pestphp/pest-plugin-profanity": "^4.2.0",
+ "phpunit/phpunit": "^12.4.4",
"symfony/process": "^7.3.4"
},
"conflict": {
"filp/whoops": "<2.18.3",
- "phpunit/phpunit": ">12.4.1",
+ "phpunit/phpunit": ">12.4.4",
"sebastian/exporter": "<7.0.0",
"webmozart/assert": "<1.11.0"
},
@@ -57,8 +57,8 @@
"require-dev": {
"pestphp/pest-dev-tools": "^4.0.0",
"pestphp/pest-plugin-browser": "^4.1.1",
- "pestphp/pest-plugin-type-coverage": "^4.0.2",
- "psy/psysh": "^0.12.12"
+ "pestphp/pest-plugin-type-coverage": "^4.0.3",
+ "psy/psysh": "^0.12.14"
},
"minimum-stability": "dev",
"prefer-stable": true,
diff --git a/src/Pest.php b/src/Pest.php
index fa581af4..a14f7b49 100644
--- a/src/Pest.php
+++ b/src/Pest.php
@@ -6,7 +6,7 @@ namespace Pest;
function version(): string
{
- return '4.1.3';
+ return '4.1.4';
}
function testDirectory(string $file = ''): string
diff --git a/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap b/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
index 63f4714c..7afe504b 100644
--- a/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
+++ b/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
@@ -1,5 +1,5 @@
- Pest Testing Framework 4.1.3.
+ Pest Testing Framework 4.1.4.
USAGE: pest [options]
diff --git a/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap b/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap
index 8bafa6ce..67cab918 100644
--- a/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap
+++ b/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap
@@ -1,3 +1,3 @@
- Pest Testing Framework 4.1.3.
+ Pest Testing Framework 4.1.4.
From f5820bd670fd65bad363d21a6171597481f34ec3 Mon Sep 17 00:00:00 2001
From: Nuno Maduro
Date: Mon, 24 Nov 2025 12:46:38 +0000
Subject: [PATCH 07/50] release: 4.1.5
---
src/Pest.php | 2 +-
.../Visual/Help/visual_snapshot_of_help_command_output.snap | 2 +-
.../Visual/Version/visual_snapshot_of_help_command_output.snap | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/Pest.php b/src/Pest.php
index a14f7b49..6cd70729 100644
--- a/src/Pest.php
+++ b/src/Pest.php
@@ -6,7 +6,7 @@ namespace Pest;
function version(): string
{
- return '4.1.4';
+ return '4.1.5';
}
function testDirectory(string $file = ''): string
diff --git a/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap b/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
index 7afe504b..4d83f2c5 100644
--- a/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
+++ b/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
@@ -1,5 +1,5 @@
- Pest Testing Framework 4.1.4.
+ Pest Testing Framework 4.1.5.
USAGE: pest [options]
diff --git a/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap b/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap
index 67cab918..263ca552 100644
--- a/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap
+++ b/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap
@@ -1,3 +1,3 @@
- Pest Testing Framework 4.1.4.
+ Pest Testing Framework 4.1.5.
From ae419afd363299c29ad5b17e8b70d118b1068bb4 Mon Sep 17 00:00:00 2001
From: Nuno Maduro
Date: Fri, 28 Nov 2025 12:04:48 +0000
Subject: [PATCH 08/50] chore: support for symfony 8.0.0 components
---
composer.json | 4 ++--
src/Pest.php | 2 +-
.../Visual/Help/visual_snapshot_of_help_command_output.snap | 2 +-
.../Version/visual_snapshot_of_help_command_output.snap | 2 +-
4 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/composer.json b/composer.json
index d6dfa44f..ddc8aeef 100644
--- a/composer.json
+++ b/composer.json
@@ -26,7 +26,7 @@
"pestphp/pest-plugin-mutate": "^4.0.1",
"pestphp/pest-plugin-profanity": "^4.2.0",
"phpunit/phpunit": "^12.4.4",
- "symfony/process": "^7.3.4"
+ "symfony/process": "^7.4.0|^8.0.0"
},
"conflict": {
"filp/whoops": "<2.18.3",
@@ -58,7 +58,7 @@
"pestphp/pest-dev-tools": "^4.0.0",
"pestphp/pest-plugin-browser": "^4.1.1",
"pestphp/pest-plugin-type-coverage": "^4.0.3",
- "psy/psysh": "^0.12.14"
+ "psy/psysh": "^0.12.15"
},
"minimum-stability": "dev",
"prefer-stable": true,
diff --git a/src/Pest.php b/src/Pest.php
index 6cd70729..87c9c7d0 100644
--- a/src/Pest.php
+++ b/src/Pest.php
@@ -6,7 +6,7 @@ namespace Pest;
function version(): string
{
- return '4.1.5';
+ return '4.1.6';
}
function testDirectory(string $file = ''): string
diff --git a/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap b/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
index 4d83f2c5..ce4d6375 100644
--- a/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
+++ b/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
@@ -1,5 +1,5 @@
- Pest Testing Framework 4.1.5.
+ Pest Testing Framework 4.1.6.
USAGE: pest [options]
diff --git a/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap b/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap
index 263ca552..5963ed17 100644
--- a/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap
+++ b/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap
@@ -1,3 +1,3 @@
- Pest Testing Framework 4.1.5.
+ Pest Testing Framework 4.1.6.
From b4172e2c2e7b9aad29443b7ba20706ad66f1c029 Mon Sep 17 00:00:00 2001
From: Jack Bayliss
Date: Wed, 10 Dec 2025 14:08:06 +0000
Subject: [PATCH 09/50] bump checkout version from 5 to 6
---
.github/workflows/static.yml | 2 +-
.github/workflows/tests.yml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml
index ee71d41f..5cce40fc 100644
--- a/.github/workflows/static.yml
+++ b/.github/workflows/static.yml
@@ -19,7 +19,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: Setup PHP
uses: shivammathur/setup-php@v2
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 3879145c..68d070da 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -21,7 +21,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: Setup PHP
uses: shivammathur/setup-php@v2
From b1c997a869fa789c36bb3b47188efff33762ea17 Mon Sep 17 00:00:00 2001
From: Owen Voke
Date: Fri, 12 Dec 2025 11:54:01 +0000
Subject: [PATCH 10/50] feat: show more useful exception when `intl` extension
not found
---
src/Expectations/OppositeExpectation.php | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/Expectations/OppositeExpectation.php b/src/Expectations/OppositeExpectation.php
index eec50c63..2713c724 100644
--- a/src/Expectations/OppositeExpectation.php
+++ b/src/Expectations/OppositeExpectation.php
@@ -15,6 +15,7 @@ use Pest\Arch\PendingArchExpectation;
use Pest\Arch\SingleArchExpectation;
use Pest\Arch\Support\FileLineFinder;
use Pest\Exceptions\InvalidExpectation;
+use Pest\Exceptions\MissingDependency;
use Pest\Expectation;
use Pest\Support\Arr;
use Pest\Support\Exporter;
@@ -284,6 +285,10 @@ final readonly class OppositeExpectation
*/
public function toHaveSuspiciousCharacters(): ArchExpectation
{
+ if (! class_exists(Spoofchecker::class)) {
+ throw new MissingDependency(__FUNCTION__, 'ext-intl >= 2.0');
+ }
+
$checker = new Spoofchecker;
/** @var Expectation|string> $original */
From 6a96aed654fa139348751f6932acb6d20a2fb94d Mon Sep 17 00:00:00 2001
From: Nuno Maduro
Date: Mon, 15 Dec 2025 11:48:43 +0000
Subject: [PATCH 11/50] feat: adds `phpunit@12.5` support
---
composer.json | 10 +++++-----
rector.php | 4 ++--
src/Pest.php | 2 +-
src/Plugins/Help.php | 1 +
.../Help/visual_snapshot_of_help_command_output.snap | 4 +++-
.../visual_snapshot_of_help_command_output.snap | 2 +-
tests/Visual/Parallel.php | 2 +-
7 files changed, 14 insertions(+), 11 deletions(-)
diff --git a/composer.json b/composer.json
index ddc8aeef..e2514f05 100644
--- a/composer.json
+++ b/composer.json
@@ -18,19 +18,19 @@
],
"require": {
"php": "^8.3.0",
- "brianium/paratest": "^7.14.2",
+ "brianium/paratest": "^7.16.0",
"nunomaduro/collision": "^8.8.3",
"nunomaduro/termwind": "^2.3.3",
"pestphp/pest-plugin": "^4.0.0",
"pestphp/pest-plugin-arch": "^4.0.0",
"pestphp/pest-plugin-mutate": "^4.0.1",
- "pestphp/pest-plugin-profanity": "^4.2.0",
- "phpunit/phpunit": "^12.4.4",
+ "pestphp/pest-plugin-profanity": "^4.2.1",
+ "phpunit/phpunit": "^12.5.3",
"symfony/process": "^7.4.0|^8.0.0"
},
"conflict": {
"filp/whoops": "<2.18.3",
- "phpunit/phpunit": ">12.4.4",
+ "phpunit/phpunit": ">12.5.3",
"sebastian/exporter": "<7.0.0",
"webmozart/assert": "<1.11.0"
},
@@ -58,7 +58,7 @@
"pestphp/pest-dev-tools": "^4.0.0",
"pestphp/pest-plugin-browser": "^4.1.1",
"pestphp/pest-plugin-type-coverage": "^4.0.3",
- "psy/psysh": "^0.12.15"
+ "psy/psysh": "^0.12.17"
},
"minimum-stability": "dev",
"prefer-stable": true,
diff --git a/rector.php b/rector.php
index 3ec9fb23..de460955 100644
--- a/rector.php
+++ b/rector.php
@@ -2,10 +2,10 @@
declare(strict_types=1);
-use Rector\CodingStyle\Rector\FunctionLike\FunctionLikeToFirstClassCallableRector;
use Rector\Config\RectorConfig;
use Rector\TypeDeclaration\Rector\ClassMethod\NarrowObjectReturnTypeRector;
use Rector\TypeDeclaration\Rector\ClassMethod\ReturnNeverTypeRector;
+use Rector\CodingStyle\Rector\ArrowFunction\ArrowFunctionDelegatingCallToFirstClassCallableRector;
return RectorConfig::configure()
->withPaths([
@@ -14,7 +14,7 @@ return RectorConfig::configure()
->withSkip([
__DIR__.'/src/Plugins/Parallel/Paratest/WrapperRunner.php',
ReturnNeverTypeRector::class,
- FunctionLikeToFirstClassCallableRector::class,
+ ArrowFunctionDelegatingCallToFirstClassCallableRector::class,
NarrowObjectReturnTypeRector::class,
])
->withPreparedSets(
diff --git a/src/Pest.php b/src/Pest.php
index 87c9c7d0..be8e6d71 100644
--- a/src/Pest.php
+++ b/src/Pest.php
@@ -6,7 +6,7 @@ namespace Pest;
function version(): string
{
- return '4.1.6';
+ return '4.2.0';
}
function testDirectory(string $file = ''): string
diff --git a/src/Plugins/Help.php b/src/Plugins/Help.php
index 89a47b66..049d119e 100644
--- a/src/Plugins/Help.php
+++ b/src/Plugins/Help.php
@@ -99,6 +99,7 @@ final readonly class Help implements HandlesArguments
{
$helpReflection = new PHPUnitHelp;
+ // @phpstan-ignore-next-line
$content = (fn (): array => $this->elements())->call($helpReflection);
$content['Configuration'] = [...[[
diff --git a/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap b/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
index ce4d6375..54d75c94 100644
--- a/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
+++ b/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
@@ -1,5 +1,5 @@
- Pest Testing Framework 4.1.6.
+ Pest Testing Framework 4.2.0.
USAGE: pest [options]
@@ -27,6 +27,7 @@
--pr .... Output to standard output tests with the given pull request number
--pull-request Output to standard output tests with the given pull request number (alias for --pr)
--retry Run non-passing tests first and stop execution upon first error or failure
+ --all .................... Ignore test selection from XML configuration file
--list-suites ................................... List available test suites
--testsuite [name] ......... Only run tests from the specified test suite(s)
--exclude-testsuite [name] .. Exclude tests from the specified test suite(s)
@@ -138,6 +139,7 @@
--only-summary-for-coverage-text Option for code coverage report in text format: only show summary
--show-uncovered-for-coverage-text Option for code coverage report in text format: show uncovered files
--coverage-xml [dir] . Write code coverage report in XML format to directory
+ --exclude-source-from-xml-coverage Exclude [source] element from code coverage report in XML format
--warm-coverage-cache ........................... Warm static analysis cache
--coverage-filter [dir] ........... Include [dir] in code coverage reporting
--path-coverage .......... Report path coverage in addition to line coverage
diff --git a/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap b/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap
index 5963ed17..74ee35dc 100644
--- a/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap
+++ b/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap
@@ -1,3 +1,3 @@
- Pest Testing Framework 4.1.6.
+ Pest Testing Framework 4.2.0.
diff --git a/tests/Visual/Parallel.php b/tests/Visual/Parallel.php
index f70c2826..93d2059d 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, 39 todos, 26 skipped, 1178 passed (2790 assertions)')
+ ->toContain('Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 39 todos, 26 skipped, 1177 passed (2790 assertions)')
->toContain('Parallel: 3 processes');
})->skipOnWindows();
From 62694c14b9c39b21d02c6102919cf0b638e06bf9 Mon Sep 17 00:00:00 2001
From: Nuno Maduro
Date: Mon, 15 Dec 2025 11:54:12 +0000
Subject: [PATCH 12/50] chore: style
---
rector.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/rector.php b/rector.php
index de460955..193407f6 100644
--- a/rector.php
+++ b/rector.php
@@ -2,10 +2,10 @@
declare(strict_types=1);
+use Rector\CodingStyle\Rector\ArrowFunction\ArrowFunctionDelegatingCallToFirstClassCallableRector;
use Rector\Config\RectorConfig;
use Rector\TypeDeclaration\Rector\ClassMethod\NarrowObjectReturnTypeRector;
use Rector\TypeDeclaration\Rector\ClassMethod\ReturnNeverTypeRector;
-use Rector\CodingStyle\Rector\ArrowFunction\ArrowFunctionDelegatingCallToFirstClassCallableRector;
return RectorConfig::configure()
->withPaths([
From 44e315df986d6e49f5aa4525935721943af0ac70 Mon Sep 17 00:00:00 2001
From: leo
Date: Mon, 22 Dec 2025 11:02:28 +0100
Subject: [PATCH 13/50] feat: add --dirty documentation in --help
---
src/Plugins/Help.php | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/Plugins/Help.php b/src/Plugins/Help.php
index 049d119e..096f2914 100644
--- a/src/Plugins/Help.php
+++ b/src/Plugins/Help.php
@@ -142,6 +142,9 @@ final readonly class Help implements HandlesArguments
], [
'arg' => '--retry',
'desc' => 'Run non-passing tests first and stop execution upon first error or failure',
+ ], [
+ 'arg' => '--dirty',
+ 'desc' => 'Only run tests that have uncommitted changes according to Git',
], ...$content['Selection']];
$content['Reporting'] = [...$content['Reporting'], ...[
From be90610f1784ea19ffaa508be4a62d00f8de8362 Mon Sep 17 00:00:00 2001
From: Willem-Jaap
Date: Tue, 30 Dec 2025 09:24:05 +0100
Subject: [PATCH 14/50] feat: add pest only function to mark each test in a
file as only
---
src/Configuration.php | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/src/Configuration.php b/src/Configuration.php
index fb4f45a4..4ca74d38 100644
--- a/src/Configuration.php
+++ b/src/Configuration.php
@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Pest;
+use Pest\PendingCalls\BeforeEachCall;
use Pest\PendingCalls\UsesCall;
/**
@@ -24,7 +25,7 @@ final readonly class Configuration
public function __construct(
string $filename,
) {
- $this->filename = str_ends_with($filename, DIRECTORY_SEPARATOR.'Pest.php') ? dirname($filename) : $filename;
+ $this->filename = str_ends_with($filename, DIRECTORY_SEPARATOR . 'Pest.php') ? dirname($filename) : $filename;
}
/**
@@ -62,6 +63,14 @@ final readonly class Configuration
return (new UsesCall($this->filename, []))->group(...$groups);
}
+ /**
+ * Marks all tests in the current file to be run exclusively.
+ */
+ public function only(): void
+ {
+ (new BeforeEachCall(TestSuite::getInstance(), $this->filename))->only();
+ }
+
/**
* Depending on where is called, it will extend the given classes and traits globally or locally.
*/
From c157b661f2668e456105b6ebf8cc657da98e33bf Mon Sep 17 00:00:00 2001
From: Willem-Jaap
Date: Tue, 30 Dec 2025 09:26:35 +0100
Subject: [PATCH 15/50] style: format
---
src/Configuration.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Configuration.php b/src/Configuration.php
index 4ca74d38..4261f3ef 100644
--- a/src/Configuration.php
+++ b/src/Configuration.php
@@ -25,7 +25,7 @@ final readonly class Configuration
public function __construct(
string $filename,
) {
- $this->filename = str_ends_with($filename, DIRECTORY_SEPARATOR . 'Pest.php') ? dirname($filename) : $filename;
+ $this->filename = str_ends_with($filename, DIRECTORY_SEPARATOR.'Pest.php') ? dirname($filename) : $filename;
}
/**
From e86bec3e68f1874c112ca782fb9db1333f3fe7ab Mon Sep 17 00:00:00 2001
From: Nuno Maduro
Date: Tue, 30 Dec 2025 14:48:33 -0500
Subject: [PATCH 16/50] release: 4.3.0
---
composer.json | 6 +++---
rector.php | 2 ++
src/Pest.php | 2 +-
.../Visual/Help/visual_snapshot_of_help_command_output.snap | 3 ++-
.../Version/visual_snapshot_of_help_command_output.snap | 2 +-
5 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/composer.json b/composer.json
index e2514f05..985e5630 100644
--- a/composer.json
+++ b/composer.json
@@ -25,12 +25,12 @@
"pestphp/pest-plugin-arch": "^4.0.0",
"pestphp/pest-plugin-mutate": "^4.0.1",
"pestphp/pest-plugin-profanity": "^4.2.1",
- "phpunit/phpunit": "^12.5.3",
+ "phpunit/phpunit": "^12.5.4",
"symfony/process": "^7.4.0|^8.0.0"
},
"conflict": {
"filp/whoops": "<2.18.3",
- "phpunit/phpunit": ">12.5.3",
+ "phpunit/phpunit": ">12.5.4",
"sebastian/exporter": "<7.0.0",
"webmozart/assert": "<1.11.0"
},
@@ -58,7 +58,7 @@
"pestphp/pest-dev-tools": "^4.0.0",
"pestphp/pest-plugin-browser": "^4.1.1",
"pestphp/pest-plugin-type-coverage": "^4.0.3",
- "psy/psysh": "^0.12.17"
+ "psy/psysh": "^0.12.18"
},
"minimum-stability": "dev",
"prefer-stable": true,
diff --git a/rector.php b/rector.php
index 193407f6..caec3188 100644
--- a/rector.php
+++ b/rector.php
@@ -4,6 +4,7 @@ declare(strict_types=1);
use Rector\CodingStyle\Rector\ArrowFunction\ArrowFunctionDelegatingCallToFirstClassCallableRector;
use Rector\Config\RectorConfig;
+use Rector\DeadCode\Rector\ClassMethod\RemoveParentDelegatingConstructorRector;
use Rector\TypeDeclaration\Rector\ClassMethod\NarrowObjectReturnTypeRector;
use Rector\TypeDeclaration\Rector\ClassMethod\ReturnNeverTypeRector;
@@ -16,6 +17,7 @@ return RectorConfig::configure()
ReturnNeverTypeRector::class,
ArrowFunctionDelegatingCallToFirstClassCallableRector::class,
NarrowObjectReturnTypeRector::class,
+ RemoveParentDelegatingConstructorRector::class,
])
->withPreparedSets(
deadCode: true,
diff --git a/src/Pest.php b/src/Pest.php
index be8e6d71..6c177561 100644
--- a/src/Pest.php
+++ b/src/Pest.php
@@ -6,7 +6,7 @@ namespace Pest;
function version(): string
{
- return '4.2.0';
+ return '4.3.0';
}
function testDirectory(string $file = ''): string
diff --git a/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap b/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
index 54d75c94..53508b51 100644
--- a/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
+++ b/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
@@ -1,5 +1,5 @@
- Pest Testing Framework 4.2.0.
+ Pest Testing Framework 4.3.0.
USAGE: pest [options]
@@ -27,6 +27,7 @@
--pr .... Output to standard output tests with the given pull request number
--pull-request Output to standard output tests with the given pull request number (alias for --pr)
--retry Run non-passing tests first and stop execution upon first error or failure
+ --dirty ...... Only run tests that have uncommitted changes according to Git
--all .................... Ignore test selection from XML configuration file
--list-suites ................................... List available test suites
--testsuite [name] ......... Only run tests from the specified test suite(s)
diff --git a/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap b/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap
index 74ee35dc..523376c6 100644
--- a/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap
+++ b/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap
@@ -1,3 +1,3 @@
- Pest Testing Framework 4.2.0.
+ Pest Testing Framework 4.3.0.
From 9fe61e0e561119885f5738de2a475a2e395edbec Mon Sep 17 00:00:00 2001
From: nuno maduro
Date: Sat, 3 Jan 2026 18:07:02 -0500
Subject: [PATCH 17/50] docs: update sponsors
Removed and updated sponsor links in the README.
---
README.md | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)
diff --git a/README.md b/README.md
index 9c83a3a4..67ba78d4 100644
--- a/README.md
+++ b/README.md
@@ -30,24 +30,22 @@ We cannot thank our sponsors enough for their incredible support in funding Pest
### Platinum Sponsors
-- **[Laracasts](https://laracasts.com/?ref=pestphp)**
-- **[NativePHP](https://nativephp.com/mobile?ref=pestphp.com)**
+- **[CodeRabbit](https://coderabbit.ai/?ref=pestphp)**
+- **[Devin](https://devin.ai/?ref=nunomaduro)**
+- **[Mailtrap](https://l.rw.rw/pestphp)**
+- **[Tighten](https://tighten.com/?ref=nunomaduro)**
+- **[Redberry](https://redberry.international/laravel-development/?utm_source=pest&utm_medium=banner&utm_campaign=pest_sponsorship)**
### Gold Sponsors
-- **[CodeRabbit](https://coderabbit.ai/?ref=pestphp)**
- **[CMS Max](https://cmsmax.com/?ref=pestphp)**
### Premium Sponsors
-- [Forge](https://forge.laravel.com/?ref=pestphp)
-- [Zapiet](https://www.zapiet.com/?ref=pestphp)
-- [Localazy](https://localazy.com/?ref=pestphp)
+- [Zapiet](https://zapiet.com/?ref=pestphp)
- [Load Forge](https://loadforge.com/?ref=pestphp)
-- [DocuWriter.ai](https://www.docuwriter.ai/?ref=pestphp)
-- [Route4Me](https://www.route4me.com/?ref=pestphp)
-- [Devtools for Livewire](https://devtools-for-livewire.com/?ref=pestphp)
-- [Nerdify](https://www.getnerdify.com/?ref=pestphp)
+- [Route4Me](https://route4me.com/pt?ref=pestphp)
+- [Nerdify](https://getnerdify.com/?ref=pestphp)
- [Akaunting](https://akaunting.com/?ref=pestphp)
- [LambdaTest](https://lambdatest.com/?ref=pestphp)
From 3a566b100ed584842b622266766b4d38d897341e Mon Sep 17 00:00:00 2001
From: nuno maduro
Date: Sun, 4 Jan 2026 11:04:03 -0500
Subject: [PATCH 18/50] docs: why php
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index 67ba78d4..ed0020c0 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,7 @@
+
From bc39830d8ae536d01644fa012279855eeaa5943b Mon Sep 17 00:00:00 2001
From: nuno maduro
Date: Sun, 4 Jan 2026 11:25:57 -0500
Subject: [PATCH 19/50] chore: removes `toHaveSuspiciousCharacters` from php
preset
---
src/ArchPresets/Php.php | 4 ----
1 file changed, 4 deletions(-)
diff --git a/src/ArchPresets/Php.php b/src/ArchPresets/Php.php
index b70a2a11..90b6985c 100644
--- a/src/ArchPresets/Php.php
+++ b/src/ArchPresets/Php.php
@@ -92,9 +92,5 @@ final class Php extends AbstractPreset
'xdebug_var_dump',
'trap',
])->not->toBeUsed();
-
- $this->eachUserNamespace(
- fn (Expectation $namespace): ArchExpectation => $namespace->not->toHaveSuspiciousCharacters(),
- );
}
}
From bc57a84e77afd4544ff9643a6858f68d05aeab96 Mon Sep 17 00:00:00 2001
From: Nuno Maduro
Date: Sun, 4 Jan 2026 11:29:59 -0500
Subject: [PATCH 20/50] release: 4.3.1
---
composer.json | 2 +-
src/ArchPresets/Php.php | 3 ---
src/Pest.php | 2 +-
.../Visual/Help/visual_snapshot_of_help_command_output.snap | 2 +-
.../Visual/Version/visual_snapshot_of_help_command_output.snap | 2 +-
tests/.snapshots/success.txt | 2 +-
tests/Visual/Parallel.php | 2 +-
7 files changed, 6 insertions(+), 9 deletions(-)
diff --git a/composer.json b/composer.json
index 985e5630..4961418b 100644
--- a/composer.json
+++ b/composer.json
@@ -26,7 +26,7 @@
"pestphp/pest-plugin-mutate": "^4.0.1",
"pestphp/pest-plugin-profanity": "^4.2.1",
"phpunit/phpunit": "^12.5.4",
- "symfony/process": "^7.4.0|^8.0.0"
+ "symfony/process": "^7.4.3|^8.0.0"
},
"conflict": {
"filp/whoops": "<2.18.3",
diff --git a/src/ArchPresets/Php.php b/src/ArchPresets/Php.php
index 90b6985c..22b409b6 100644
--- a/src/ArchPresets/Php.php
+++ b/src/ArchPresets/Php.php
@@ -4,9 +4,6 @@ declare(strict_types=1);
namespace Pest\ArchPresets;
-use Pest\Arch\Contracts\ArchExpectation;
-use Pest\Expectation;
-
/**
* @internal
*/
diff --git a/src/Pest.php b/src/Pest.php
index 6c177561..f0c338df 100644
--- a/src/Pest.php
+++ b/src/Pest.php
@@ -6,7 +6,7 @@ namespace Pest;
function version(): string
{
- return '4.3.0';
+ return '4.3.1';
}
function testDirectory(string $file = ''): string
diff --git a/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap b/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
index 53508b51..52e93473 100644
--- a/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
+++ b/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
@@ -1,5 +1,5 @@
- Pest Testing Framework 4.3.0.
+ Pest Testing Framework 4.3.1.
USAGE: pest [options]
diff --git a/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap b/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap
index 523376c6..04dbacc0 100644
--- a/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap
+++ b/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap
@@ -1,3 +1,3 @@
- Pest Testing Framework 4.3.0.
+ Pest Testing Framework 4.3.1.
diff --git a/tests/.snapshots/success.txt b/tests/.snapshots/success.txt
index bfa91bb1..7b3d6f9b 100644
--- a/tests/.snapshots/success.txt
+++ b/tests/.snapshots/success.txt
@@ -1782,4 +1782,4 @@
✓ pass with dataset with ('my-datas-set-value')
✓ within describe → pass with dataset with ('my-datas-set-value')
- Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 39 todos, 35 skipped, 1188 passed (2814 assertions)
\ No newline at end of file
+ Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 39 todos, 35 skipped, 1188 passed (2813 assertions)
\ No newline at end of file
diff --git a/tests/Visual/Parallel.php b/tests/Visual/Parallel.php
index 93d2059d..1aced21d 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, 39 todos, 26 skipped, 1177 passed (2790 assertions)')
+ ->toContain('Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 39 todos, 26 skipped, 1177 passed (2789 assertions)')
->toContain('Parallel: 3 processes');
})->skipOnWindows();
From c7e4efcea4389d5da25fe86011e1aaccd472d019 Mon Sep 17 00:00:00 2001
From: Ilia Smirnov
Date: Wed, 14 Jan 2026 00:55:35 +0100
Subject: [PATCH 21/50] fix: replace `substr` with `mb_substr` in
Str::beforeLast to ensure multibyte string compatibility and correct TeamCity
test names for datasets in "describe" blocks
---
src/Support/Str.php | 2 +-
tests/.snapshots/SuccessOnly.php.inc | 8 ++++++--
tests/.tests/SuccessOnly.php | 6 ++++++
tests/Visual/JUnit.php | 4 ++--
4 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/src/Support/Str.php b/src/Support/Str.php
index 6e32c05d..04f4b1fd 100644
--- a/src/Support/Str.php
+++ b/src/Support/Str.php
@@ -79,7 +79,7 @@ final class Str
return $subject;
}
- return substr($subject, 0, $pos);
+ return mb_substr($subject, 0, $pos);
}
/**
diff --git a/tests/.snapshots/SuccessOnly.php.inc b/tests/.snapshots/SuccessOnly.php.inc
index b00a0e36..b940b7b6 100644
--- a/tests/.snapshots/SuccessOnly.php.inc
+++ b/tests/.snapshots/SuccessOnly.php.inc
@@ -1,5 +1,5 @@
##teamcity[testSuiteStarted name='Tests/tests/SuccessOnly' locationHint='pest_qn://tests/.tests/SuccessOnly.php' flowId='1234']
-##teamcity[testCount count='3' flowId='1234']
+##teamcity[testCount count='4' flowId='1234']
##teamcity[testStarted name='it can pass with comparison' locationHint='pest_qn://tests/.tests/SuccessOnly.php::it can pass with comparison' flowId='1234']
##teamcity[testFinished name='it can pass with comparison' duration='100000' flowId='1234']
##teamcity[testStarted name='can also pass' locationHint='pest_qn://tests/.tests/SuccessOnly.php::can also pass' flowId='1234']
@@ -8,8 +8,12 @@
##teamcity[testStarted name='can pass with dataset with data set "(true)"' locationHint='pest_qn://tests/.tests/SuccessOnly.php::can pass with dataset with data set "(true)"' flowId='1234']
##teamcity[testFinished name='can pass with dataset with data set "(true)"' duration='100000' flowId='1234']
##teamcity[testSuiteFinished name='can pass with dataset' flowId='1234']
+##teamcity[testSuiteStarted name='`block` → can pass with dataset in describe block' locationHint='pest_qn://tests/.tests/SuccessOnly.php::`block` → can pass with dataset in describe block' flowId='1234']
+##teamcity[testStarted name='`block` → can pass with dataset in describe block with data set "(1)"' locationHint='pest_qn://tests/.tests/SuccessOnly.php::`block` → can pass with dataset in describe block with data set "(1)"' flowId='1234']
+##teamcity[testFinished name='`block` → can pass with dataset in describe block with data set "(1)"' duration='100000' flowId='1234']
+##teamcity[testSuiteFinished name='`block` → can pass with dataset in describe block' flowId='1234']
##teamcity[testSuiteFinished name='Tests/tests/SuccessOnly' flowId='1234']
- [90mTests:[39m [32;1m3 passed[39;22m[90m (3 assertions)[39m
+ [90mTests:[39m [32;1m4 passed[39;22m[90m (4 assertions)[39m
[90mDuration:[39m [39m1.00s[39m
diff --git a/tests/.tests/SuccessOnly.php b/tests/.tests/SuccessOnly.php
index cb4009a6..4d231a8d 100644
--- a/tests/.tests/SuccessOnly.php
+++ b/tests/.tests/SuccessOnly.php
@@ -13,3 +13,9 @@ test('can also pass', function () {
test('can pass with dataset', function ($value) {
expect($value)->toEqual(true);
})->with([true]);
+
+describe('block', function () {
+ test('can pass with dataset in describe block', function ($number) {
+ expect($number)->toBeInt();
+ })->with([1]);
+});
diff --git a/tests/Visual/JUnit.php b/tests/Visual/JUnit.php
index 3523bdd6..fd34ea7a 100644
--- a/tests/Visual/JUnit.php
+++ b/tests/Visual/JUnit.php
@@ -36,8 +36,8 @@ test('junit output', function () use ($normalizedPath, $run) {
expect($result['testsuite']['@attributes'])
->name->toBe('Tests\tests\SuccessOnly')
->file->toBe($normalizedPath('tests/.tests/SuccessOnly.php'))
- ->tests->toBe('3')
- ->assertions->toBe('3')
+ ->tests->toBe('4')
+ ->assertions->toBe('4')
->errors->toBe('0')
->failures->toBe('0')
->skipped->toBe('0');
From 3a4329ddc7a2b67c19fca8342a668b39be3ae398 Mon Sep 17 00:00:00 2001
From: Nuno Maduro
Date: Wed, 28 Jan 2026 01:01:19 +0000
Subject: [PATCH 22/50] release: 4.3.2
---
composer.json | 10 +++++-----
src/Pest.php | 2 +-
src/Support/HigherOrderCallables.php | 1 +
.../Help/visual_snapshot_of_help_command_output.snap | 2 +-
.../visual_snapshot_of_help_command_output.snap | 2 +-
5 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/composer.json b/composer.json
index 4961418b..9d7fcdee 100644
--- a/composer.json
+++ b/composer.json
@@ -18,19 +18,19 @@
],
"require": {
"php": "^8.3.0",
- "brianium/paratest": "^7.16.0",
+ "brianium/paratest": "^7.16.1",
"nunomaduro/collision": "^8.8.3",
"nunomaduro/termwind": "^2.3.3",
"pestphp/pest-plugin": "^4.0.0",
"pestphp/pest-plugin-arch": "^4.0.0",
"pestphp/pest-plugin-mutate": "^4.0.1",
"pestphp/pest-plugin-profanity": "^4.2.1",
- "phpunit/phpunit": "^12.5.4",
- "symfony/process": "^7.4.3|^8.0.0"
+ "phpunit/phpunit": "^12.5.8",
+ "symfony/process": "^7.4.4|^8.0.0"
},
"conflict": {
"filp/whoops": "<2.18.3",
- "phpunit/phpunit": ">12.5.4",
+ "phpunit/phpunit": ">12.5.8",
"sebastian/exporter": "<7.0.0",
"webmozart/assert": "<1.11.0"
},
@@ -56,7 +56,7 @@
},
"require-dev": {
"pestphp/pest-dev-tools": "^4.0.0",
- "pestphp/pest-plugin-browser": "^4.1.1",
+ "pestphp/pest-plugin-browser": "^4.2.1",
"pestphp/pest-plugin-type-coverage": "^4.0.3",
"psy/psysh": "^0.12.18"
},
diff --git a/src/Pest.php b/src/Pest.php
index f0c338df..ba3a540e 100644
--- a/src/Pest.php
+++ b/src/Pest.php
@@ -6,7 +6,7 @@ namespace Pest;
function version(): string
{
- return '4.3.1';
+ return '4.3.2';
}
function testDirectory(string $file = ''): string
diff --git a/src/Support/HigherOrderCallables.php b/src/Support/HigherOrderCallables.php
index 9e5bba36..358b4da5 100644
--- a/src/Support/HigherOrderCallables.php
+++ b/src/Support/HigherOrderCallables.php
@@ -46,6 +46,7 @@ final readonly class HigherOrderCallables
*/
public function and(mixed $value): Expectation
{
+ // @phpstan-ignore-next-line
return $this->expect($value);
}
diff --git a/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap b/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
index 52e93473..ef023f6c 100644
--- a/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
+++ b/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
@@ -1,5 +1,5 @@
- Pest Testing Framework 4.3.1.
+ Pest Testing Framework 4.3.2.
USAGE: pest [options]
diff --git a/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap b/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap
index 04dbacc0..c6a7cadf 100644
--- a/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap
+++ b/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap
@@ -1,3 +1,3 @@
- Pest Testing Framework 4.3.1.
+ Pest Testing Framework 4.3.2.
From 9fcbca69d46f395c5f403b8dccc7277b43678cda Mon Sep 17 00:00:00 2001
From: nuno maduro
Date: Fri, 13 Feb 2026 10:41:22 +0000
Subject: [PATCH 23/50] Update README.md
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index ed0020c0..33cab137 100644
--- a/README.md
+++ b/README.md
@@ -48,6 +48,6 @@ We cannot thank our sponsors enough for their incredible support in funding Pest
- [Route4Me](https://route4me.com/pt?ref=pestphp)
- [Nerdify](https://getnerdify.com/?ref=pestphp)
- [Akaunting](https://akaunting.com/?ref=pestphp)
-- [LambdaTest](https://lambdatest.com/?ref=pestphp)
+- [TestMu AI](https://www.testmuai.com/?utm_medium=sponsor&utm_source=pest)
Pest is an open-sourced software licensed under the **[MIT license](https://opensource.org/licenses/MIT)**.
From 1f39b28e2c18ead15170e52c1d8322a537a5ca62 Mon Sep 17 00:00:00 2001
From: Liam Hammett
Date: Mon, 16 Feb 2026 00:25:47 +0100
Subject: [PATCH 24/50] Allow App\Http to be used in providers
---
src/ArchPresets/Laravel.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/ArchPresets/Laravel.php b/src/ArchPresets/Laravel.php
index 7d094c36..167725b6 100644
--- a/src/ArchPresets/Laravel.php
+++ b/src/ArchPresets/Laravel.php
@@ -150,7 +150,7 @@ final class Laravel extends AbstractPreset
->toHaveSuffix('Controller');
$this->expectations[] = expect('App\Http')
- ->toOnlyBeUsedIn('App\Http');
+ ->toOnlyBeUsedIn(['App\Http', 'App\Providers']);
$this->expectations[] = expect('App\Http\Controllers')
->not->toHavePublicMethodsBesides(['__construct', '__invoke', 'index', 'show', 'create', 'store', 'edit', 'update', 'destroy', 'middleware']);
From cf00e58b7d2741eb50a038b20e370c02561d6cfd Mon Sep 17 00:00:00 2001
From: Nuno Maduro
Date: Tue, 17 Feb 2026 11:22:04 +0000
Subject: [PATCH 25/50] chore: bumps dependencies
---
composer.json | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/composer.json b/composer.json
index 9d7fcdee..36540eb1 100644
--- a/composer.json
+++ b/composer.json
@@ -18,19 +18,19 @@
],
"require": {
"php": "^8.3.0",
- "brianium/paratest": "^7.16.1",
- "nunomaduro/collision": "^8.8.3",
- "nunomaduro/termwind": "^2.3.3",
+ "brianium/paratest": "^7.19.0",
+ "nunomaduro/collision": "^8.9.0",
+ "nunomaduro/termwind": "^2.4.0",
"pestphp/pest-plugin": "^4.0.0",
"pestphp/pest-plugin-arch": "^4.0.0",
"pestphp/pest-plugin-mutate": "^4.0.1",
"pestphp/pest-plugin-profanity": "^4.2.1",
- "phpunit/phpunit": "^12.5.8",
- "symfony/process": "^7.4.4|^8.0.0"
+ "phpunit/phpunit": "^12.5.12",
+ "symfony/process": "^7.4.5|^8.0.5"
},
"conflict": {
"filp/whoops": "<2.18.3",
- "phpunit/phpunit": ">12.5.8",
+ "phpunit/phpunit": ">12.5.12",
"sebastian/exporter": "<7.0.0",
"webmozart/assert": "<1.11.0"
},
@@ -58,7 +58,7 @@
"pestphp/pest-dev-tools": "^4.0.0",
"pestphp/pest-plugin-browser": "^4.2.1",
"pestphp/pest-plugin-type-coverage": "^4.0.3",
- "psy/psysh": "^0.12.18"
+ "psy/psysh": "^0.12.20"
},
"minimum-stability": "dev",
"prefer-stable": true,
From 69cb752d02a2e80e5ebe85e73d9a2f0cea53dd5c Mon Sep 17 00:00:00 2001
From: Nuno Maduro
Date: Tue, 17 Feb 2026 15:01:37 +0000
Subject: [PATCH 26/50] chore: bumps dependencies
---
composer.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/composer.json b/composer.json
index 36540eb1..9f4ffa85 100644
--- a/composer.json
+++ b/composer.json
@@ -55,8 +55,8 @@
]
},
"require-dev": {
- "pestphp/pest-dev-tools": "^4.0.0",
- "pestphp/pest-plugin-browser": "^4.2.1",
+ "pestphp/pest-dev-tools": "^4.1.0",
+ "pestphp/pest-plugin-browser": "^4.3.0",
"pestphp/pest-plugin-type-coverage": "^4.0.3",
"psy/psysh": "^0.12.20"
},
From aaa226f6a647a2ddd176863ec9fd2d6b0237efbc Mon Sep 17 00:00:00 2001
From: Nuno Maduro
Date: Tue, 17 Feb 2026 15:14:45 +0000
Subject: [PATCH 27/50] chore: tests against symfony 8
---
.github/workflows/tests.yml | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 68d070da..8ab19811 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -13,9 +13,12 @@ jobs:
fail-fast: true
matrix:
os: [ubuntu-latest, macos-latest] # windows-latest
- symfony: ['7.3']
+ symfony: ['7.4', '8.0']
php: ['8.3', '8.4', '8.5']
dependency_version: [prefer-stable]
+ exclude:
+ - php: '8.3'
+ symfony: '8.0'
name: PHP ${{ matrix.php }} - Symfony ^${{ matrix.symfony }} - ${{ matrix.os }} - ${{ matrix.dependency_version }}
From b0f6a74cb6419b620318eb2712304f2df6d7d6a2 Mon Sep 17 00:00:00 2001
From: Nuno Maduro
Date: Tue, 17 Feb 2026 15:18:33 +0000
Subject: [PATCH 28/50] ci: makes jobs faster
---
.github/workflows/static.yml | 14 ++++++++++++++
.github/workflows/tests.yml | 14 ++++++++++++++
2 files changed, 28 insertions(+)
diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml
index 5cce40fc..ef51a559 100644
--- a/.github/workflows/static.yml
+++ b/.github/workflows/static.yml
@@ -29,6 +29,20 @@ jobs:
coverage: none
extensions: sockets
+ - name: Get Composer cache directory
+ id: composer-cache
+ shell: bash
+ run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
+
+ - name: Cache Composer dependencies
+ uses: actions/cache@v4
+ with:
+ path: ${{ steps.composer-cache.outputs.dir }}
+ key: static-php-8.3-${{ matrix.dependency-version }}-composer-${{ hashFiles('**/composer.json') }}
+ restore-keys: |
+ static-php-8.3-${{ matrix.dependency-version }}-composer-
+ static-php-8.3-composer-
+
- name: Install Dependencies
run: composer update --prefer-stable --no-interaction --no-progress --ansi
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 8ab19811..a0c1ee2c 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -34,6 +34,20 @@ jobs:
coverage: none
extensions: sockets
+ - name: Get Composer cache directory
+ id: composer-cache
+ shell: bash
+ run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
+
+ - name: Cache Composer dependencies
+ uses: actions/cache@v4
+ with:
+ path: ${{ steps.composer-cache.outputs.dir }}
+ key: ${{ matrix.os }}-php-${{ matrix.php }}-symfony-${{ matrix.symfony }}-composer-${{ hashFiles('**/composer.json') }}
+ restore-keys: |
+ ${{ matrix.os }}-php-${{ matrix.php }}-symfony-${{ matrix.symfony }}-composer-
+ ${{ matrix.os }}-php-${{ matrix.php }}-composer-
+
- name: Setup Problem Matches
run: |
echo "::add-matcher::${{ runner.tool_cache }}/php.json"
From a49cf7edc5b247c94e4e155fc1bf282df59d1edb Mon Sep 17 00:00:00 2001
From: Nuno Maduro
Date: Tue, 17 Feb 2026 15:21:20 +0000
Subject: [PATCH 29/50] ci: speed up ci
---
.github/workflows/static.yml | 7 ++++++-
.github/workflows/tests.yml | 5 +++++
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml
index ef51a559..ae45ea68 100644
--- a/.github/workflows/static.yml
+++ b/.github/workflows/static.yml
@@ -2,10 +2,15 @@ name: Static Analysis
on:
push:
+ branches: [4.x]
pull_request:
schedule:
- cron: '0 0 * * *'
+concurrency:
+ group: static-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
+ cancel-in-progress: true
+
jobs:
static:
if: github.event_name != 'schedule' || github.repository == 'pestphp/pest'
@@ -44,7 +49,7 @@ jobs:
static-php-8.3-composer-
- name: Install Dependencies
- run: composer update --prefer-stable --no-interaction --no-progress --ansi
+ run: composer update --${{ matrix.dependency-version }} --no-interaction --no-progress --ansi
- name: Profanity Check
run: composer test:profanity
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index a0c1ee2c..1f74b76e 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -2,8 +2,13 @@ name: Tests
on:
push:
+ branches: [4.x]
pull_request:
+concurrency:
+ group: tests-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
+ cancel-in-progress: true
+
jobs:
tests:
if: github.event_name != 'schedule' || github.repository == 'pestphp/pest'
From f96a1b27864b585b0b29b0ee7331176726f7e54a Mon Sep 17 00:00:00 2001
From: Nuno Maduro
Date: Tue, 17 Feb 2026 15:27:18 +0000
Subject: [PATCH 30/50] release: v4.4.1
---
src/Pest.php | 2 +-
.../Visual/Help/visual_snapshot_of_help_command_output.snap | 2 +-
.../Visual/Version/visual_snapshot_of_help_command_output.snap | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/Pest.php b/src/Pest.php
index ba3a540e..a66b7254 100644
--- a/src/Pest.php
+++ b/src/Pest.php
@@ -6,7 +6,7 @@ namespace Pest;
function version(): string
{
- return '4.3.2';
+ return '4.4.1';
}
function testDirectory(string $file = ''): string
diff --git a/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap b/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
index ef023f6c..808b1613 100644
--- a/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
+++ b/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
@@ -1,5 +1,5 @@
- Pest Testing Framework 4.3.2.
+ Pest Testing Framework 4.4.1.
USAGE: pest [options]
diff --git a/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap b/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap
index c6a7cadf..0160b757 100644
--- a/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap
+++ b/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap
@@ -1,3 +1,3 @@
- Pest Testing Framework 4.3.2.
+ Pest Testing Framework 4.4.1.
From 7d80f1d20e672b44435ded168d5478ce82967e48 Mon Sep 17 00:00:00 2001
From: Nuno Maduro
Date: Tue, 17 Feb 2026 15:34:23 +0000
Subject: [PATCH 31/50] chore: removes non used files
---
Makefile | 14 --------------
docker-compose.yml | 14 --------------
2 files changed, 28 deletions(-)
delete mode 100644 Makefile
delete mode 100644 docker-compose.yml
diff --git a/Makefile b/Makefile
deleted file mode 100644
index ec4faa84..00000000
--- a/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-# Well documented Makefiles
-DEFAULT_GOAL := help
-help:
- @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z0-9_-]+:.*?##/ { printf " \033[36m%-40s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
-
-build: ## Build all docker images. Specify the command e.g. via make build ARGS="--build-arg PHP=8.2"
- docker compose build $(ARGS)
-
-##@ [Application]
-install: ## Install the composer dependencies
- docker compose run --rm composer install
-
-test: ## Run the tests
- docker compose run --rm composer test
diff --git a/docker-compose.yml b/docker-compose.yml
deleted file mode 100644
index 70b75de2..00000000
--- a/docker-compose.yml
+++ /dev/null
@@ -1,14 +0,0 @@
-version: "3.8"
-
-services:
- php:
- build:
- context: ./docker
- volumes:
- - .:/var/www/html
- composer:
- build:
- context: ./docker
- volumes:
- - .:/var/www/html
- entrypoint: ["composer"]
From 5de8693e3bc02dbdf81d9c203d10468f9f6aa80b Mon Sep 17 00:00:00 2001
From: Nuno Maduro
Date: Tue, 17 Feb 2026 16:15:58 +0000
Subject: [PATCH 32/50] chore: style
---
src/Plugins/Parallel/Paratest/WrapperRunner.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Plugins/Parallel/Paratest/WrapperRunner.php b/src/Plugins/Parallel/Paratest/WrapperRunner.php
index 1d73e2db..064856bc 100644
--- a/src/Plugins/Parallel/Paratest/WrapperRunner.php
+++ b/src/Plugins/Parallel/Paratest/WrapperRunner.php
@@ -131,7 +131,7 @@ final class WrapperRunner implements RunnerInterface
$parameters = $this->handleLaravelHerd($parameters);
$parameters[] = $wrapper;
- $parameters[] = '--test-directory='.TestSuite::getInstance()->testPath;
+ $parameters[] = '--test-directory='.TestSuite::getInstance()->testPath;
$this->parameters = $parameters;
$this->codeCoverageFilterRegistry = new CodeCoverageFilterRegistry;
From df7b6c8454cbd286ac5bf3dd7352e776e2645a47 Mon Sep 17 00:00:00 2001
From: SimonBroekaert
Date: Fri, 22 Aug 2025 02:14:30 +0200
Subject: [PATCH 33/50] feat: add toBeCasedCorrectly arch test assertion
---
src/Expectation.php | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/src/Expectation.php b/src/Expectation.php
index 50729d7a..3a5cc94e 100644
--- a/src/Expectation.php
+++ b/src/Expectation.php
@@ -18,6 +18,7 @@ use Pest\Arch\Expectations\ToOnlyUse;
use Pest\Arch\Expectations\ToUse;
use Pest\Arch\Expectations\ToUseNothing;
use Pest\Arch\PendingArchExpectation;
+use Pest\Arch\Support\Composer;
use Pest\Arch\Support\FileLineFinder;
use Pest\Concerns\Extendable;
use Pest\Concerns\Pipeable;
@@ -669,6 +670,41 @@ final class Expectation
throw InvalidExpectation::fromMethods(['toHavePrivateMethods']);
}
+ /**
+ * Asserts that the given expectation target is cased correctly.
+ */
+ public function toBeCasedCorrectly(): ArchExpectation
+ {
+ return Targeted::make(
+ $this,
+ function (ObjectDescription $object): bool {
+ if (! isset($object->reflectionClass)) {
+ return false;
+ }
+
+ $realPath = realpath($object->path);
+
+ foreach (Composer::userNamespaces() as $directory => $namespace) {
+ if (str_starts_with($realPath, $directory)) {
+ $relativePath = substr($realPath, strlen($directory) + 1);
+ $relativePath = explode('.', $relativePath)[0];
+ $classFromPath = $namespace . '\\' . str_replace(DIRECTORY_SEPARATOR, '\\', $relativePath);
+
+ if ($classFromPath === $object->reflectionClass->getName()) {
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ return false;
+ },
+ "to be cased correctly",
+ FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
+ );
+ }
+
/**
* Asserts that the given expectation target is enum.
*/
From 1675dd1d4193b9aa5210d07ac73efeefae0ca5f6 Mon Sep 17 00:00:00 2001
From: SimonBroekaert
Date: Tue, 17 Feb 2026 19:03:46 +0100
Subject: [PATCH 34/50] chore: add tests for toBeCasedCorrectly() arch test
---
tests/Features/Expect/toBeCasedCorrectly.php | 12 ++++++++++++
.../CorrectCasing/CorrectCasing.php | 5 +++++
.../IncorrectCasing/incorrectCasing.php | 5 +++++
.../incorrectDirectoryCasing/CorrectCasing.php | 5 +++++
4 files changed, 27 insertions(+)
create mode 100644 tests/Features/Expect/toBeCasedCorrectly.php
create mode 100644 tests/Fixtures/Arch/ToBeCasedCorrectly/CorrectCasing/CorrectCasing.php
create mode 100644 tests/Fixtures/Arch/ToBeCasedCorrectly/IncorrectCasing/incorrectCasing.php
create mode 100644 tests/Fixtures/Arch/ToBeCasedCorrectly/incorrectDirectoryCasing/CorrectCasing.php
diff --git a/tests/Features/Expect/toBeCasedCorrectly.php b/tests/Features/Expect/toBeCasedCorrectly.php
new file mode 100644
index 00000000..6a8432d2
--- /dev/null
+++ b/tests/Features/Expect/toBeCasedCorrectly.php
@@ -0,0 +1,12 @@
+expect('Tests\Fixtures\Arch\ToBeCasedCorrectly\CorrectCasing')
+ ->toBeCasedCorrectly();
+
+test('failure')
+ ->expect('Tests\Fixtures\Arch\ToBeCasedCorrectly\IncorrectCasing')
+ ->toBeCasedCorrectly()
+ ->throws(ArchExpectationFailedException::class);
diff --git a/tests/Fixtures/Arch/ToBeCasedCorrectly/CorrectCasing/CorrectCasing.php b/tests/Fixtures/Arch/ToBeCasedCorrectly/CorrectCasing/CorrectCasing.php
new file mode 100644
index 00000000..8418d969
--- /dev/null
+++ b/tests/Fixtures/Arch/ToBeCasedCorrectly/CorrectCasing/CorrectCasing.php
@@ -0,0 +1,5 @@
+
Date: Fri, 20 Feb 2026 01:18:43 +0000
Subject: [PATCH 35/50] Add SerpApi to the list of sponsors
Add SerpApi as a sponsor in the README.
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index 33cab137..aa128055 100644
--- a/README.md
+++ b/README.md
@@ -36,6 +36,7 @@ We cannot thank our sponsors enough for their incredible support in funding Pest
- **[Mailtrap](https://l.rw.rw/pestphp)**
- **[Tighten](https://tighten.com/?ref=nunomaduro)**
- **[Redberry](https://redberry.international/laravel-development/?utm_source=pest&utm_medium=banner&utm_campaign=pest_sponsorship)**
+- **[SerpApi](https://serpapi.com/?ref=nunomaduro)**
### Gold Sponsors
From f7015fe59c250b13457d43a25a4adfbf28ea08c2 Mon Sep 17 00:00:00 2001
From: Nuno Maduro
Date: Tue, 24 Feb 2026 10:44:48 +0000
Subject: [PATCH 36/50] chore: adjusts sponsors
---
README.md | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/README.md b/README.md
index aa128055..af33fd43 100644
--- a/README.md
+++ b/README.md
@@ -32,11 +32,10 @@ We cannot thank our sponsors enough for their incredible support in funding Pest
### Platinum Sponsors
- **[CodeRabbit](https://coderabbit.ai/?ref=pestphp)**
-- **[Devin](https://devin.ai/?ref=nunomaduro)**
- **[Mailtrap](https://l.rw.rw/pestphp)**
+- **[SerpApi](https://serpapi.com/?ref=nunomaduro)**
- **[Tighten](https://tighten.com/?ref=nunomaduro)**
- **[Redberry](https://redberry.international/laravel-development/?utm_source=pest&utm_medium=banner&utm_campaign=pest_sponsorship)**
-- **[SerpApi](https://serpapi.com/?ref=nunomaduro)**
### Gold Sponsors
From 2a80101f420a377bdf491a99f8227927b29fb5cd Mon Sep 17 00:00:00 2001
From: nuno maduro
Date: Tue, 10 Mar 2026 21:06:28 +0000
Subject: [PATCH 37/50] chore: update styling
---
composer.json | 4 ++--
overrides/Logging/JUnit/JunitXmlLogger.php | 7 +++++--
src/Concerns/Pipeable.php | 2 +-
src/Concerns/Testable.php | 6 +++---
src/Expectation.php | 4 ++--
src/Factories/TestCaseFactory.php | 3 ++-
src/Factories/TestCaseMethodFactory.php | 12 ++++++++----
src/Functions.php | 8 ++++----
src/Logging/Converter.php | 4 ++--
src/Logging/TeamCity/TeamCityLogger.php | 2 +-
src/Mixins/Expectation.php | 5 +++--
src/PendingCalls/Concerns/Describable.php | 6 ++++--
src/PendingCalls/DescribeCall.php | 2 +-
src/PendingCalls/TestCall.php | 12 ++++++++----
src/Plugins/Parallel/Handlers/Laravel.php | 5 +++--
src/Support/Closure.php | 4 ++--
src/Support/Container.php | 2 +-
src/Support/Reflection.php | 7 ++++---
tests/Autoload.php | 6 ++++--
tests/Features/BeforeAll.php | 2 +-
tests/Features/Coverage.php | 2 +-
tests/Features/Helpers.php | 2 +-
tests/Helpers.php | 4 +++-
.../CustomAffixes/FolderWithAn@/ExampleTest.php | 3 ++-
tests/PHPUnit/CustomTestCase/UsesPerDirectory.php | 4 +++-
.../SubFolder2/UsesPerFile.php | 4 +++-
tests/Unit/Configuration/Theme.php | 4 +++-
tests/Visual/Collision.php | 4 +++-
tests/Visual/Help.php | 4 +++-
tests/Visual/Success.php | 4 +++-
tests/Visual/TeamCity.php | 4 +++-
tests/Visual/Version.php | 4 +++-
32 files changed, 92 insertions(+), 54 deletions(-)
diff --git a/composer.json b/composer.json
index 9f4ffa85..846dc188 100644
--- a/composer.json
+++ b/composer.json
@@ -19,7 +19,7 @@
"require": {
"php": "^8.3.0",
"brianium/paratest": "^7.19.0",
- "nunomaduro/collision": "^8.9.0",
+ "nunomaduro/collision": "^8.9.1",
"nunomaduro/termwind": "^2.4.0",
"pestphp/pest-plugin": "^4.0.0",
"pestphp/pest-plugin-arch": "^4.0.0",
@@ -58,7 +58,7 @@
"pestphp/pest-dev-tools": "^4.1.0",
"pestphp/pest-plugin-browser": "^4.3.0",
"pestphp/pest-plugin-type-coverage": "^4.0.3",
- "psy/psysh": "^0.12.20"
+ "psy/psysh": "^0.12.21"
},
"minimum-stability": "dev",
"prefer-stable": true,
diff --git a/overrides/Logging/JUnit/JunitXmlLogger.php b/overrides/Logging/JUnit/JunitXmlLogger.php
index b7362b1f..1fc237a6 100644
--- a/overrides/Logging/JUnit/JunitXmlLogger.php
+++ b/overrides/Logging/JUnit/JunitXmlLogger.php
@@ -14,6 +14,9 @@ namespace PHPUnit\Logging\JUnit;
use DOMDocument;
use DOMElement;
+use Pest\Logging\Converter;
+use Pest\Support\Container;
+use Pest\TestSuite;
use PHPUnit\Event\Code\Test;
use PHPUnit\Event\Code\TestMethod;
use PHPUnit\Event\EventFacadeIsSealedException;
@@ -50,7 +53,7 @@ final class JunitXmlLogger
{
private readonly Printer $printer;
- private readonly \Pest\Logging\Converter $converter; // pest-added
+ private readonly Converter $converter; // pest-added
private DOMDocument $document;
@@ -108,7 +111,7 @@ final class JunitXmlLogger
public function __construct(Printer $printer, Facade $facade)
{
$this->printer = $printer;
- $this->converter = new \Pest\Logging\Converter(\Pest\Support\Container::getInstance()->get(\Pest\TestSuite::class)->rootPath); // pest-added
+ $this->converter = new Converter(Container::getInstance()->get(TestSuite::class)->rootPath); // pest-added
$this->registerSubscribers($facade);
$this->createDocument();
diff --git a/src/Concerns/Pipeable.php b/src/Concerns/Pipeable.php
index 63ab0b7d..4e44f8db 100644
--- a/src/Concerns/Pipeable.php
+++ b/src/Concerns/Pipeable.php
@@ -66,6 +66,6 @@ trait Pipeable
*/
private function pipes(string $name, object $context, string $scope): array
{
- return array_map(fn (Closure $pipe): \Closure => $pipe->bindTo($context, $scope), self::$pipes[$name] ?? []);
+ return array_map(fn (Closure $pipe): Closure => $pipe->bindTo($context, $scope), self::$pipes[$name] ?? []);
}
}
diff --git a/src/Concerns/Testable.php b/src/Concerns/Testable.php
index 767a7c69..7ed0887d 100644
--- a/src/Concerns/Testable.php
+++ b/src/Concerns/Testable.php
@@ -129,7 +129,7 @@ trait Testable
*/
public function __addBeforeAll(?Closure $hook): void
{
- if (! $hook instanceof \Closure) {
+ if (! $hook instanceof Closure) {
return;
}
@@ -143,7 +143,7 @@ trait Testable
*/
public function __addAfterAll(?Closure $hook): void
{
- if (! $hook instanceof \Closure) {
+ if (! $hook instanceof Closure) {
return;
}
@@ -173,7 +173,7 @@ trait Testable
*/
private function __addHook(string $property, ?Closure $hook): void
{
- if (! $hook instanceof \Closure) {
+ if (! $hook instanceof Closure) {
return;
}
diff --git a/src/Expectation.php b/src/Expectation.php
index 50729d7a..d9ce935a 100644
--- a/src/Expectation.php
+++ b/src/Expectation.php
@@ -136,7 +136,7 @@ final class Expectation
/**
* Dump the expectation value when the result of the condition is truthy.
*
- * @param (\Closure(TValue): bool)|bool $condition
+ * @param (Closure(TValue): bool)|bool $condition
* @return self
*/
public function ddWhen(Closure|bool $condition, mixed ...$arguments): Expectation
@@ -153,7 +153,7 @@ final class Expectation
/**
* Dump the expectation value when the result of the condition is falsy.
*
- * @param (\Closure(TValue): bool)|bool $condition
+ * @param (Closure(TValue): bool)|bool $condition
* @return self
*/
public function ddUnless(Closure|bool $condition, mixed ...$arguments): Expectation
diff --git a/src/Factories/TestCaseFactory.php b/src/Factories/TestCaseFactory.php
index 0d2a0978..3349d03d 100644
--- a/src/Factories/TestCaseFactory.php
+++ b/src/Factories/TestCaseFactory.php
@@ -17,6 +17,7 @@ use Pest\Factories\Concerns\HigherOrderable;
use Pest\Support\Reflection;
use Pest\Support\Str;
use Pest\TestSuite;
+use PHPUnit\Framework\Attributes\TestDox;
use PHPUnit\Framework\TestCase;
use RuntimeException;
@@ -135,7 +136,7 @@ final class TestCaseFactory
$this->attributes = [
new Attribute(
- \PHPUnit\Framework\Attributes\TestDox::class,
+ TestDox::class,
[$this->filename],
),
...$this->attributes,
diff --git a/src/Factories/TestCaseMethodFactory.php b/src/Factories/TestCaseMethodFactory.php
index c88db44d..9438f837 100644
--- a/src/Factories/TestCaseMethodFactory.php
+++ b/src/Factories/TestCaseMethodFactory.php
@@ -9,10 +9,14 @@ use Pest\Evaluators\Attributes;
use Pest\Exceptions\ShouldNotHappen;
use Pest\Factories\Concerns\HigherOrderable;
use Pest\Repositories\DatasetsRepository;
+use Pest\Support\Description;
use Pest\Support\Str;
use Pest\TestSuite;
use PHPUnit\Framework\Assert;
use PHPUnit\Framework\Attributes\DataProvider;
+use PHPUnit\Framework\Attributes\Depends;
+use PHPUnit\Framework\Attributes\Test;
+use PHPUnit\Framework\Attributes\TestDox;
use PHPUnit\Framework\TestCase;
/**
@@ -32,7 +36,7 @@ final class TestCaseMethodFactory
/**
* The test's describing, if any.
*
- * @var array
+ * @var array
*/
public array $describing = [];
@@ -192,11 +196,11 @@ final class TestCaseMethodFactory
$this->attributes = [
new Attribute(
- \PHPUnit\Framework\Attributes\Test::class,
+ Test::class,
[],
),
new Attribute(
- \PHPUnit\Framework\Attributes\TestDox::class,
+ TestDox::class,
[str_replace('*/', '{@*}', $this->description)],
),
...$this->attributes,
@@ -206,7 +210,7 @@ final class TestCaseMethodFactory
$depend = Str::evaluable($this->describing === [] ? $depend : Str::describe($this->describing, $depend));
$this->attributes[] = new Attribute(
- \PHPUnit\Framework\Attributes\Depends::class,
+ Depends::class,
[$depend],
);
}
diff --git a/src/Functions.php b/src/Functions.php
index 0ed631f3..42331a56 100644
--- a/src/Functions.php
+++ b/src/Functions.php
@@ -140,7 +140,7 @@ if (! function_exists('test')) {
*/
function test(?string $description = null, ?Closure $closure = null): HigherOrderTapProxy|TestCall
{
- if ($description === null && TestSuite::getInstance()->test instanceof \PHPUnit\Framework\TestCase) {
+ if ($description === null && TestSuite::getInstance()->test instanceof TestCase) {
return new HigherOrderTapProxy(TestSuite::getInstance()->test);
}
@@ -236,7 +236,7 @@ if (! function_exists('covers')) {
/** @var MutationTestRunner $runner */
$runner = Container::getInstance()->get(MutationTestRunner::class);
- /** @var \Pest\Mutate\Repositories\ConfigurationRepository $configurationRepository */
+ /** @var ConfigurationRepository $configurationRepository */
$configurationRepository = Container::getInstance()->get(ConfigurationRepository::class);
$everything = $configurationRepository->cliConfiguration->toArray()['everything'] ?? false;
$classes = $configurationRepository->cliConfiguration->toArray()['classes'] ?? false;
@@ -263,7 +263,7 @@ if (! function_exists('mutates')) {
/** @var MutationTestRunner $runner */
$runner = Container::getInstance()->get(MutationTestRunner::class);
- /** @var \Pest\Mutate\Repositories\ConfigurationRepository $configurationRepository */
+ /** @var ConfigurationRepository $configurationRepository */
$configurationRepository = Container::getInstance()->get(ConfigurationRepository::class);
$everything = $configurationRepository->cliConfiguration->toArray()['everything'] ?? false;
$classes = $configurationRepository->cliConfiguration->toArray()['classes'] ?? false;
@@ -320,7 +320,7 @@ if (! function_exists('visit')) {
*/
function visit(array|string $url, array $options = []): ArrayablePendingAwaitablePage|PendingAwaitablePage
{
- if (! class_exists(\Pest\Browser\Configuration::class)) {
+ if (! class_exists(Pest\Browser\Configuration::class)) {
PluginBrowser::install();
exit(0);
diff --git a/src/Logging/Converter.php b/src/Logging/Converter.php
index 50a42d1a..e0b69bb0 100644
--- a/src/Logging/Converter.php
+++ b/src/Logging/Converter.php
@@ -151,7 +151,7 @@ final readonly class Converter
{
if ($testSuite instanceof TestSuiteForTestMethodWithDataProvider) {
$firstTest = $this->getFirstTest($testSuite);
- if ($firstTest instanceof \PHPUnit\Event\Code\TestMethod) {
+ if ($firstTest instanceof TestMethod) {
return $this->getTestMethodNameWithoutDatasetSuffix($firstTest);
}
}
@@ -179,7 +179,7 @@ final readonly class Converter
public function getTestSuiteLocation(TestSuite $testSuite): ?string
{
$firstTest = $this->getFirstTest($testSuite);
- if (! $firstTest instanceof \PHPUnit\Event\Code\TestMethod) {
+ if (! $firstTest instanceof TestMethod) {
return null;
}
$path = $firstTest->testDox()->prettifiedClassName();
diff --git a/src/Logging/TeamCity/TeamCityLogger.php b/src/Logging/TeamCity/TeamCityLogger.php
index 19a7be69..cbbf0347 100644
--- a/src/Logging/TeamCity/TeamCityLogger.php
+++ b/src/Logging/TeamCity/TeamCityLogger.php
@@ -200,7 +200,7 @@ final class TeamCityLogger
public function testFinished(Finished $event): void
{
- if (! $this->time instanceof \PHPUnit\Event\Telemetry\HRTime) {
+ if (! $this->time instanceof HRTime) {
throw ShouldNotHappen::fromMessage('Start time has not been set.');
}
diff --git a/src/Mixins/Expectation.php b/src/Mixins/Expectation.php
index 09974787..f235c748 100644
--- a/src/Mixins/Expectation.php
+++ b/src/Mixins/Expectation.php
@@ -9,6 +9,7 @@ use Closure;
use Countable;
use DateTimeInterface;
use Error;
+use Illuminate\Testing\TestResponse;
use InvalidArgumentException;
use JsonSerializable;
use Pest\Exceptions\InvalidExpectationValue;
@@ -842,7 +843,7 @@ final class Expectation
is_object($this->value) && method_exists($this->value, 'toSnapshot') => $this->value->toSnapshot(),
is_object($this->value) && method_exists($this->value, '__toString') => $this->value->__toString(),
is_object($this->value) && method_exists($this->value, 'toString') => $this->value->toString(),
- $this->value instanceof \Illuminate\Testing\TestResponse => $this->value->getContent(), // @phpstan-ignore-line
+ $this->value instanceof TestResponse => $this->value->getContent(), // @phpstan-ignore-line
is_array($this->value) => json_encode($this->value, JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT),
$this->value instanceof Traversable => json_encode(iterator_to_array($this->value), JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT),
$this->value instanceof JsonSerializable => json_encode($this->value->jsonSerialize(), JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT),
@@ -983,7 +984,7 @@ final class Expectation
*/
private function export(mixed $value): string
{
- if (! $this->exporter instanceof \Pest\Support\Exporter) {
+ if (! $this->exporter instanceof Exporter) {
$this->exporter = Exporter::default();
}
diff --git a/src/PendingCalls/Concerns/Describable.php b/src/PendingCalls/Concerns/Describable.php
index 0208ea4b..cac2fb0b 100644
--- a/src/PendingCalls/Concerns/Describable.php
+++ b/src/PendingCalls/Concerns/Describable.php
@@ -4,6 +4,8 @@ declare(strict_types=1);
namespace Pest\PendingCalls\Concerns;
+use Pest\Support\Description;
+
/**
* @internal
*/
@@ -12,14 +14,14 @@ trait Describable
/**
* Note: this is property is not used; however, it gets added automatically by rector php.
*
- * @var array
+ * @var array
*/
public array $__describing;
/**
* The describing of the test case.
*
- * @var array
+ * @var array
*/
public array $describing = [];
}
diff --git a/src/PendingCalls/DescribeCall.php b/src/PendingCalls/DescribeCall.php
index 08ebc15e..712aedcb 100644
--- a/src/PendingCalls/DescribeCall.php
+++ b/src/PendingCalls/DescribeCall.php
@@ -73,7 +73,7 @@ final class DescribeCall
{
$filename = Backtrace::file();
- if (! $this->currentBeforeEachCall instanceof \Pest\PendingCalls\BeforeEachCall) {
+ if (! $this->currentBeforeEachCall instanceof BeforeEachCall) {
$this->currentBeforeEachCall = new BeforeEachCall(TestSuite::getInstance(), $filename);
$this->currentBeforeEachCall->describing[] = $this->description;
diff --git a/src/PendingCalls/TestCall.php b/src/PendingCalls/TestCall.php
index a65c8bb5..79264596 100644
--- a/src/PendingCalls/TestCall.php
+++ b/src/PendingCalls/TestCall.php
@@ -22,6 +22,10 @@ use Pest\Support\NullClosure;
use Pest\Support\Str;
use Pest\TestSuite;
use PHPUnit\Framework\AssertionFailedError;
+use PHPUnit\Framework\Attributes\CoversClass;
+use PHPUnit\Framework\Attributes\CoversFunction;
+use PHPUnit\Framework\Attributes\CoversTrait;
+use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\TestCase;
/**
@@ -211,7 +215,7 @@ final class TestCall // @phpstan-ignore-line
{
foreach ($groups as $group) {
$this->testCaseMethod->attributes[] = new Attribute(
- \PHPUnit\Framework\Attributes\Group::class,
+ Group::class,
[$group],
);
}
@@ -604,7 +608,7 @@ final class TestCall // @phpstan-ignore-line
{
foreach ($classes as $class) {
$this->testCaseFactoryAttributes[] = new Attribute(
- \PHPUnit\Framework\Attributes\CoversClass::class,
+ CoversClass::class,
[$class],
);
}
@@ -627,7 +631,7 @@ final class TestCall // @phpstan-ignore-line
{
foreach ($traits as $trait) {
$this->testCaseFactoryAttributes[] = new Attribute(
- \PHPUnit\Framework\Attributes\CoversTrait::class,
+ CoversTrait::class,
[$trait],
);
}
@@ -650,7 +654,7 @@ final class TestCall // @phpstan-ignore-line
{
foreach ($functions as $function) {
$this->testCaseFactoryAttributes[] = new Attribute(
- \PHPUnit\Framework\Attributes\CoversFunction::class,
+ CoversFunction::class,
[$function],
);
}
diff --git a/src/Plugins/Parallel/Handlers/Laravel.php b/src/Plugins/Parallel/Handlers/Laravel.php
index f634be56..30063d5f 100644
--- a/src/Plugins/Parallel/Handlers/Laravel.php
+++ b/src/Plugins/Parallel/Handlers/Laravel.php
@@ -7,6 +7,7 @@ namespace Pest\Plugins\Parallel\Handlers;
use Closure;
use Composer\InstalledVersions;
use Illuminate\Testing\ParallelRunner;
+use Orchestra\Testbench\TestCase;
use ParaTest\Options;
use ParaTest\RunnerInterface;
use Pest\Contracts\Plugins\HandlesArguments;
@@ -39,13 +40,13 @@ final class Laravel implements HandlesArguments
* Executes the given closure when running Laravel.
*
* @param array $arguments
- * @param CLosure(array): array $closure
+ * @param Closure(array): array $closure
* @return array
*/
private function whenUsingLaravel(array $arguments, Closure $closure): array
{
$isLaravelApplication = InstalledVersions::isInstalled('laravel/framework', false);
- $isLaravelPackage = class_exists(\Orchestra\Testbench\TestCase::class);
+ $isLaravelPackage = class_exists(TestCase::class);
if ($isLaravelApplication && ! $isLaravelPackage) {
return $closure($arguments);
diff --git a/src/Support/Closure.php b/src/Support/Closure.php
index e447903f..bf715780 100644
--- a/src/Support/Closure.php
+++ b/src/Support/Closure.php
@@ -19,14 +19,14 @@ final class Closure
*/
public static function bind(?BaseClosure $closure, ?object $newThis, object|string|null $newScope = 'static'): BaseClosure
{
- if (! $closure instanceof \Closure) {
+ if (! $closure instanceof BaseClosure) {
throw ShouldNotHappen::fromMessage('Could not bind null closure.');
}
// @phpstan-ignore-next-line
$closure = BaseClosure::bind($closure, $newThis, $newScope);
- if (! $closure instanceof \Closure) {
+ if (! $closure instanceof BaseClosure) {
throw ShouldNotHappen::fromMessage('Could not bind closure.');
}
diff --git a/src/Support/Container.php b/src/Support/Container.php
index 241825f5..d43c22be 100644
--- a/src/Support/Container.php
+++ b/src/Support/Container.php
@@ -28,7 +28,7 @@ final class Container
*/
public static function getInstance(): self
{
- if (! self::$instance instanceof \Pest\Support\Container) {
+ if (! self::$instance instanceof Container) {
self::$instance = new self;
}
diff --git a/src/Support/Reflection.php b/src/Support/Reflection.php
index d4f5f133..ac1a4273 100644
--- a/src/Support/Reflection.php
+++ b/src/Support/Reflection.php
@@ -8,6 +8,7 @@ use Closure;
use InvalidArgumentException;
use Pest\Exceptions\ShouldNotHappen;
use Pest\TestSuite;
+use PHPUnit\Framework\TestCase;
use ReflectionClass;
use ReflectionException;
use ReflectionFunction;
@@ -66,7 +67,7 @@ final class Reflection
{
$test = TestSuite::getInstance()->test;
- if (! $test instanceof \PHPUnit\Framework\TestCase) {
+ if (! $test instanceof TestCase) {
return self::bindCallable($callable);
}
@@ -221,7 +222,7 @@ final class Reflection
{
$getProperties = fn (ReflectionClass $reflectionClass): array => array_filter(
array_map(
- fn (ReflectionProperty $property): \ReflectionProperty => $property,
+ fn (ReflectionProperty $property): ReflectionProperty => $property,
$reflectionClass->getProperties(),
), fn (ReflectionProperty $property): bool => $property->getDeclaringClass()->getName() === $reflectionClass->getName(),
);
@@ -256,7 +257,7 @@ final class Reflection
{
$getMethods = fn (ReflectionClass $reflectionClass): array => array_filter(
array_map(
- fn (ReflectionMethod $method): \ReflectionMethod => $method,
+ fn (ReflectionMethod $method): ReflectionMethod => $method,
$reflectionClass->getMethods($filter),
), fn (ReflectionMethod $method): bool => $method->getDeclaringClass()->getName() === $reflectionClass->getName(),
);
diff --git a/tests/Autoload.php b/tests/Autoload.php
index 2d3ce530..5bd3c23b 100644
--- a/tests/Autoload.php
+++ b/tests/Autoload.php
@@ -1,5 +1,7 @@
bar = 0;
beforeAll(function () use ($foo) {
diff --git a/tests/Features/Coverage.php b/tests/Features/Coverage.php
index 974568e6..55ce4164 100644
--- a/tests/Features/Coverage.php
+++ b/tests/Features/Coverage.php
@@ -17,7 +17,7 @@ it('adds coverage if --coverage exist', function () {
$arguments = $plugin->handleArguments(['--coverage']);
expect($arguments)->toEqual(['--coverage-php', Coverage::getPath()])
->and($plugin->coverage)->toBeTrue();
-})->skip(! \Pest\Support\Coverage::isAvailable() || ! function_exists('xdebug_info') || ! in_array('coverage', xdebug_info('mode'), true), 'Coverage is not available');
+})->skip(! Coverage::isAvailable() || ! function_exists('xdebug_info') || ! in_array('coverage', xdebug_info('mode'), true), 'Coverage is not available');
it('adds coverage if --min exist', function () {
$plugin = new CoveragePlugin(new ConsoleOutput);
diff --git a/tests/Features/Helpers.php b/tests/Features/Helpers.php
index e32faffa..d2ea9485 100644
--- a/tests/Features/Helpers.php
+++ b/tests/Features/Helpers.php
@@ -39,7 +39,7 @@ it('allows to call underlying protected/private methods', function () {
it('throws error if method do not exist', function () {
test()->foo();
-})->throws(\ReflectionException::class, 'Call to undefined method PHPUnit\Framework\TestCase::foo()');
+})->throws(ReflectionException::class, 'Call to undefined method PHPUnit\Framework\TestCase::foo()');
it('can forward unexpected calls to any global function')->_assertThat();
diff --git a/tests/Helpers.php b/tests/Helpers.php
index 7a7be690..f7870f38 100644
--- a/tests/Helpers.php
+++ b/tests/Helpers.php
@@ -1,7 +1,9 @@
use(Tests\CustomTestCase\CustomTestCase::class)->in(__DIR__);
+use Tests\CustomTestCase\CustomTestCase;
+
+pest()->use(CustomTestCase::class)->in(__DIR__);
test('closure was bound to CustomTestCase', function () {
$this->assertCustomTrue();
diff --git a/tests/PHPUnit/CustomTestCaseInSubFolders/SubFolder2/UsesPerFile.php b/tests/PHPUnit/CustomTestCaseInSubFolders/SubFolder2/UsesPerFile.php
index 676e80f4..edce0fe6 100644
--- a/tests/PHPUnit/CustomTestCaseInSubFolders/SubFolder2/UsesPerFile.php
+++ b/tests/PHPUnit/CustomTestCaseInSubFolders/SubFolder2/UsesPerFile.php
@@ -1,5 +1,7 @@
printer();
- expect($theme)->toBeInstanceOf(Pest\Configuration\Printer::class);
+ expect($theme)->toBeInstanceOf(Printer::class);
});
diff --git a/tests/Visual/Collision.php b/tests/Visual/Collision.php
index 7812fc0d..99870cac 100644
--- a/tests/Visual/Collision.php
+++ b/tests/Visual/Collision.php
@@ -1,8 +1,10 @@
'DefaultPrinter', 'COLLISION_IGNORE_DURATION' => 'true', 'COLLISION_TEST' => true]
diff --git a/tests/Visual/Help.php b/tests/Visual/Help.php
index eea3fd99..35b25989 100644
--- a/tests/Visual/Help.php
+++ b/tests/Visual/Help.php
@@ -1,8 +1,10 @@
'DefaultPrinter', 'COLLISION_IGNORE_DURATION' => 'true']));
+ $process = (new Process(['php', 'bin/pest', '--help'], null, ['COLLISION_PRINTER' => 'DefaultPrinter', 'COLLISION_IGNORE_DURATION' => 'true']));
$process->run();
diff --git a/tests/Visual/Success.php b/tests/Visual/Success.php
index d87ad304..16d49a38 100644
--- a/tests/Visual/Success.php
+++ b/tests/Visual/Success.php
@@ -1,5 +1,7 @@
'integration', '--exclude-group' => 'integration', 'REBUILD_SNAPSHOTS' => false, 'PARATEST' => 0, 'COLLISION_PRINTER' => 'DefaultPrinter', 'COLLISION_IGNORE_DURATION' => 'true'],
diff --git a/tests/Visual/TeamCity.php b/tests/Visual/TeamCity.php
index c02ee21e..926f3957 100644
--- a/tests/Visual/TeamCity.php
+++ b/tests/Visual/TeamCity.php
@@ -1,5 +1,7 @@
'DefaultPrinter', 'COLLISION_IGNORE_DURATION' => 'true']));
+ $process = (new Process(['php', 'bin/pest', '--version'], null, ['COLLISION_PRINTER' => 'DefaultPrinter', 'COLLISION_IGNORE_DURATION' => 'true']));
$process->run();
From 9d17b872dd239f00128387b0c77d6e45a60d5726 Mon Sep 17 00:00:00 2001
From: nuno maduro
Date: Tue, 10 Mar 2026 21:09:02 +0000
Subject: [PATCH 38/50] chore: update stubs
---
stubs/init-laravel/Pest.php.stub | 4 +++-
stubs/init/Pest.php.stub | 4 +++-
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/stubs/init-laravel/Pest.php.stub b/stubs/init-laravel/Pest.php.stub
index 60f04a45..38347589 100644
--- a/stubs/init-laravel/Pest.php.stub
+++ b/stubs/init-laravel/Pest.php.stub
@@ -1,5 +1,7 @@
extend(Tests\TestCase::class)
+pest()->extend(TestCase::class)
// ->use(Illuminate\Foundation\Testing\RefreshDatabase::class)
->in('Feature');
diff --git a/stubs/init/Pest.php.stub b/stubs/init/Pest.php.stub
index b239048c..fbc6d9ae 100644
--- a/stubs/init/Pest.php.stub
+++ b/stubs/init/Pest.php.stub
@@ -1,5 +1,7 @@
extend(Tests\TestCase::class)->in('Feature');
+pest()->extend(TestCase::class)->in('Feature');
/*
|--------------------------------------------------------------------------
From 5d42e8fe3ae1d9fdf7c9f73ee88138fd30265701 Mon Sep 17 00:00:00 2001
From: nuno maduro
Date: Tue, 10 Mar 2026 21:09:12 +0000
Subject: [PATCH 39/50] release: v4.4.2
---
src/Pest.php | 2 +-
.../Visual/Help/visual_snapshot_of_help_command_output.snap | 2 +-
.../Visual/Version/visual_snapshot_of_help_command_output.snap | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/Pest.php b/src/Pest.php
index a66b7254..cf1c3a11 100644
--- a/src/Pest.php
+++ b/src/Pest.php
@@ -6,7 +6,7 @@ namespace Pest;
function version(): string
{
- return '4.4.1';
+ return '4.4.2';
}
function testDirectory(string $file = ''): string
diff --git a/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap b/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
index 808b1613..cec9c17f 100644
--- a/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
+++ b/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
@@ -1,5 +1,5 @@
- Pest Testing Framework 4.4.1.
+ Pest Testing Framework 4.4.2.
USAGE: pest [options]
diff --git a/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap b/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap
index 0160b757..36a5bb80 100644
--- a/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap
+++ b/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap
@@ -1,3 +1,3 @@
- Pest Testing Framework 4.4.1.
+ Pest Testing Framework 4.4.2.
From 1a4c06bd6ed07c2aee7e84111adb78aae0fed442 Mon Sep 17 00:00:00 2001
From: brianseymour
Date: Wed, 18 Mar 2026 20:51:45 -0700
Subject: [PATCH 40/50] Fix Pest comment typo while still honoring the
Otwellian Waterfall
---
stubs/init-laravel/Pest.php.stub | 2 +-
stubs/init/Pest.php.stub | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/stubs/init-laravel/Pest.php.stub b/stubs/init-laravel/Pest.php.stub
index 38347589..9d1d8d95 100644
--- a/stubs/init-laravel/Pest.php.stub
+++ b/stubs/init-laravel/Pest.php.stub
@@ -9,7 +9,7 @@ use Tests\TestCase;
|
| The closure you provide to your test functions is always bound to a specific PHPUnit test
| case class. By default, that class is "PHPUnit\Framework\TestCase". Of course, you may
-| need to change it using the "pest()" function to bind a different classes or traits.
+| need to change it using the "pest()" function to bind different classes or traits.
|
*/
diff --git a/stubs/init/Pest.php.stub b/stubs/init/Pest.php.stub
index fbc6d9ae..d4ffffba 100644
--- a/stubs/init/Pest.php.stub
+++ b/stubs/init/Pest.php.stub
@@ -9,7 +9,7 @@ use Tests\TestCase;
|
| The closure you provide to your test functions is always bound to a specific PHPUnit test
| case class. By default, that class is "PHPUnit\Framework\TestCase". Of course, you may
-| need to change it using the "pest()" function to bind a different classes or traits.
+| need to change it using the "pest()" function to bind different classes or traits.
|
*/
From a753b41409fdf6e13996019202488370dc80e9a5 Mon Sep 17 00:00:00 2001
From: nuno maduro
Date: Sat, 21 Mar 2026 13:14:35 +0000
Subject: [PATCH 41/50] chore: bumps phpunit
---
composer.json | 6 +++---
src/Support/ExceptionTrace.php | 1 +
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/composer.json b/composer.json
index 846dc188..0c47bed4 100644
--- a/composer.json
+++ b/composer.json
@@ -18,19 +18,19 @@
],
"require": {
"php": "^8.3.0",
- "brianium/paratest": "^7.19.0",
+ "brianium/paratest": "^7.19.2",
"nunomaduro/collision": "^8.9.1",
"nunomaduro/termwind": "^2.4.0",
"pestphp/pest-plugin": "^4.0.0",
"pestphp/pest-plugin-arch": "^4.0.0",
"pestphp/pest-plugin-mutate": "^4.0.1",
"pestphp/pest-plugin-profanity": "^4.2.1",
- "phpunit/phpunit": "^12.5.12",
+ "phpunit/phpunit": "^12.5.14",
"symfony/process": "^7.4.5|^8.0.5"
},
"conflict": {
"filp/whoops": "<2.18.3",
- "phpunit/phpunit": ">12.5.12",
+ "phpunit/phpunit": ">12.5.14",
"sebastian/exporter": "<7.0.0",
"webmozart/assert": "<1.11.0"
},
diff --git a/src/Support/ExceptionTrace.php b/src/Support/ExceptionTrace.php
index 9d4132e2..92047840 100644
--- a/src/Support/ExceptionTrace.php
+++ b/src/Support/ExceptionTrace.php
@@ -26,6 +26,7 @@ final class ExceptionTrace
return $closure();
} catch (Throwable $throwable) {
if (Str::startsWith($message = $throwable->getMessage(), self::UNDEFINED_METHOD)) {
+ // @phpstan-ignore-next-line
$class = preg_match('/^Call to undefined method ([^:]+)::/', $message, $matches) === false ? null : $matches[1];
$message = str_replace(self::UNDEFINED_METHOD, 'Call to undefined method ', $message);
From e6ab897594312728ef2e32d586cb4f6780b1b495 Mon Sep 17 00:00:00 2001
From: nuno maduro
Date: Sat, 21 Mar 2026 13:14:39 +0000
Subject: [PATCH 42/50] release: v4.4.3
---
src/Pest.php | 2 +-
.../Visual/Help/visual_snapshot_of_help_command_output.snap | 2 +-
.../Visual/Version/visual_snapshot_of_help_command_output.snap | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/Pest.php b/src/Pest.php
index cf1c3a11..3bf7581d 100644
--- a/src/Pest.php
+++ b/src/Pest.php
@@ -6,7 +6,7 @@ namespace Pest;
function version(): string
{
- return '4.4.2';
+ return '4.4.3';
}
function testDirectory(string $file = ''): string
diff --git a/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap b/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
index cec9c17f..cfeda92f 100644
--- a/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
+++ b/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
@@ -1,5 +1,5 @@
- Pest Testing Framework 4.4.2.
+ Pest Testing Framework 4.4.3.
USAGE: pest [options]
diff --git a/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap b/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap
index 36a5bb80..56526ad9 100644
--- a/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap
+++ b/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap
@@ -1,3 +1,3 @@
- Pest Testing Framework 4.4.2.
+ Pest Testing Framework 4.4.3.
From a08755538302b39f65d8c8641f35f42bfad2da73 Mon Sep 17 00:00:00 2001
From: nuno maduro
Date: Thu, 26 Mar 2026 14:30:03 +0000
Subject: [PATCH 43/50] bump: dependencies
---
composer.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/composer.json b/composer.json
index 0c47bed4..db2c1957 100644
--- a/composer.json
+++ b/composer.json
@@ -58,7 +58,7 @@
"pestphp/pest-dev-tools": "^4.1.0",
"pestphp/pest-plugin-browser": "^4.3.0",
"pestphp/pest-plugin-type-coverage": "^4.0.3",
- "psy/psysh": "^0.12.21"
+ "psy/psysh": "^0.12.22"
},
"minimum-stability": "dev",
"prefer-stable": true,
From 6c42e7f4ea877a555389c735a7cf14adc2027730 Mon Sep 17 00:00:00 2001
From: "Gal Jakic (We Wow Web)"
Date: Wed, 1 Apr 2026 16:48:14 +0200
Subject: [PATCH 44/50] Laravel Pint default formatting applied to
Pest-php.stub
---
stubs/init-laravel/Pest.php.stub | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/stubs/init-laravel/Pest.php.stub b/stubs/init-laravel/Pest.php.stub
index 38347589..cb09b7f3 100644
--- a/stubs/init-laravel/Pest.php.stub
+++ b/stubs/init-laravel/Pest.php.stub
@@ -1,5 +1,6 @@
extend(TestCase::class)
- // ->use(Illuminate\Foundation\Testing\RefreshDatabase::class)
+ // ->use(RefreshDatabase::class)
->in('Feature');
/*
From 3d2ebdb27321e42f8a425b39ea945c7eecf96ccb Mon Sep 17 00:00:00 2001
From: nuno maduro
Date: Fri, 3 Apr 2026 11:59:54 +0100
Subject: [PATCH 45/50] bump: dependencies
---
composer.json | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/composer.json b/composer.json
index db2c1957..afdead31 100644
--- a/composer.json
+++ b/composer.json
@@ -18,19 +18,19 @@
],
"require": {
"php": "^8.3.0",
- "brianium/paratest": "^7.19.2",
- "nunomaduro/collision": "^8.9.1",
+ "brianium/paratest": "^7.20.0",
+ "nunomaduro/collision": "^8.9.2",
"nunomaduro/termwind": "^2.4.0",
"pestphp/pest-plugin": "^4.0.0",
"pestphp/pest-plugin-arch": "^4.0.0",
"pestphp/pest-plugin-mutate": "^4.0.1",
"pestphp/pest-plugin-profanity": "^4.2.1",
- "phpunit/phpunit": "^12.5.14",
- "symfony/process": "^7.4.5|^8.0.5"
+ "phpunit/phpunit": "^12.5.16",
+ "symfony/process": "^7.4.5|^8.0.8"
},
"conflict": {
"filp/whoops": "<2.18.3",
- "phpunit/phpunit": ">12.5.14",
+ "phpunit/phpunit": ">12.5.16",
"sebastian/exporter": "<7.0.0",
"webmozart/assert": "<1.11.0"
},
From ce05ee9aad5672c21d50c7f2db6683727687771b Mon Sep 17 00:00:00 2001
From: nuno maduro
Date: Fri, 3 Apr 2026 12:00:04 +0100
Subject: [PATCH 46/50] release: v4.4.4
---
src/Pest.php | 2 +-
.../Visual/Help/visual_snapshot_of_help_command_output.snap | 4 ++--
.../Version/visual_snapshot_of_help_command_output.snap | 2 +-
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/Pest.php b/src/Pest.php
index 3bf7581d..8595bd5f 100644
--- a/src/Pest.php
+++ b/src/Pest.php
@@ -6,7 +6,7 @@ namespace Pest;
function version(): string
{
- return '4.4.3';
+ return '4.4.4';
}
function testDirectory(string $file = ''): string
diff --git a/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap b/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
index cfeda92f..1b8c0dcc 100644
--- a/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
+++ b/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
@@ -1,5 +1,5 @@
- Pest Testing Framework 4.4.3.
+ Pest Testing Framework 4.4.4.
USAGE: pest [options]
@@ -92,7 +92,7 @@
--random-order-seed [N] Use the specified random seed when running tests in random order
REPORTING OPTIONS:
- --colors [flag] ......... Use colors in output ("never", "auto" or "always")
+ --colors=[flag] ......... Use colors in output ("never", "auto" or "always")
--columns [n] ................. Number of columns to use for progress output
--columns max ............ Use maximum number of columns for progress output
--stderr ................................. Write to STDERR instead of STDOUT
diff --git a/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap b/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap
index 56526ad9..988eec06 100644
--- a/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap
+++ b/tests/.pest/snapshots/Visual/Version/visual_snapshot_of_help_command_output.snap
@@ -1,3 +1,3 @@
- Pest Testing Framework 4.4.3.
+ Pest Testing Framework 4.4.4.
From c1a54df233a3ff3c19a03473a500d01da1feeb9d Mon Sep 17 00:00:00 2001
From: nuno maduro
Date: Fri, 3 Apr 2026 14:04:20 +0100
Subject: [PATCH 47/50] feat: `--ai` work in progress
---
composer.json | 2 +-
src/Plugins/Concerns/HandleArguments.php | 27 +++++++++++++++++++
src/Plugins/Help.php | 7 +++++
src/Repositories/TestRepository.php | 10 +++++++
...isual_snapshot_of_help_command_output.snap | 3 +++
5 files changed, 48 insertions(+), 1 deletion(-)
diff --git a/composer.json b/composer.json
index afdead31..a3691452 100644
--- a/composer.json
+++ b/composer.json
@@ -26,7 +26,7 @@
"pestphp/pest-plugin-mutate": "^4.0.1",
"pestphp/pest-plugin-profanity": "^4.2.1",
"phpunit/phpunit": "^12.5.16",
- "symfony/process": "^7.4.5|^8.0.8"
+ "symfony/process": "^7.4.8|^8.0.8"
},
"conflict": {
"filp/whoops": "<2.18.3",
diff --git a/src/Plugins/Concerns/HandleArguments.php b/src/Plugins/Concerns/HandleArguments.php
index 9cf5e606..6fdcff8c 100644
--- a/src/Plugins/Concerns/HandleArguments.php
+++ b/src/Plugins/Concerns/HandleArguments.php
@@ -56,4 +56,31 @@ trait HandleArguments
return array_values(array_flip($arguments));
}
+
+ /**
+ * Pops the given argument and its value from the arguments, returning the value.
+ *
+ * @param array $arguments
+ */
+ public function popArgumentValue(string $argument, array &$arguments): ?string
+ {
+ foreach ($arguments as $key => $value) {
+ if (str_contains($value, "$argument=")) {
+ unset($arguments[$key]);
+ $arguments = array_values($arguments);
+
+ return substr($value, strlen($argument) + 1);
+ }
+
+ if ($value === $argument && isset($arguments[$key + 1])) {
+ $result = $arguments[$key + 1];
+ unset($arguments[$key], $arguments[$key + 1]);
+ $arguments = array_values($arguments);
+
+ return $result;
+ }
+ }
+
+ return null;
+ }
}
diff --git a/src/Plugins/Help.php b/src/Plugins/Help.php
index 096f2914..a2fb1ef0 100644
--- a/src/Plugins/Help.php
+++ b/src/Plugins/Help.php
@@ -107,6 +107,13 @@ final readonly class Help implements HandlesArguments
'desc' => 'Initialise a standard Pest configuration',
]], ...$content['Configuration']];
+ $content['AI'] = [
+ [
+ 'arg' => '--ai',
+ 'desc' => 'Run a code snippet as a fully scaffolded test for AI verification',
+ ],
+ ];
+
$content['Execution'] = [...[
[
'arg' => '--parallel',
diff --git a/src/Repositories/TestRepository.php b/src/Repositories/TestRepository.php
index 466d3226..cfce2cf1 100644
--- a/src/Repositories/TestRepository.php
+++ b/src/Repositories/TestRepository.php
@@ -113,6 +113,16 @@ final class TestRepository
$this->testCaseMethodFilters[] = $filter;
}
+ /**
+ * Gets the class and traits configured for the given directory path.
+ *
+ * @return array
+ */
+ public function getUsesForPath(string $path): array
+ {
+ return $this->uses[$path][0] ?? [];
+ }
+
/**
* Gets the test case factory from the given filename.
*/
diff --git a/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap b/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
index 1b8c0dcc..75439fc3 100644
--- a/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
+++ b/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap
@@ -147,6 +147,9 @@
--disable-coverage-ignore ...... Disable metadata for ignoring code coverage
--no-coverage Ignore code coverage reporting configured in the XML configuration file
+ AI OPTIONS:
+ --ai ..... Run a code snippet as a fully scaffolded test for AI verification
+
MUTATION TESTING OPTIONS:
--mutate .... Runs mutation testing, to understand the quality of your tests
--mutate --parallel ...................... Runs mutation testing in parallel
From 9797a71dbc776f46d6fcacb708b002755da6f37a Mon Sep 17 00:00:00 2001
From: nuno maduro
Date: Fri, 3 Apr 2026 14:43:28 +0100
Subject: [PATCH 48/50] feat(ai): allow temporary namesapce
---
src/Factories/TestCaseFactory.php | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/Factories/TestCaseFactory.php b/src/Factories/TestCaseFactory.php
index 3349d03d..4599ee77 100644
--- a/src/Factories/TestCaseFactory.php
+++ b/src/Factories/TestCaseFactory.php
@@ -59,6 +59,11 @@ final class TestCaseFactory
Concerns\Expectable::class,
];
+ /**
+ * The namespace for the test case, overrides the path-based namespace when set.
+ */
+ public ?string $namespace = null;
+
/**
* Creates a new Factory instance.
*/
@@ -127,7 +132,7 @@ final class TestCaseFactory
$partsFQN = explode('\\', $classFQN);
$className = array_pop($partsFQN);
- $namespace = implode('\\', $partsFQN);
+ $namespace = $this->namespace ?? implode('\\', $partsFQN);
$baseClass = sprintf('\%s', $this->class);
if (trim($className) === '') {
From e44c554a0b0f4bbeee7beb7e497118a33b6a0a6f Mon Sep 17 00:00:00 2001
From: nuno maduro
Date: Mon, 6 Apr 2026 21:57:05 +0100
Subject: [PATCH 49/50] chore: bumps dependencies
---
composer.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/composer.json b/composer.json
index a3691452..7ef9486e 100644
--- a/composer.json
+++ b/composer.json
@@ -19,7 +19,7 @@
"require": {
"php": "^8.3.0",
"brianium/paratest": "^7.20.0",
- "nunomaduro/collision": "^8.9.2",
+ "nunomaduro/collision": "^8.9.3",
"nunomaduro/termwind": "^2.4.0",
"pestphp/pest-plugin": "^4.0.0",
"pestphp/pest-plugin-arch": "^4.0.0",
@@ -57,7 +57,7 @@
"require-dev": {
"pestphp/pest-dev-tools": "^4.1.0",
"pestphp/pest-plugin-browser": "^4.3.0",
- "pestphp/pest-plugin-type-coverage": "^4.0.3",
+ "pestphp/pest-plugin-type-coverage": "^4.0.4",
"psy/psysh": "^0.12.22"
},
"minimum-stability": "dev",
From d9d46c73f8d1f4edb449d889632e3d8c3cd2172d Mon Sep 17 00:00:00 2001
From: nuno maduro
Date: Thu, 9 Apr 2026 21:36:49 +0100
Subject: [PATCH 50/50] chore: stores statically the result
---
src/Plugins/Parallel/Paratest/WrapperRunner.php | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/Plugins/Parallel/Paratest/WrapperRunner.php b/src/Plugins/Parallel/Paratest/WrapperRunner.php
index 064856bc..b853c65f 100644
--- a/src/Plugins/Parallel/Paratest/WrapperRunner.php
+++ b/src/Plugins/Parallel/Paratest/WrapperRunner.php
@@ -51,6 +51,11 @@ final class WrapperRunner implements RunnerInterface
/**
* The time to sleep between cycles.
*/
+ /**
+ * The merged test result from the parallel run.
+ */
+ public static ?TestResult $result = null;
+
private const int CYCLE_SLEEP = 10000;
/**
@@ -386,6 +391,8 @@ final class WrapperRunner implements RunnerInterface
$testResultSum->numberOfIssuesIgnoredByBaseline(),
);
+ self::$result = $testResultSum;
+
if ($this->options->configuration->cacheResult()) {
$resultCacheSum = new DefaultResultCache($this->options->configuration->testResultCacheFile());
foreach ($this->resultCacheFiles as $resultCacheFile) {