diff --git a/src/Illuminate/Testing/Fluent/Concerns/Matching.php b/src/Illuminate/Testing/Fluent/Concerns/Matching.php index 949047b82bad..9ff7a31823ea 100644 --- a/src/Illuminate/Testing/Fluent/Concerns/Matching.php +++ b/src/Illuminate/Testing/Fluent/Concerns/Matching.php @@ -47,6 +47,49 @@ public function where(string $key, $expected): self return $this; } + /** + * Asserts that the property does not match the expected value. + * + * @param string $key + * @param mixed|\Closure $expected + * @return $this + */ + public function whereNot(string $key, $expected): self + { + $this->has($key); + + $actual = $this->prop($key); + + if ($expected instanceof Closure) { + PHPUnit::assertFalse( + $expected(is_array($actual) ? Collection::make($actual) : $actual), + sprintf('Property [%s] was marked as invalid using a closure.', $this->dotPath($key)) + ); + + return $this; + } + + if ($expected instanceof Arrayable) { + $expected = $expected->toArray(); + } + + $this->ensureSorted($expected); + $this->ensureSorted($actual); + + PHPUnit::assertNotSame( + $expected, + $actual, + sprintf( + 'Property [%s] contains a value that should be missing: [%s, %s]', + $this->dotPath($key), + $key, + $expected + ) + ); + + return $this; + } + /** * Asserts that all properties match their expected values. * diff --git a/tests/Testing/Fluent/AssertTest.php b/tests/Testing/Fluent/AssertTest.php index 8397603a7182..1e4f28e00b23 100644 --- a/tests/Testing/Fluent/AssertTest.php +++ b/tests/Testing/Fluent/AssertTest.php @@ -153,6 +153,96 @@ public function testAssertHasOnlyCountFailsScoped() }); } + public function testAssertHasWithWhereNotDoesNotFail() + { + $assert = AssertableJson::fromArray([ + 'data' => [ + [ + 'id' => 1, + 'name' => 'Taylor', + ], + [ + 'id' => 2, + 'name' => 'Nuno', + ], + ], + ]); + + $assert->has('data', function ($bar) { + $bar->has(2) + ->each(fn ($json) => $json->whereNot('id', 3)->etc()); + }); + } + + public function testAssertHasWithWhereNotFails() + { + $assert = AssertableJson::fromArray([ + 'data' => [ + [ + 'id' => 1, + 'name' => 'Taylor', + ], + [ + 'id' => 2, + 'name' => 'Mateus', + ], + ], + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [data.1.id] contains a value that should be missing: [id, 2]'); + + $assert->has('data', function ($bar) { + $bar->has(2) + ->each(fn ($json) => $json->whereNot('id', 2)->etc()); + }); + } + + public function testAssertHasWithWhereNotDoesNotFailClosure() + { + $assert = AssertableJson::fromArray([ + 'data' => [ + [ + 'id' => 1, + 'name' => 'Taylor', + ], + [ + 'id' => 2, + 'name' => 'Mateus', + ], + ], + ]); + + $assert->has('data', function ($bar) { + $bar->has(2) + ->each(fn ($json) => $json->whereNot('id', fn ($value) => $value === 3)->etc()); + }); + } + + public function testAssertHasWithWhereNotFailsClosure() + { + $assert = AssertableJson::fromArray([ + 'data' => [ + [ + 'id' => 1, + 'name' => 'Taylor', + ], + [ + 'id' => 2, + 'name' => 'Mateus', + ], + ], + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [data.1.id] was marked as invalid using a closure.'); + + $assert->has('data', function ($bar) { + $bar->has(2) + ->each(fn ($json) => $json->whereNot('id', fn ($value) => $value === 2)->etc()); + }); + } + public function testAssertCount() { $assert = AssertableJson::fromArray([ @@ -625,6 +715,64 @@ public function testAssertNestedWhereFailsWhenDoesNotMatchValue() $assert->where('example.nested', 'another-value'); } + public function testAssertWhereDoesNotMatchValue() + { + $assert = AssertableJson::fromArray([ + 'bar' => 'value', + ]); + + $assert->whereNot('bar', 'different_value'); + } + + public function testAssertWhereNotFailsWhenMatchingValue() + { + $assert = AssertableJson::fromArray([ + 'bar' => 'value', + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [bar] contains a value that should be missing: [bar, value]'); + + $assert->whereNot('bar', 'value'); + } + + public function testAssertWhereNotFailsWhenNotMissing() + { + $assert = AssertableJson::fromArray([ + 'bar' => 'value', + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [baz] does not exist.'); + + $assert->whereNot('baz', 'value'); + } + + public function testAssertWhereNotUsingClosure() + { + $assert = AssertableJson::fromArray([ + 'bar' => 'baz', + ]); + + $assert->whereNot('bar', function ($value) { + return $value === 'foo'; + }); + } + + public function testAssertWhereNotFailsWhenMatchesValueUsingClosure() + { + $assert = AssertableJson::fromArray([ + 'bar' => 'baz', + ]); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Property [bar] was marked as invalid using a closure.'); + + $assert->whereNot('bar', function ($value) { + return $value === 'baz'; + }); + } + public function testScope() { $assert = AssertableJson::fromArray([