laravel-json-api / laravel

JSON:API for Laravel applications

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

When using relationships, assertCreatedWithServerId() fails due to relationship sort.

pacoorozco opened this issue · comments

I've a test which use the assertCreatedWithServerId() in order to assert that the object has been created and the returned JSON data is the expected one.

This object has a 1:N relationship and when assertCreatedWithServerId() is asserting the relationship is failing, due to the different sorting when submitting the data and when retrieving it from the store method.

This is the test I'm talking about, see it here:

public function editors_should_create_hosts_groups(): void
    {
        $this->user->givePermissionTo(Permissions::EditHosts);

        /** @var Hostgroup $want */
        $want = Hostgroup::factory()->make();

        $hosts = Host::factory()
            ->count(2)
            ->create();

        $data = [
            'type' => 'hostgroups',
            'attributes' => [
                'name' => $want->name,
                'description' => $want->description,
            ],
            'relationships' => [
                'hosts' => [
                    'data' => $hosts->map(fn (Host $host) => [
                        'type' => 'hosts',
                        'id' => (string) $host->getRouteKey(),
                    ])->all(),
                ],
            ],
        ];

        $id = $this
            ->actingAs($this->user)
            ->jsonApi()
            ->expects('hostgroups')
            ->withData($data)
            ->includePaths('hosts')
            ->post(route('v1.hostgroups.store'))
            ->assertCreatedWithServerId('http://localhost/api/v1/hostgroups', $data)
            ->id();

        $group = Hostgroup::query()
            ->where('id', $id)
            ->where('name', $want->name)
            ->where('description', $want->description)
            ->first();

        $this->assertInstanceOf(Hostgroup::class, $group);

        $this->assertCount(count($hosts), $group->hosts);
    }

And this is the error when running the test, see it here:

1) Tests\Feature\Http\Api\ApiHostgroupsTest::editors_should_create_hosts_groups
Failed asserting that the member at [/data] matches the subset:
{
    "attributes": {
        "description": "Nemo aut beatae ipsa itaque ipsa velit id quis. Quaerat sint consectetur sit et minus. Aspernatur natus autem facilis occaecati quibusdam.",
        "name": "Group_minima"
    },
    "relationships": {
        "hosts": {
            "data": [
                {
                    "id": "28",
                    "type": "hosts"
                },
                {
                    "id": "29",
                    "type": "hosts"
                }
            ]
        }
    },
    "type": "hostgroups"
}

within JSON API document:
{
    "data": {
        "attributes": {
            "createdAt": "2023-04-28T12:46:39.000000Z",
            "description": "Nemo aut beatae ipsa itaque ipsa velit id quis. Quaerat sint consectetur sit et minus. Aspernatur natus autem facilis occaecati quibusdam.",
            "name": "Group_minima"
        },
        "id": "12",
        "links": {
            "self": "http://localhost/api/v1/hostgroups/12"
        },
        "relationships": {
            "hosts": {
                "data": [
                    {
                        "id": "29",
                        "type": "hosts"
                    },
                    {
                        "id": "28",
                        "type": "hosts"
                    }
                ],
                "links": {
                    "related": "http://localhost/api/v1/hostgroups/12/hosts",
                    "self": "http://localhost/api/v1/hostgroups/12/relationships/hosts"
                }
            }
        },
        "type": "hostgroups"
    },
    "included": [
        {
            "attributes": {
                "authorizedKeysFile": null,
                "createdAt": "2023-04-28T12:46:39.000000Z",
                "enabled": true,
                "fullHostname": "chet.schinner@daniel.johnston.org",
                "hostname": "daniel.johnston.org",
                "port": null,
                "synced": false,
                "syncedAt": null,
                "syncedStatus": "Initial status",
                "username": "chet.schinner"
            },
            "id": "29",
            "links": {
                "self": "http://localhost/api/v1/hosts/29"
            },
            "relationships": {
                "groups": {
                    "links": {
                        "related": "http://localhost/api/v1/hosts/29/groups",
                        "self": "http://localhost/api/v1/hosts/29/relationships/groups"
                    }
                }
            },
            "type": "hosts"
        },
        {
            "attributes": {
                "authorizedKeysFile": null,
                "createdAt": "2023-04-28T12:46:39.000000Z",
                "enabled": true,
                "fullHostname": "ora.harber@welch.murphy.org",
                "hostname": "welch.murphy.org",
                "port": null,
                "synced": false,
                "syncedAt": null,
                "syncedStatus": "Initial status",
                "username": "ora.harber"
            },
            "id": "28",
            "links": {
                "self": "http://localhost/api/v1/hosts/28"
            },
            "relationships": {
                "groups": {
                    "links": {
                        "related": "http://localhost/api/v1/hosts/28/groups",
                        "self": "http://localhost/api/v1/hosts/28/relationships/groups"
                    }
                }
            },
            "type": "hosts"
        }
    ],
    "jsonapi": {
        "version": "1.0"
    },
    "links": {
        "self": "http://localhost/api/v1/hostgroups/12"
    }
}.
--- Expected
+++ Actual
@@ @@
         "hosts": {
             "data": [
                 {
-                    "id": "28",
+                    "id": "29",
                     "type": "hosts"
                 },
                 {
-                    "id": "29",
+                    "id": "28",
                     "type": "hosts"
                 }
             ],

Hey! If you're expecting the data to be returned in a particular order, your test should assert the expected order in the response.

In other words this:

->assertCreatedWithServerId('http://localhost/api/v1/hostgroups', $data)

needs adjusting, because $data doesn't actually represent the expected JSON in the response - it represents the request data.

Typically in this scenario I'd have a $data for the data in the request, and a $expected for the data in the response, as the two are semantically different.

Thanks @lindyhopchris for the quick response, it would be great to update the documentation to take it into account. Otherwise is misleading.

Hmmm, yeah possibly. However, it's not really that the docs are wrong - there can be legitimate test scenarios where the request data is the same as the expected response data. I only use $data/$expected in scenarios where the two aren't expected to be the same.

The examples in the docs can't cover every test scenario; tests would always need to be modified for the actual scenario under test.