Framework: Api resource testing doesn't resolve nested resources

Created on 31 Jan 2018  路  2Comments  路  Source: laravel/framework

  • Laravel Version: 5.5.33
  • PHP Version: 7.2.1
  • Database Driver & Version: sqlite | 3.19.3

Description:

Returning api resources fails to perform toArray on related models when testing.
Or because we cant provide the current request in testing this is causing issues.

Honestly i dont know whats causing it, but i do know the test result shows the roles property is returning a resource collection instance of the roles, not the array produced from that collection.

Steps To Reproduce:

Controller method:

The returned response from a login call

protected function authenticated(Request $request, $user)
{
    return new \App\Http\Resources\User($user->loadMissing(['roles.permissions']));
}

Test method:

    /**
     * Ensure correct logins return user resource
     *
     * @return void
     */
    public function testCorrectLoginReturnsUserResourceTest()
    {
        $user = factory(User::class)->create([
            'app_id' => 1,
            'password' => 'mysecretpass'
        ]);

        $user->roles()->save(Role::first());

        $resource = (new \App\Http\Resources\User($user->loadMissing(['roles.permissions'])))->resolve();

        $response = $this->json('POST', 'login', [
                'email' => $user->email,
                'password' => 'mysecretpass'
            ])
            ->assertStatus(200)
            ->assertJsonStructure([
                'data' => [
                    'id', 'title', 'first_name', 'last_name', 'full_name', 'email', 'reference', 'created_at', 'updated_at'
                ],
                'links' => [
                    'self'
                ]
            ]);

        $this->assertSame($response->json(), $resource);
    }

The resource

class User extends Resource
{
    /**
     * Transform the resource into an array.
     *
     * @param  \Illuminate\Http\Request
     * @return array
     */
    public function toArray($request)
    {
        return [
            'data' => [
                'id' => $this->uuid,
                'title' => $this->title,
                'first_name' => $this->first_name,
                'last_name' => $this->last_name,
                'full_name' => $this->full_name,
                'reference' => $this->reference,
                'api_token' => $this->when($request->route() && $request->route()->getName() === 'api.v1.0.0.users.store' || ($request->user() && $request->user()->id === $this->id), $this->api_token),
                'email' => $this->email,
                'addresses' => Address::collection($this->whenLoaded('addresses')),
                'roles' => Role::collection($this->whenLoaded('roles')),
                'created_at' => (string) $this->created_at,
                'updated_at' => (string) $this->updated_at,
            ],
            'links' => [
                'self' => route('api.v1.0.0.users.show', ['user' => $this->uuid]),
            ],
        ];
    }
}

Phpunit error

