From c61dcad42b086b7ec2c3c22e783b486b4ccb7bda Mon Sep 17 00:00:00 2001 From: dbpolito Date: Wed, 11 Feb 2026 17:57:07 -0300 Subject: [PATCH] Dataset Named Parameters --- src/Concerns/Testable.php | 11 +++-- tests/Features/DatasetsTests.php | 77 ++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 3 deletions(-) diff --git a/src/Concerns/Testable.php b/src/Concerns/Testable.php index 767a7c69..43c84e3c 100644 --- a/src/Concerns/Testable.php +++ b/src/Concerns/Testable.php @@ -350,7 +350,8 @@ trait Testable } $underlyingTest = Reflection::getFunctionVariable($this->__test, 'closure'); - $testParameterTypes = array_values(Reflection::getFunctionArguments($underlyingTest)); + $testParameterTypesByName = Reflection::getFunctionArguments($underlyingTest); + $testParameterTypes = array_values($testParameterTypesByName); if (count($arguments) !== 1) { foreach ($arguments as $argumentIndex => $argumentValue) { @@ -358,7 +359,11 @@ trait Testable continue; } - if (in_array($testParameterTypes[$argumentIndex], [Closure::class, 'callable', 'mixed'])) { + $parameterType = is_string($argumentIndex) + ? ($testParameterTypesByName[$argumentIndex] ?? 'mixed') + : ($testParameterTypes[$argumentIndex] ?? 'mixed'); + + if (in_array($parameterType, [Closure::class, 'callable', 'mixed'])) { continue; } @@ -384,7 +389,7 @@ trait Testable return [$boundDatasetResult]; } - return array_values($boundDatasetResult); + return $boundDatasetResult; } /** diff --git a/tests/Features/DatasetsTests.php b/tests/Features/DatasetsTests.php index 837b56f6..1ae7437e 100644 --- a/tests/Features/DatasetsTests.php +++ b/tests/Features/DatasetsTests.php @@ -457,3 +457,80 @@ dataset('after-describe', ['after']); test('after describe block with named dataset', function (...$args) { expect($args)->toBe(['after']); })->with('after-describe'); + +// Named parameters on datasets +test('named parameters match by parameter name', function (string $email, string $name) { + expect($name)->toBe('Taylor'); + expect($email)->toBe('taylor@laravel.com'); +})->with([ + ['name' => 'Taylor', 'email' => 'taylor@laravel.com'], +]); + +test('named parameters work with multiple dataset items', function (string $email, string $name) { + expect($name)->toBeString(); + expect($email)->toContain('@'); +})->with([ + ['name' => 'Taylor', 'email' => 'taylor@laravel.com'], + ['name' => 'James', 'email' => 'james@laravel.com'], +]); + +test('named parameters work in different order than closure params', function (string $third, string $first, string $second) { + expect($first)->toBe('a'); + expect($second)->toBe('b'); + expect($third)->toBe('c'); +})->with([ + ['first' => 'a', 'second' => 'b', 'third' => 'c'], +]); + +test('named parameters work with named dataset keys', function (string $email, string $name) { + expect($name)->toBeString(); + expect($email)->toContain('@'); +})->with([ + 'taylor' => ['name' => 'Taylor', 'email' => 'taylor@laravel.com'], + 'james' => ['name' => 'James', 'email' => 'james@laravel.com'], +]); + +test('named parameters work with closures that should be resolved', function (string $email, string $name) { + expect($name)->toBe('bar'); + expect($email)->toBe('bar@example.com'); +})->with([ + [ + 'name' => function () { + return $this->foo; + }, + 'email' => function () { + return $this->foo.'@example.com'; + }, + ], +]); + +test('named parameters work with closure type hints', function (Closure $callback, string $name) { + expect($name)->toBe('Taylor'); + expect($callback())->toBe('resolved'); +})->with([ + [ + 'name' => 'Taylor', + 'callback' => function () { + return 'resolved'; + }, + ], +]); + +dataset('named-params-dataset', [ + ['name' => 'Taylor', 'email' => 'taylor@laravel.com'], + ['name' => 'James', 'email' => 'james@laravel.com'], +]); + +test('named parameters work with registered datasets', function (string $email, string $name) { + expect($name)->toBeString(); + expect($email)->toContain('@'); +})->with('named-params-dataset'); + +test('named parameters work with bound closure returning associative array', function (string $email, string $name) { + expect($name)->toBe('bar'); + expect($email)->toBe('test@example.com'); +})->with([ + function () { + return ['name' => $this->foo, 'email' => 'test@example.com']; + }, +]);