New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Tests Feature] Assert Exact JSON Structure #19871
Comments
Sorry please ask on the forums, this repo is for bug reporting only. |
thanks @themsaid For future related issues, https://laravel.io/forum/assert-exact-json-structure |
Here is my solution. <?php
namespace Tests\Support;
use Illuminate\Foundation\Testing\TestResponse;
use PHPUnit\Framework\Assert as PHPUnit;
trait AssertJson
{
public function setUpAssertJson()
{
TestResponse::macro('assertJsonStructureExact', function (array $structure = null, $responseData = null)
{
if (is_null($structure)) {
return $this->assertJson($this->json());
}
if (is_null($responseData)) {
$responseData = $this->decodeResponseJson();
}
if (! array_key_exists('*', $structure)) {
$keys = array_map(function ($value, $key) {
return is_array($value) ? $key : $value;
}, $structure, array_keys($structure));
PHPUnit::assertEquals($keys, array_keys($responseData));
}
foreach ($structure as $key => $value) {
if (is_array($value) && $key === '*') {
PHPUnit::assertInternalType('array', $responseData);
foreach ($responseData as $responseDataItem) {
$this->assertJsonStructureExact($structure['*'], $responseDataItem);
}
} elseif (is_array($value)) {
PHPUnit::assertArrayHasKey($key, $responseData);
$this->assertJsonStructureExact($structure[$key], $responseData[$key]);
} else {
PHPUnit::assertArrayHasKey($value, $responseData);
}
}
return $this;
});
}
} Usage: class MyTestCase extends TestCase
{
use AssertJson;
public function setUp(): void
{
parent::setUp();
$this->setUpAssertJson();
}
public function text_example()
{
$this->get('api/users')->assertJsonStructureExact(['data' => ['*' => ['id', 'email']]]);
}
} |
Maybe, this post is closed and old, but I want shared the updated code for future users: <?php
namespace Tests\Support;
use Illuminate\Foundation\Testing\TestResponse;
use Illuminate\Support\Arr;
use PHPUnit\Framework\Assert as PHPUnit;
trait AssertJson
{
public function setUpAssertJson(): void
{
TestResponse::macro('assertJsonStructureExact', function (array $structure = null, $responseData = null) {
if ($structure === null) {
return $this->assertJson($this->json());
}
if ($responseData === null) {
$responseData = $this->decodeResponseJson();
}
if (!array_key_exists('*', $structure)) {
$keys = array_map(static function ($value, $key) {
return is_array($value) ? $key : $value;
}, $structure, array_keys($structure));
PHPUnit::assertEquals(Arr::sortRecursive($keys), Arr::sortRecursive(array_keys($responseData)));
}
foreach ($structure as $key => $value) {
if (is_array($value) && $key === '*') {
PHPUnit::assertIsArray($responseData);
foreach ($responseData as $responseDataItem) {
$this->assertJsonStructureExact($structure['*'], $responseDataItem);
}
} elseif (is_array($value)) {
PHPUnit::assertArrayHasKey($key, $responseData);
$this->assertJsonStructureExact($structure[$key], $responseData[$key]);
} else {
PHPUnit::assertArrayHasKey($value, $responseData);
}
}
return $this;
});
}
} |
If you're using Laravel 7, |
You can actually move the setup function into the trait itself. https://gist.github.com/Oldenborg/dbea4eb6df6cabf388310e6b0168262f |
Thanks for the solutions here! What do you think about this implementation? use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Illuminate\Testing\TestResponse;
use Illuminate\Testing\Assert as PHPUnit;
TestResponse::macro('assertJsonStructureExact', function(string $path, array $structure) {
$structure = Arr::dot($structure);
$responseStructure = array_keys(Arr::dot($this->decodeResponseJson()->json($path)));
foreach ($structure as $key => $value) {
$keyIndex = Str::afterLast($key, '.');
if (! is_int(($keyIndex)))
{
$newKey = Str::replaceLast($keyIndex, $value, $key);
unset($structure[$key]);
$structure[] = $newKey;
}
}
PHPUnit::assertSame(Arr::sortRecursive($structure), Arr::sortRecursive($responseStructure));
return $this;
}); It uses similar logic (Manipulating into recursively sorted arrays) as in https://github.com/laravel/framework/blob/49ee16b9ee784d425205fa456b43581de7cf804a/src/Illuminate/Testing/AssertableJsonString.php It also will accepts a |
Signal-boosting @Oldenborg's gist. There is an error with the first implementation after upgrading to Laravel 8:
You need to update this line to include
However, I decided to not use this trait after all! Instead, I'm using the Using the example in @brunocascio's original post, I think the $response->assertJson(fn ($json) => $json
->each(fn ($json) => $json
->hasAll(['id', 'name', 'slug'])
)
); Removing Unfortunately, it seems that the |
I know I'm a bit late to the party, I had no idea people were using this, until I randomly looked for a solution to this again today, and forgot that I made the gist....(feeling old..) I will get it updated to use with Laravel 10 |
Description
Currently, I'm using
assertJsonStructure
in order to validate the structure, but it doesn't check the exact JSON structure, for example:Test results are:
assertJsonStructure([['id', 'name', 'slug']]);
: trueassertJsonStructure([['id', 'name']]);
: trueTest results expected:
assertJsonStructure([['id', 'name', 'slug']]);
: trueassertJsonStructure([['id', 'name']]);
: falseIs there some way to validate that?
The text was updated successfully, but these errors were encountered: