38

I am creating a unit test and want to test the JSON structure returned in the response. I am aware that the TestResponse provides a method assertJsonStructure to match the structure of your JSON response. But for some reason I am unable to map the $structure to my response and in result the test fails. Let me share the required snippets.

Endpoint Response

{
   "status": true,
   "message": "",
   "data": [
       {
          "id": 2,
          "name": "Shanelle Goodwin",
          "email": "chaz43@example.net",
          "created_at": "2017-03-05 16:12:49",
          "updated_at": "2017-03-05 16:12:49",
          "user_id": 1
       }
    ]
}

Test Function

public function testEndpoint(){

  $response = $this->get('/api/manufacturer/read', [], $this->headers);
  $response->assertStatus(200);
  $response->assertJsonStructure([
    'status',
    'message',
    'data' => [
      {
        'id',
        'name',
        'email',
        'created_at',
        'updated_at',
        'user_id'
      }
    ]
  ]);
  var_dump("'/api/manufacturer/read' => Test Endpoint");
}

There can multiple nodes in data array so that is why i tried to mention the array in structure but seems it doesn't map correctly.Any help would be appreciated :-)

Marcin Nabiałek
  • 109,655
  • 42
  • 258
  • 291
Farooq Ahmed Khan
  • 3,975
  • 3
  • 27
  • 36

2 Answers2

106

Luckily, playing with different options I have solved this issue. A '*' is expected as key if we are to match a nested object in an array. We can see the reference here.

Source: TestResponse

I have set the structure like this for array ofobjects`

$response->assertJsonStructure([
    'status',
    'message',
    'data' => [
      '*' => [
        'id',
        'name',
        'email',
        'created_at',
        'updated_at',
        'user_id'
      ]
    ]
  ]);

And if you want to match just a single object

$response->assertJsonStructure([
    'status',
    'message',
    'data' => [
      [
        'id',
        'name',
        'email',
        'created_at',
        'updated_at',
        'user_id'
      ]
    ]
  ]);
Farooq Ahmed Khan
  • 3,975
  • 3
  • 27
  • 36
  • 6
    Extremely useful! should be in the official docs. Thanks for fishing it out for us. – Jannie Theunissen May 12 '17 at 11:46
  • 1
    [the code has moved](https://github.com/laravel/framework/blob/5.4/src/Illuminate/Foundation/Testing/TestResponse.php#L363) – Tim Ogilvy Jan 23 '18 at 05:54
  • When the structure does not match, testing framework does not show the NOT matching response. How can I access it? – Onur Demir Sep 14 '18 at 16:59
  • 1
    How about array of object with one prop? You're solution worked for me but it raises an error for this => `['data' => ['*' => [name]]]` . It's an **error** not failure and it says: `Argument #2 (No Value) of PHPUnit\Framework\Assert::assertArrayHasKey() must be a array or ArrayAccess`. After adding another prop the error gone! – Khalil Laleh May 09 '19 at 05:42
  • 1
    for any one wondering if it's not on the docs, it's actually on the docs: https://laravel.com/docs/8.x/http-tests#assert-json-structure – mending3 Dec 22 '21 at 19:09
3

I think you should use:

 $response->assertJsonStructure([
    'status',
    'message',
    'data' => [
      [ // change here
        'id',
        'name',
        'email',
        'created_at',
        'updated_at',
        'user_id'
      ] // change here
    ]
  ]);
Marcin Nabiałek
  • 109,655
  • 42
  • 258
  • 291