-
-
Save Oldenborg/dbea4eb6df6cabf388310e6b0168262f to your computer and use it in GitHub Desktop.
<?php | |
namespace Tests\Traits; | |
use Illuminate\Testing\TestResponse; | |
use Illuminate\Support\Arr; | |
use PHPUnit\Framework\Assert as PHPUnit; | |
trait AssertJson | |
{ | |
/* @before */ | |
public function setUp(): void | |
{ | |
parent::setUp(); | |
$this->setUpAssertJson(); | |
} | |
public function setUpAssertJson(): void | |
{ | |
TestResponse::macro('assertJsonStructureExact', function (array $structure = null, $responseData = null) { | |
$transformStructure = function ($structure, $prefix = '') use (&$transformStructure) { | |
$result = []; | |
foreach ($structure as $key => $value) { | |
if (is_array($value) && array_keys($value) !== range(0, count($value) - 1)) { | |
$result = array_merge($result, $transformStructure($value, $prefix . $key . '.')); | |
} elseif (is_array($value)) { | |
foreach ($value as $k) { | |
$result[] = $prefix . $key . '.' . $k; | |
} | |
} else { | |
$result[] = $prefix . $value; | |
} | |
} | |
return $result; | |
}; | |
$expectedKeys = $transformStructure($structure); | |
sort($expectedKeys); | |
if ($responseData === null) { | |
$responseData = json_decode($this->getContent(), true); | |
} | |
$responseKeys = Arr::dot($responseData); | |
$responseKeys = array_keys($responseKeys); | |
sort($responseKeys); | |
$missingKeys = array_diff($expectedKeys, $responseKeys); | |
$extraKeys = array_diff($responseKeys, $expectedKeys); | |
$errorMessage = ""; | |
if (!empty($extraKeys)) { | |
$prettyList = "[\n '" . implode("',\n '", $extraKeys) . "'\n]"; | |
$errorMessage .= "The response had the following unexpected parameters:\n" . $prettyList . "."; | |
} | |
if (!empty($missingKeys)) { | |
$prettyList = "[\n '" . implode("',\n '", $missingKeys) . "'\n]"; | |
$errorMessage .= "The response is missing the following parameters:\n" . $prettyList . "."; | |
} | |
PHPUnit::assertTrue(empty($missingKeys) && empty($extraKeys), $errorMessage); | |
return $this; | |
}); | |
} | |
} |
Thanks to @dmitrybubyakin and @MrJmpl3 for the initial code solution
Not sure what I'm doing wrong. I get
1) Tests\Feature\OpticalReaderModelTest::testIndex
BadMethodCallException: Method Illuminate\Http\JsonResponse::assertJsonStructureExact does not exist.
Illuminate/Support/Traits/Macroable.php:103
Illuminate/Testing/TestResponse.php:1327
tests/Feature/OpticalReaderModelTest.php:36
assertJsonStructure
would work fine there, but has the downside of this.
Edit:
I found my problem. My TestCase
Class has its own setUp
method, which overrides the setUp
from the trait. So I add $this->setUpAssertJson();
to my setUp method and now everything works fine.
After upgrading to Laravel 8, I got this error from previously (in Laravel 7) working tests.
- Tests\Feature\MyTest::testIndex
ErrorException: array_keys() expects parameter 1 to be array, object giventests/AssertJson.php:37
vendor/laravel/framework/src/Illuminate/Macroable/Traits/Macroable.php:111
vendor/laravel/framework/src/Illuminate/Testing/TestResponse.php:1215
tests/Feature/MyTest.php:28
The breaking change is in:
if ($responseData === null) {
$responseData = $this->decodeResponseJson();
}
decodeResponseJson()
will now return an object with the original json and the decoded array. Unfortunately, the decoded array is protected and not accessible from this trait.
Here is how to fix this: (Line 25-27)
if ($responseData === null) {
$responseData = json_decode($this->decodeResponseJson()->json, true);
}
I had success fixing it by doing this, instead of calling json_decode()
:
$responseData = $this->decodeResponseJson()->json();
Not sure when exactly the json()
method was introduced.
I had success fixing it by doing this, instead of calling
json_decode()
:$responseData = $this->decodeResponseJson()->json();
Not sure when exactly the
json()
method was introduced.
I havent look at this trait for a long time. And I haven't been doing much Laravel development the past few years. @IllyaMoskvin do you suggest I update my Trait to reflect this change to $responseData = $this->decodeResponseJson()->json();
?
I have finally taken the time to update this Trait so it works with the lastest version of Laravel (10)
At the same time, I have implemented more meaningful error messages that will be visible in the console.
FAILED Tests\Feature\AuthenticationTest > a guest can register
The response had the following unexpected parameters:
[
'data.token',
'data.user.created_at',
'data.user.email_verification_token',
'data.user.updated_at'
],
The response is missing the following parameters:
[
'status'
].
How to use this trait.
tests\AssertJson.php
example