Failed asserting that Array &0 (
    'data' => Array &1 (
        'id' => '9fc1e7fc-3bbf-4c69-85d1-0dadc5f1674d'
        'title' => 'Mr'
        'first_name' => 'Brandi'
        'last_name' => 'Feeney'
        'full_name' => 'Brandi Feeney'
        'reference' => '5a71e65051cfd'
        'email' => '[email protected]'
        'roles' => Illuminate\Http\Resources\Json\AnonymousResourceCollection Object &000000004c01bdd1000000001d6d5ff2 (
            'collects' => 'App\Http\Resources\Role'
            'collection' => Illuminate\Support\Collection Object &000000004c01bc29000000001d6d5ff2 (
                'items' => Array &2 (
                    0 => App\Http\Resources\Role Object &000000004c01bc4f000000001d6d5ff2 (
                        'resource' => App\Models\Role Object &000000004c01bd86000000001d6d5ff2 (
                            'fillable' => Array &3 (
                                0 => 'name'
                                1 => 'label'
                            )
                            'hidden' => Array &4 (
                                0 => 'id'
                                1 => 'pivot'
                                2 => 'app_id'
                            )
                            'appends' => Array &5 (
                                0 => 'core'
                            )
                            'connection' => 'test'
                            'table' => null
                            'primaryKey' => 'id'
                            'keyType' => 'int'
                            'incrementing' => true
                            'with' => Array &6 ()
                            'withCount' => Array &7 ()
                            'perPage' => 15
                            'exists' => true
                            'wasRecentlyCreated' => false
                            'attributes' => Array &8 (
                                'id' => '1'
                                'uuid' => '21eb3313-79ca-420b-b112-8a024cb80d23'
                                'name' => 'administrator'
                                'label' => 'Administrator'
                                'created_at' => '2018-01-31 15:52:42'
                                'updated_at' => '2018-01-31 15:52:42'
                                'app_id' => null
                            )
                            'original' => Array &9 (
                                'id' => '1'
                                'uuid' => '21eb3313-79ca-420b-b112-8a024cb80d23'
                                'name' => 'administrator'
                                'label' => 'Administrator'
                                'created_at' => '2018-01-31 15:52:42'
                                'updated_at' => '2018-01-31 15:52:42'
                                'app_id' => null
                                'pivot_user_id' => '1'
                                'pivot_role_id' => '1'
                            )
                            'changes' => Array &10 ()
                            'casts' => Array &11 ()
                            'dates' => Array &12 ()
                            'dateFormat' => null
                            'dispatchesEvents' => Array &13 ()
                            'observables' => Array &14 ()
                            'relations' => Array &15 (
                                'pivot' => Illuminate\Database\Eloquent\Relations\Pivot Object &000000004c01bd87000000001d6d5ff2 (
                                    'pivotParent' => App\Models\User Object &000000004c01a0d4000000001d6d5ff2 (
                                        'dates' => Array &16 (
                                            0 => 'created_at'
                                            1 => 'updated_at'
                                            2 => 'deleted_at'
                                        )
                                        'fillable' => Array &17 (
                                            0 => 'title'
                                            1 => 'first_name'
                                            2 => 'last_name'
                                            3 => 'email'
                                            4 => 'password'
                                            5 => 'api_token'
                                        )
                                        'hidden' => Array &18 (
                                            0 => 'id'
                                            1 => 'password'
                                            2 => 'remember_token'
                                            3 => 'pivot'
                                            4 => 'app_id'
                                        )
                                        'appends' => Array &19 (
                                            0 => 'full_name'
                                        )
                                        'connection' => 'test'
                                        'table' => null
                                        'primaryKey' => 'id'
                                        'keyType' => 'int'
                                        'incrementing' => true
                                        'with' => Array &20 ()
                                        'withCount' => Array &21 ()
                                        'perPage' => 15
                                        'exists' => true
                                        'wasRecentlyCreated' => true
                                        'attributes' => Array &22 (
                                            'uuid' => '9fc1e7fc-3bbf-4c69-85d1-0dadc5f1674d'
                                            'title' => 'Mr'
                                            'first_name' => 'Brandi'
                                            'last_name' => 'Feeney'
                                            'email' => '[email protected]'
                                            'password' => '$2y$04$t7XZe3OP6g79ROayPcS9suesPHuKJJoFJ3bF3nb9wqvkKjRyaAzlu'
                                            'remember_token' => '5ES7sWYPdz'
                                            'api_token' => 'lE0FiO751DpgdkjY3fbPnUnvUKrHGYoF'
                                            'app_id' => 1
                                            'reference' => '5a71e65051cfd'
                                            'updated_at' => '2018-01-31 15:52:48'
                                            'created_at' => '2018-01-31 15:52:48'
                                            'id' => 1
                                        )
                                        'original' => Array &23 (
                                            'uuid' => '9fc1e7fc-3bbf-4c69-85d1-0dadc5f1674d'
                                            'title' => 'Mr'
                                            'first_name' => 'Brandi'
                                            'last_name' => 'Feeney'
                                            'email' => '[email protected]'
                                            'password' => '$2y$04$t7XZe3OP6g79ROayPcS9suesPHuKJJoFJ3bF3nb9wqvkKjRyaAzlu'
                                            'remember_token' => '5ES7sWYPdz'
                                            'api_token' => 'lE0FiO751DpgdkjY3fbPnUnvUKrHGYoF'
                                            'app_id' => 1
                                            'reference' => '5a71e65051cfd'
                                            'updated_at' => '2018-01-31 15:52:48'
                                            'created_at' => '2018-01-31 15:52:48'
                                            'id' => 1
                                        )
                                        'changes' => Array &24 ()
                                        'casts' => Array &25 ()
                                        'dateFormat' => null
                                        'dispatchesEvents' => Array &26 ()
                                        'observables' => Array &27 ()
                                        'relations' => Array &28 (
                                            'roles' => Illuminate\Database\Eloquent\Collection Object &000000004c01bc62000000001d6d5ff2 (
                                                'items' => Array &29 (
                                                    0 => App\Models\Role Object &000000004c01bd86000000001d6d5ff2
                                                )
                                            )
                                        )
                                        'touches' => Array &30 ()
                                        'timestamps' => true
                                        'visible' => Array &31 ()
                                        'guarded' => Array &32 (
                                            0 => '*'
                                        )
                                        'rememberTokenName' => 'remember_token'
                                        'forceDeleting' => false
                                    )
                                    'foreignKey' => 'user_id'
                                    'relatedKey' => 'role_id'
                                    'guarded' => Array &33 ()
                                    'connection' => 'test'
                                    'table' => 'role_user'
                                    'primaryKey' => 'id'
                                    'keyType' => 'int'
                                    'incrementing' => true
                                    'with' => Array &34 ()
                                    'withCount' => Array &35 ()
                                    'perPage' => 15
                                    'exists' => true
                                    'wasRecentlyCreated' => false
                                    'attributes' => Array &36 (
                                        'user_id' => '1'
                                        'role_id' => '1'
                                    )
                                    'original' => Array &37 (
                                        'user_id' => '1'
                                        'role_id' => '1'
                                    )
                                    'changes' => Array &38 ()
                                    'casts' => Array &39 ()
                                    'dates' => Array &40 ()
                                    'dateFormat' => null
                                    'appends' => Array &41 ()
                                    'dispatchesEvents' => Array &42 ()
                                    'observables' => Array &43 ()
                                    'relations' => Array &44 ()
                                    'touches' => Array &45 ()
                                    'timestamps' => false
                                    'hidden' => Array &46 ()
                                    'visible' => Array &47 ()
                                    'fillable' => Array &48 ()
                                )
                                'permissions' => Illuminate\Database\Eloquent\Collection Object &000000004c01bd85000000001d6d5ff2 (
                                    'items' => Array &49 ()
                                )
                            )
                            'touches' => Array &50 ()
                            'timestamps' => true
                            'visible' => Array &51 ()
                            'guarded' => Array &52 (
                                0 => '*'
                            )
                        )
                        'with' => Array &53 ()
                        'additional' => Array &54 ()
                    )
                )
            )
            'resource' => Illuminate\Support\Collection Object &000000004c01bc29000000001d6d5ff2
            'with' => Array &55 ()
            'additional' => Array &56 ()
        )
        'created_at' => '2018-01-31 15:52:48'
        'updated_at' => '2018-01-31 15:52:48'
    )
    'links' => Array &57 (
        'self' => 'http://localhost/api/v1.0.0/users/9fc1e7fc-3bbf-4c69-85d1-0dadc5f1674d'
    )
) is identical to Array &0 (
    'data' => Array &1 (
        'id' => '9fc1e7fc-3bbf-4c69-85d1-0dadc5f1674d'
        'title' => 'Mr'
        'first_name' => 'Brandi'
        'last_name' => 'Feeney'
        'full_name' => 'Brandi Feeney'
        'reference' => '5a71e65051cfd'
        'api_token' => 'lE0FiO751DpgdkjY3fbPnUnvUKrHGYoF'
        'email' => '[email protected]'
        'roles' => Array &2 (
            0 => Array &3 (
                'data' => Array &4 (
                    'id' => '21eb3313-79ca-420b-b112-8a024cb80d23'
                    'name' => 'administrator'
                    'label' => 'Administrator'
                    'core' => true
                    'permissions' => Array &5 ()
                    'created_at' => '2018-01-31 15:52:42'
                    'updated_at' => '2018-01-31 15:52:42'
                )
                'links' => Array &6 (
                    'self' => ''
                )
            )
        )
        'created_at' => '2018-01-31 15:52:48'
        'updated_at' => '2018-01-31 15:52:48'
    )
    'links' => Array &7 (
        'self' => 'http://localhost/api/v1.0.0/users/9fc1e7fc-3bbf-4c69-85d1-0dadc5f1674d'
    )
).

Most helpful comment

@leemason - its because the resource is not a json representation when comparing. Try the below, I used something like this and it works perfectly.

$resource = (new \App\Http\Resources\User($user->loadMissing(['roles.permissions'])));
and
$this->assertSame(json_decode($resource->response()->getContent(), true), $response->json());

All 2 comments

I can't replicate this, seems to be working fine for me, please test in a fresh laravel app using simple two nested resources, if issue can be replicated on a fresh sample app please share the repo URL so we can clone that project and run the tests.

@leemason - its because the resource is not a json representation when comparing. Try the below, I used something like this and it works perfectly.

$resource = (new \App\Http\Resources\User($user->loadMissing(['roles.permissions'])));
and
$this->assertSame(json_decode($resource->response()->getContent(), true), $response->json());

Was this page helpful?
0 / 5 - 0 ratings