diff --git a/src/Illuminate/Testing/Fluent/Concerns/Has.php b/src/Illuminate/Testing/Fluent/Concerns/Has.php index e1575d606cc6..89cd2eafe5b4 100644 --- a/src/Illuminate/Testing/Fluent/Concerns/Has.php +++ b/src/Illuminate/Testing/Fluent/Concerns/Has.php @@ -63,9 +63,14 @@ public function has($key, $length = null, Closure $callback = null): self $this->interactsWith($key); - if (is_int($length) && ! is_null($callback)) { + if (! is_null($callback)) { return $this->has($key, function (self $scope) use ($length, $callback) { - return $scope->count($length) + return $scope + ->tap(function (self $scope) use ($length) { + if (! is_null($length)) { + $scope->count($length); + } + }) ->first($callback) ->etc(); }); diff --git a/tests/Testing/Fluent/AssertTest.php b/tests/Testing/Fluent/AssertTest.php index 0f0ba7159076..07f515a230ea 100644 --- a/tests/Testing/Fluent/AssertTest.php +++ b/tests/Testing/Fluent/AssertTest.php @@ -607,6 +607,24 @@ public function testScopeShorthand() $this->assertTrue($called, 'The scoped query was never actually called.'); } + public function testScopeShorthandWithoutCount() + { + $assert = AssertableJson::fromArray([ + 'bar' => [ + ['key' => 'first'], + ['key' => 'second'], + ], + ]); + + $called = false; + $assert->has('bar', null, function (AssertableJson $item) use (&$called) { + $item->where('key', 'first'); + $called = true; + }); + + $this->assertTrue($called, 'The scoped query was never actually called.'); + } + public function testScopeShorthandFailsWhenAssertingZeroItems() { $assert = AssertableJson::fromArray([ @@ -641,6 +659,54 @@ public function testScopeShorthandFailsWhenAmountOfItemsDoesNotMatch() }); } + public function testScopeShorthandFailsWhenAssertingEmptyArray() + { + $assert = AssertableJson::fromArray([ + 'bar' => [], + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage( + 'Cannot scope directly onto the first element of property [bar] because it is empty.' + ); + + $assert->has('bar', 0, function (AssertableJson $item) { + $item->where('key', 'first'); + }); + } + + public function testScopeShorthandFailsWhenAssertingEmptyArrayWithoutCount() + { + $assert = AssertableJson::fromArray([ + 'bar' => [], + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage( + 'Cannot scope directly onto the first element of property [bar] because it is empty.' + ); + + $assert->has('bar', null, function (AssertableJson $item) { + $item->where('key', 'first'); + }); + } + + public function testScopeShorthandFailsWhenSecondArgumentUnsupportedType() + { + $assert = AssertableJson::fromArray([ + 'bar' => [ + ['key' => 'first'], + ['key' => 'second'], + ], + ]); + + $this->expectException(TypeError::class); + + $assert->has('bar', 'invalid', function (AssertableJson $item) { + $item->where('key', 'first'); + }); + } + public function testFirstScope() { $assert = AssertableJson::fromArray([