From c61dcad42b086b7ec2c3c22e783b486b4ccb7bda Mon Sep 17 00:00:00 2001 From: dbpolito Date: Wed, 11 Feb 2026 17:57:07 -0300 Subject: [PATCH 1/3] 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 767a7c696..43c84e3c8 100644 --- a/src/Concerns/Testable.php +++ b/src/Concerns/Testable.php @@ -350,7 +350,8 @@ private function __resolveTestArguments(array $arguments): array } $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 @@ private function __resolveTestArguments(array $arguments): array 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 @@ private function __resolveTestArguments(array $arguments): array return [$boundDatasetResult]; } - return array_values($boundDatasetResult); + return $boundDatasetResult; } /** diff --git a/tests/Features/DatasetsTests.php b/tests/Features/DatasetsTests.php index 837b56f62..1ae7437e1 100644 --- a/tests/Features/DatasetsTests.php +++ b/tests/Features/DatasetsTests.php @@ -457,3 +457,80 @@ function () { 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']; + }, +]); From 6966802afcea99814531634a0c655bb0df7f1fa7 Mon Sep 17 00:00:00 2001 From: dbpolito Date: Wed, 11 Feb 2026 18:02:21 -0300 Subject: [PATCH 2/3] Cleanup --- src/Concerns/Testable.php | 2 +- tests/Features/DatasetsTests.php | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Concerns/Testable.php b/src/Concerns/Testable.php index 43c84e3c8..e192c8faf 100644 --- a/src/Concerns/Testable.php +++ b/src/Concerns/Testable.php @@ -361,7 +361,7 @@ private function __resolveTestArguments(array $arguments): array $parameterType = is_string($argumentIndex) ? ($testParameterTypesByName[$argumentIndex] ?? 'mixed') - : ($testParameterTypes[$argumentIndex] ?? 'mixed'); + : $testParameterTypes[$argumentIndex]; if (in_array($parameterType, [Closure::class, 'callable', 'mixed'])) { continue; diff --git a/tests/Features/DatasetsTests.php b/tests/Features/DatasetsTests.php index 1ae7437e1..b56071066 100644 --- a/tests/Features/DatasetsTests.php +++ b/tests/Features/DatasetsTests.php @@ -458,7 +458,6 @@ function () { 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'); From b081584ab60fd5051f3f365b52bcc701d96ec5a6 Mon Sep 17 00:00:00 2001 From: dbpolito Date: Wed, 11 Feb 2026 18:09:09 -0300 Subject: [PATCH 3/3] Improvements --- src/Concerns/Testable.php | 2 +- tests/Features/DatasetsTests.php | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Concerns/Testable.php b/src/Concerns/Testable.php index e192c8faf..67a16b2c2 100644 --- a/src/Concerns/Testable.php +++ b/src/Concerns/Testable.php @@ -360,7 +360,7 @@ private function __resolveTestArguments(array $arguments): array } $parameterType = is_string($argumentIndex) - ? ($testParameterTypesByName[$argumentIndex] ?? 'mixed') + ? $testParameterTypesByName[$argumentIndex] : $testParameterTypes[$argumentIndex]; if (in_array($parameterType, [Closure::class, 'callable', 'mixed'])) { diff --git a/tests/Features/DatasetsTests.php b/tests/Features/DatasetsTests.php index b56071066..99682015b 100644 --- a/tests/Features/DatasetsTests.php +++ b/tests/Features/DatasetsTests.php @@ -533,3 +533,12 @@ function () { return ['name' => $this->foo, 'email' => 'test@example.com']; }, ]); + +test('dataset items can mix named and sequential styles', function (string $name, string $email) { + expect($name)->toBeString(); + expect($email)->toContain('@'); +})->with([ + ['name' => 'Taylor', 'email' => 'taylor@laravel.com'], + ['James', 'james@laravel.com'], + ['James', 'email' => 'james@laravel.com'], +]);