Hey all! After going through this course, I still had issues with asserting API JSON responses in an expressive way given the way Laravel's TestResponse helpers work, so I created a few macros that helped, so I'm posting them here if anyone wants to use them. Feel free to suggest improvements 😄
My main issues where:
$this->assertJsonMissing(), etc doesn't work with nested keys - ie. Laravel's ['data' => '...'] convention using Resource classes. There are some issues on this, but Taylor chose to leave this out of core.
Asserting sort orders, etc in an expressive way, especially given # 1 above
Example Usage for a Geo-Location App:
// Not Nearby
factory(Some::class)->create(['location' => '40,-80.1111', 'some-identifier' => 1003]);
// Nearby - But created out of order distance wise (intentionally)
factory(Some::class)->create(['location' => '40,-80.0002', 'some-identifier' => 1001]);
factory(Some::class)->create(['location' => '40,-80.0003', 'some-identifier' => 1002]);
factory(Some::class)->create(['location' => '40,-80.0001', 'some-identifier' => 1000]);
$userLocation = '40,-80.0000'; // lat, long
$response = $this->json('GET', "/locations?near={$userLocation}");
$response->assertHasWhere('some-identifier', [1000, 1001, 1002]);
$response->assertMissingWhere('some-identifier', [1003]);
$response->assertSort('some-identifier', [1000, 1001, 1002]);
Macros:
/**
* Asserts response has objects with the given key/value(s)
*/
TestResponse::macro('assertHasWhere', function (string $key, $values, bool $strict = false)
{
$content = $this->decodeResponseJson();
$content = $content['data'] ?? $content;
$values = is_array($values) ? $values : [$values];
$method = $strict ? 'whereInStrict' : 'whereIn';
PHPUnit::assertTrue((collect($content)->$method($key, $values)->count() === sizeof($values)), 'Failed to assert json response contained all values');
return $this;
});
/**
* Asserts response has objects sorted in the specified order by key
*/
TestResponse::macro('assertSort', function (string $key, array $values, bool $strict = false)
{
$content = $this->decodeResponseJson();
$content = $content['data'] ?? $content;
$method = $strict ? 'whereInStrict' : 'whereIn';
$contentSubset = collect($content)->$method($key, $values)->pluck($key)->all();
PHPUnit::assertEquals($values, $contentSubset, 'Failed to assert sorted');
return $this;
});
/**
* Asserts response is missing objects with the given key/value(s)
*/
TestResponse::macro('assertMissingWhere', function (string $key, $values, bool $strict = false)
{
$content = $this->decodeResponseJson();
$content = $content['data'] ?? $content;
$values = is_array($values) ? $values : [$values];
$method = $strict ? 'whereInStrict' : 'whereIn';
PHPUnit::assertTrue((collect($content)->$method($key, $values)->count() === 0), 'Failed to assert json response was missing all values');
return $this;
});
I toyed with just added an $assertSort flag to assertHasWhere, along with a few other approaches, but the error messages were a bit convoluted, so I split them out into separate macros.
Enjoy!
P.S. I couldn't find a better place to post these, so if an Issue isn't the best place, let me know.
Hey all! After going through this course, I still had issues with asserting API JSON responses in an expressive way given the way Laravel's TestResponse helpers work, so I created a few macros that helped, so I'm posting them here if anyone wants to use them. Feel free to suggest improvements 😄
My main issues where:
$this->assertJsonMissing()
, etc doesn't work with nested keys - ie. Laravel's['data' => '...']
convention using Resource classes. There are some issues on this, but Taylor chose to leave this out of core.Example Usage for a Geo-Location App:
Macros:
I toyed with just added an
$assertSort
flag toassertHasWhere
, along with a few other approaches, but the error messages were a bit convoluted, so I split them out into separate macros.Enjoy!
P.S. I couldn't find a better place to post these, so if an Issue isn't the best place, let me know.