Home Assertable Json String (Laravel 8+)

Enter a search term to find articles.
assertable-json-string-laravel-8
2022-04-12
721

Assertable Json String (Laravel 8+)

Once in a while when diving deep into the Laravel codebase, I find that there are hidden gems that I think would really be helpful to developers. In this post, I'll shed light on one of those hidden gems.

I'm talking about the AssertableJsonString::class that is new since Laravel version 8.x. Let's go!

Typically when testing json responses, we have the ability to chain json assertions from the response like so:

public function test_json_response()
{
    $response = $this->get(route('some.json.endpoint'));

    $response->assertJson(['foo' => 'bar'])
        ->assertJsonMissing(['bar' => 'baz']);
}

Thanks to the fact that response is an instance of Illuminate\Testing\TestResponse::class which holds these convenient json assertion methods. However, there are cases that we need to make assertions against json data that isn't coming from a json endpoint. One example is reading a json file:

public function test_read_package_json_data()
{
    $data = json_decode(
        file_get_contents(base_path('package.json')),
        true
    );

    // This won't work since $data is just a plain array and
    // not an instance of Illuminate\Testing\TestResponse
    $data->assertJsonFragment(["vue" => "^3.2.31"]);
}

Our typical assertions will not work on this example since $data is just a plain array. Before Laravel 8.x my workaround for this is to either pull in a third-party package specifically for json assertions, or wrap the json data with Illuminate\Testing\TestResponse::class like so:

use Illuminate\Http\Response;
use Illuminate\Testing\TestResponse;

...

public function test_read_package_json_data()
{
    $data = json_decode(
        file_get_contents(base_path('package.json')),
        true
    );

    // Wrap the data with Illuminate\Testing\TestResponse class
    // so that you can perform your typical json assertions...
    $response = TestResponse::fromBaseResponse(new Response($data));

    $response->assertJsonFragment(["vue" => "^3.2.31"]);
}

This approach works, but feels kind of hacky. For one, the data is not really an HTTP response so why does it have to go through these response classes?

Thankfully, Laravel 8.x extracted these json assertions into a class called AssertableJsonString::class!

Now we can just wrap our json data with this class and perform our assertions like so:

use Illuminate\Testing\AssertableJsonString

...

public function test_read_package_json_data()
{
    $data = json_decode(
        file_get_contents(base_path('package.json')),
        true
    );

    $data = new AssertableJsonString($data);

    $data->assertFragment(["vue" => "^3.2.31"])
        ->assertMissing(["php" => "^8.1" ]);
}

Enjoy coding!

Marvin Quezon

Full Stack Web Developer
Marvin Quezon · Copyright © 2024 · Privacy · Sitemap