From 3927dbfcdfc4c77e1bf213241bc52dee88182aae Mon Sep 17 00:00:00 2001 From: Sonali dudhia <45190968+sonalidudhia@users.noreply.github.com> Date: Fri, 17 Jul 2026 18:43:01 +0530 Subject: [PATCH 1/5] fix: report dataset provider errors as failing tests (#1749) Errors raised while resolving a test's dataset (missing named dataset, throwing dataset closure) previously crashed the whole run. Now the data provider catches them, wraps them in a DatasetProviderError, and the test method rethrows the original throwable so the affected test fails cleanly with a non-zero exit code while other tests keep running. --- src/Exceptions/DatasetProviderError.php | 19 +++++++++ src/Factories/TestCaseFactory.php | 1 + src/Factories/TestCaseMethodFactory.php | 10 ++++- tests/.tests/DatasetClosureThrows.php | 9 +++++ tests/.tests/IssueOnly.php | 7 ++++ tests/.tests/IssueWithPassing.php | 11 ++++++ tests/Features/DatasetProviderErrors.php | 49 ++++++++++++++++++++++++ 7 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 src/Exceptions/DatasetProviderError.php create mode 100644 tests/.tests/DatasetClosureThrows.php create mode 100644 tests/.tests/IssueOnly.php create mode 100644 tests/.tests/IssueWithPassing.php create mode 100644 tests/Features/DatasetProviderErrors.php diff --git a/src/Exceptions/DatasetProviderError.php b/src/Exceptions/DatasetProviderError.php new file mode 100644 index 00000000..11630781 --- /dev/null +++ b/src/Exceptions/DatasetProviderError.php @@ -0,0 +1,19 @@ +getMessage(), (int) $previous->getCode(), $previous); + } +} diff --git a/src/Factories/TestCaseFactory.php b/src/Factories/TestCaseFactory.php index f2bb3e1b..5d892faa 100644 --- a/src/Factories/TestCaseFactory.php +++ b/src/Factories/TestCaseFactory.php @@ -161,6 +161,7 @@ final class TestCaseFactory $classCode = <<getPrevious() ?? \$arguments[0]; + } + return \$this->__runTest( \$this->__test, ...\$arguments, @@ -261,7 +265,11 @@ final class TestCaseMethodFactory public static function $dataProviderName() { - return __PestDatasets::get(self::\$__filename, "$methodName"); + try { + return __PestDatasets::get(self::\$__filename, "$methodName"); + } catch (\Throwable \$throwable) { + return [[new __PestDatasetProviderError(\$throwable)]]; + } } EOF; diff --git a/tests/.tests/DatasetClosureThrows.php b/tests/.tests/DatasetClosureThrows.php new file mode 100644 index 00000000..2a8fc765 --- /dev/null +++ b/tests/.tests/DatasetClosureThrows.php @@ -0,0 +1,9 @@ +toBeTrue(); +})->with('throws'); diff --git a/tests/.tests/IssueOnly.php b/tests/.tests/IssueOnly.php new file mode 100644 index 00000000..1e0c8701 --- /dev/null +++ b/tests/.tests/IssueOnly.php @@ -0,0 +1,7 @@ +toBeTruthy(); +})->with('missing'); diff --git a/tests/.tests/IssueWithPassing.php b/tests/.tests/IssueWithPassing.php new file mode 100644 index 00000000..2cce0884 --- /dev/null +++ b/tests/.tests/IssueWithPassing.php @@ -0,0 +1,11 @@ +toBeTrue(); +}); + +it('references a missing dataset', function ($value) { + expect($value)->toBeTruthy(); +})->with('missing'); diff --git a/tests/Features/DatasetProviderErrors.php b/tests/Features/DatasetProviderErrors.php new file mode 100644 index 00000000..95fabb7d --- /dev/null +++ b/tests/Features/DatasetProviderErrors.php @@ -0,0 +1,49 @@ + 'DefaultPrinter', 'COLLISION_IGNORE_DURATION' => 'true'], + ); + + $process->run(); + + return [ + 'output' => removeAnsiEscapeSequences($process->getOutput().$process->getErrorOutput()), + 'code' => $process->getExitCode(), + ]; +}; + +test('reports missing datasets as errors for a single file run', function () use ($run) { + $result = $run('tests/.tests/IssueOnly.php'); + + expect($result['output']) + ->toContain("A dataset with the name `missing` does not exist. You can create it using `dataset('missing', ['a', 'b']);`.") + ->toContain('FAILED') + ->toContain('Tests: 1 failed'); + + expect($result['code'])->not->toBe(0); +})->skipOnWindows(); + +test('reports missing datasets as errors alongside passing tests', function () use ($run) { + $result = $run('tests/.tests/IssueWithPassing.php'); + + expect($result['output']) + ->toContain("A dataset with the name `missing` does not exist. You can create it using `dataset('missing', ['a', 'b']);`.") + ->toContain('1 passed') + ->toContain('1 failed'); + + expect($result['code'])->not->toBe(0); +})->skipOnWindows(); + +test('reports dataset closure exceptions as errors', function () use ($run) { + $result = $run('tests/.tests/DatasetClosureThrows.php'); + + expect($result['output']) + ->toContain('boom from dataset'); + + expect($result['code'])->not->toBe(0); +})->skipOnWindows(); From bbc6ada21e50137336756e6775f0c2b8f70ea6ac Mon Sep 17 00:00:00 2001 From: nuno maduro Date: Fri, 17 Jul 2026 14:32:17 +0100 Subject: [PATCH 2/5] chore: bumps deps --- composer.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index a584ea5f..a7149316 100644 --- a/composer.json +++ b/composer.json @@ -20,18 +20,18 @@ "php": "^8.3.0", "brianium/paratest": "^7.20.0", "composer/xdebug-handler": "^3.0.5", - "nunomaduro/collision": "^8.9.4", + "nunomaduro/collision": "^8.9.5", "nunomaduro/termwind": "^2.4.0", "pestphp/pest-plugin": "^4.0.0", "pestphp/pest-plugin-arch": "^4.0.2", "pestphp/pest-plugin-mutate": "^4.0.1", "pestphp/pest-plugin-profanity": "^4.2.1", - "phpunit/phpunit": "^12.5.30", + "phpunit/phpunit": "^12.5.31", "symfony/process": "^7.4.13|^8.1.0" }, "conflict": { "filp/whoops": "<2.18.3", - "phpunit/phpunit": ">12.5.30", + "phpunit/phpunit": ">12.5.31", "sebastian/exporter": "<7.0.0", "webmozart/assert": "<1.11.0" }, From feaac1ab7e6719f168a6104f4705819b265d9da4 Mon Sep 17 00:00:00 2001 From: nuno maduro Date: Fri, 17 Jul 2026 14:32:27 +0100 Subject: [PATCH 3/5] chore: fixes rector ignore --- rector.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rector.php b/rector.php index a5c426f5..1531a89d 100644 --- a/rector.php +++ b/rector.php @@ -6,6 +6,7 @@ use Rector\CodingStyle\Rector\ArrowFunction\ArrowFunctionDelegatingCallToFirstCl use Rector\Config\RectorConfig; use Rector\DeadCode\Rector\ClassMethod\RemoveDuplicatedReturnSelfDocblockRector; use Rector\DeadCode\Rector\ClassMethod\RemoveParentDelegatingConstructorRector; +use Rector\DeadCode\Rector\ClassMethod\RemoveReturnTagIncompatibleWithNativeTypeRector; use Rector\DeadCode\Rector\ClassMethod\RemoveUselessUnionReturnDocblockRector; use Rector\TypeDeclaration\Rector\ClassMethod\NarrowObjectReturnTypeRector; use Rector\TypeDeclaration\Rector\ClassMethod\ReturnNeverTypeRector; @@ -22,6 +23,9 @@ return RectorConfig::configure() RemoveParentDelegatingConstructorRector::class, RemoveDuplicatedReturnSelfDocblockRector::class, RemoveUselessUnionReturnDocblockRector::class, + RemoveReturnTagIncompatibleWithNativeTypeRector::class => [ + __DIR__.'/src/Expectations/HigherOrderExpectation.php', + ], ]) ->withPreparedSets( deadCode: true, From ff4aba2ffa8d512891d63bfb800eab2da70fe16b Mon Sep 17 00:00:00 2001 From: nuno maduro Date: Fri, 17 Jul 2026 14:32:33 +0100 Subject: [PATCH 4/5] chore: updates snapshots --- tests/.snapshots/success.txt | 7 ++++++- tests/Visual/Parallel.php | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/.snapshots/success.txt b/tests/.snapshots/success.txt index 0e38f50f..ec8f6d7c 100644 --- a/tests/.snapshots/success.txt +++ b/tests/.snapshots/success.txt @@ -136,6 +136,11 @@ ✓ describe()->with() preserves depends → first with (9) ✓ describe()->with() preserves depends → second with (9) + PASS Tests\Features\DatasetProviderErrors + ✓ reports missing datasets as errors for a single file run + ✓ reports missing datasets as errors alongside passing tests + ✓ reports dataset closure exceptions as errors + PASS Tests\Features\DatasetsTests - 1 todo ✓ it throws exception if dataset does not exist ✓ it throws exception if dataset already exist @@ -1941,4 +1946,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, 40 todos, 35 skipped, 1330 passed (3010 assertions) \ No newline at end of file + Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 40 todos, 35 skipped, 1333 passed (3020 assertions) \ No newline at end of file diff --git a/tests/Visual/Parallel.php b/tests/Visual/Parallel.php index d497eef3..f8beea96 100644 --- a/tests/Visual/Parallel.php +++ b/tests/Visual/Parallel.php @@ -24,13 +24,13 @@ test('parallel', function () use ($run) { $file = file_get_contents(__FILE__); $file = preg_replace( '/\$expected = \'.*?\';/', - "\$expected = '2 deprecated, 4 warnings, 5 incomplete, 3 notices, 40 todos, 27 skipped, 1314 passed (2959 assertions)';", + "\$expected = '2 deprecated, 4 warnings, 5 incomplete, 3 notices, 40 todos, 27 skipped, 1317 passed (2969 assertions)';", $file, ); file_put_contents(__FILE__, $file); } - $expected = '2 deprecated, 4 warnings, 5 incomplete, 3 notices, 40 todos, 27 skipped, 1314 passed (2959 assertions)'; + $expected = '2 deprecated, 4 warnings, 5 incomplete, 3 notices, 40 todos, 27 skipped, 1317 passed (2969 assertions)'; expect($output) ->toContain("Tests: {$expected}") From 1b83b8fcda7865d28fd701eff2fc9aeb67950ed0 Mon Sep 17 00:00:00 2001 From: nuno maduro Date: Fri, 17 Jul 2026 16:33:29 +0100 Subject: [PATCH 5/5] release: v4.7.6 --- 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 fe25c6ae..0a415e38 100644 --- a/src/Pest.php +++ b/src/Pest.php @@ -6,7 +6,7 @@ namespace Pest; function version(): string { - return '4.7.5'; + return '4.7.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 319fc91c..04b72cb8 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.7.5. + Pest Testing Framework 4.7.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 36c2c23d..2342608a 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.7.5. + Pest Testing Framework 4.7.6.