-
-
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; | |
}); | |
} | |
} |
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'
].
Not sure what I'm doing wrong. I get
assertJsonStructure
would work fine there, but has the downside of this.Edit:
I found my problem. My
TestCase
Class has its ownsetUp
method, which overrides thesetUp
from the trait. So I add$this->setUpAssertJson();
to my setUp method and now everything works fine.