As you know when in PHPUnit we use assertEquals()
and assertSame()
and we pass arrays to them, they will assert arrays based on key-value pairs. So if the array is non-assoc array (list) and the order doesn’t matter, the tests will fail. Since these methods consider index as a key and compare the value for each corresponded key.
This problem can easily fixed by custom assertion method like this:
protected function assertListWithoutOrderEquals(array $expected, array $actual): void
{
sort($expected);
sort($actual);
$this->assertEquals($expected, $actual);
}
But when we are in Laravel HTTP test and we have json to assert, Laravel will convert json to array and assert them based on these methods, I think, and I don’t have any idea to fix this problem here.
For example I have this test in Laravel and I have problem for asserting genres
value.:
use IlluminateTestingFluentAssertableJson;
public function test_http_response(): void
{
$expectedData = [
'id' => 1,
'name' => 'The fantastic book',
'genres' => ['science-fiction', 'drama', 'mystery'],
// other elements
];
$response = $this->get('url');
$response->assertJson(
fn(AssertableJson $json) => $json->where('id', $expectedData['id'])
->where('name', $expectedData['name'])
->where('genres', $expectedData['genres']) // This is order sensitive and makes tests to fail.
->etc()
);
}
I tried this but it’s messy. I’m looking for a better and cleaner solution if you can help me.
->where('genres', fn($genres) => $genres->diff($expectedData['genres'])->isEmpty() && $genres->count() == count($expectedData['genres']))
To explain better, Laravel will convert json array to collection, so I checked diff()
and since diff() is an one way method, I mean it checks that all items in first array exist in second array and don’t consider extra items in second array, I checkd the size of them as well.