framework: phpunit: Unable to find JSON fragment

When I test my api I get the following error:

Unable to find JSON fragment ["company":{"name":"Johnston Group","token":"JVW","updated_at":"2015-11-24 16:47:04","created_at":"2015-11-24 16:47:04","id":1}] within [{"company":{"created_at":"2015-11-24 16:47:04","id":"1","name":"Johnston Group","token":"JVW","updated_at":"2015-11-24 16:47:04"},"company_id":"1","created_at":"2015-11-24 16:47:04","firstname":"","id":1,"lastname":"","pin":"1234","token":"JVWBkC","updated_at":"2015-11-24 16:47:04"}].

Here again the both json outputs aligned:

 ["company":{"name":"Johnston Group","token":"JVW","updated_at":"2015-11-24 16:47:04","created_at":"2015-11-24 16:47:04","id":1}]
[{"company":{"created_at":"2015-11-24 16:47:04","id":"1","name":"Johnston Group","token":"JVW","updated_at":"2015-11-24 16:47:04"},"company_id":"1","created_at":"2015-11-24 16:47:04","firstname":"","id":1,"lastname":"","pin":"1234","token":"JVWBkC","updated_at":"2015-11-24 16:47:04"}]

As you can see the fragment is indeed present (wrong order, though). So why this error appears?

My seeJSON command tests on this:

            ->seeJson([
               'company' => $company,
               'firstname' => '',
               'lastname' => '',
               'pin' => 1234,
               'role' => 1
            ]);

About this issue

  • Original URL
  • State: closed
  • Created 9 years ago
  • Reactions: 4
  • Comments: 24 (1 by maintainers)

Most upvoted comments

I have the same issue like @jairovsky.

@GrahamCampbell Do you need more details? I don’t understand why you closed this issue 😦

I “fixed” the issue by editing Lumen / Laravel MakesHttpRequests.php class. I just added 4 lines of code in SeeJsonContains method.

Lines added

    if (is_array($value)) {
        $this->seeJsonContains($value, $negate);
        continue;
    }

New SeeJsonContains methods

/**
     * Assert that the response contains the given JSON.
     *
     * @param  array  $data
     * @param  bool  $negate
     * @return $this
     */
    protected function seeJsonContains(array $data, $negate = false)
    {
        $method = $negate ? 'assertFalse' : 'assertTrue';

        $actual = json_decode($this->response->getContent(), true);

        if (is_null($actual) || $actual === false) {
            return PHPUnit::fail('Invalid JSON was returned from the route. Perhaps an exception was thrown?');
        }

        $actual = json_encode(array_sort_recursive(
            (array) $actual
        ));

        foreach (array_sort_recursive($data) as $key => $value) {
            $expected = $this->formatToExpectedJson($key, $value);

            if (is_array($value)) {
                $this->seeJsonContains($value, $negate);
                continue;
            }

            PHPUnit::{$method}(
                Str::contains($actual, $expected),
                ($negate ? 'Found unexpected' : 'Unable to find')." JSON fragment [{$expected}] within [{$actual}]."
            );
        }

        return $this;
    }

phpunit result before changes

PHPUnit 6.2.4 by Sebastian Bergmann and contributors.

F                                                                   1 / 1 (100%)

Time: 95 ms, Memory: 16.00MB

There was 1 failure:

1) Tests\API\FlowTest::testCreation
Unable to find JSON fragment ["response":[]] within [{"message":"Success","response":{"created_at":"2017-08-25 19:26:28","description":"Reprehenderit voluptates veritatis et rerum nulla at. Nesciunt adipisci earum explicabo odit aut. Dolores nam est eaque eos. Ducimus rerum atque voluptas quo eius dolores.","id":7,"label":"minima expedita aut","updated_at":"2017-08-25 19:26:28","user_id":2},"success":true}].
Failed asserting that false is true.

/home/rom1/bbbot-api/vendor/laravel/lumen-framework/src/Testing/Concerns/MakesHttpRequests.php:288
/home/rom1/bbbot-api/vendor/laravel/lumen-framework/src/Testing/Concerns/MakesHttpRequests.php:213
/home/rom1/bbbot-api/tests/API/FlowTest.php:34

FAILURES!
Tests: 1, Assertions: 2, Failures: 1.

phpunit result after changes

PHPUnit 6.2.4 by Sebastian Bergmann and contributors.

.                                                                   1 / 1 (100%)

Time: 85 ms, Memory: 16.00MB

OK (1 test, 5 assertions)

I don’t know if I should make a merge request as it is a bit “hacky”…

Actually it will look for the key / value in all the JSON at any depth so if you have a JSON with same key at different nested-level, the test may pass while the key / value cheked was not the correct one.

@kgkg would be cool if you could handle that new issue. I didnt use Laravel in a long time. I just keep geeting updates about this issue and its actually quite amusing and sad at the same time 😄

I dont know why this was closed prematurely since this is a real problem

Same, I don’t use Lumen anymore but it is quite funny that such an important point that testing API response (main purpose of this framework) is still not resolved several years after the bug came out.

@Fuzzyma: maybe try to create new issue, I think they may ignore it since it’s closed. This is a serious issue, because right now there is no convenient method to check API response if it’s not just flat array.

Since this issue is already 4 years old, it seems like nobody cares about that even though it feels like this could be fixed fairly easily. @jairovsky @GrahamCampbell any news?

A workaround for the bug with $response->assertJson($array) is $response->assertSee(json_encode($array)).

I agree that i missed the role. However the error remains when I comment out pin and role. Furtermore the error is pointing to the company-object which is obviously not found and not the pin or role.

So there actually is an issue here (or is there some other magic involved?)

Also there are some mistakes in the json representation as well:

 ["company":{"name":"Johnston Group","token":"JVW","updated_at":"2015-11-24 16:47:04","created_at":"2015-11-24 16:47:04","id":1}]
 ^--array literal but the content is what you would see in an object literal. Its no valid json

seeJson make strict comparisons, so 'pin' => 1234 (interpreted as integer) will fail because the JSON returned by your API is actually "pin":"1234" (interpreted as string).

Also, the JSON returned by your API lacks a role attribute.