From 974546d49f3813456826ee6e58bc611812f9b52d Mon Sep 17 00:00:00 2001 From: sonali-dudhia Date: Wed, 8 Jul 2026 18:05:18 +0530 Subject: [PATCH] fix: report dataset provider errors as failing tests 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 000000000..116307819 --- /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 b23082fd6..82014c5af 100644 --- a/src/Factories/TestCaseFactory.php +++ b/src/Factories/TestCaseFactory.php @@ -158,6 +158,7 @@ public function evaluate(string $filename, array $methods): void $classCode = <<getPrevious() ?? \$arguments[0]; + } + return \$this->__runTest( \$this->__test, ...\$arguments, @@ -261,7 +265,11 @@ private function buildDatasetForEvaluation(string $methodName, string $dataProvi 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 000000000..2a8fc7657 --- /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 000000000..1e0c87012 --- /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 000000000..2cce08842 --- /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 000000000..95fabb7d3 --- /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();