Yesterday I shared a scenario where a test failure with assertJson
returned a less-than-helpful error with a backed enum.
Today I want to continue that discussion to also point out that not all test assertions treat enums the same.
For example, you can pass a BackedEnum
instance directly to assertExactJson
and it will pass:
// app/Enums/Urgency.php
enum Urgency: string {
case LOW = 'low';
case MEDIUM = 'medium';
case HIGH = 'high';
}
// tests/Feature/ExampleTest.php
$response->assertExactJson([
'data' => [
'urgency' => Urgency::LOW, // no ->value needed here
],
])
Why does this pass when the same approach with assertJson
fails?
As discussed yesterday, assertJson
passes the data through to an underlying PHPUnit assertion.
But assertExactJson
uses the fluent AssertableJsonString
object which massages the data before passing it to PHPUnit::assertEquals
:
// taken from src/Illuminate/Testing/AssertableJsonString.php
PHPUnit::assertEquals(
json_encode($expected, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES),
json_encode($actual, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)
);
As I pointed out yesterday, json_encode
will convert a BackedEnum
instance to its string value, so this assertion will pass.
The key takeaway is that you should know how your assertion works and build your test logic accordingly, especially when dealing with enums.
Here to help,
Joel
P.S. These are some real gems you won't find in the docs. Collect all these tips and keep them for ready reference in our latest volume.