Mistre83
Mistre83

Reputation: 2827

Laravel - Assert json array ids using wildcard

In my application I have a response like this:

{
  "items": [
    {
      "id": 10,
      "field": "foo"
    },
    {
      "id": 20,
      "field": "bar"
    }
  ]
}

I need to test the content of items and validate each id.

I've tried many solutions but no one works, for example (this is just a kind of pseudo-code):

assertJson(fn (AssertableJson $json) =>
    $json->where('items.*.id', [10, 20])
)

Is there a way to use a wildcard to pick every ID and validate using an array?

Upvotes: 1

Views: 1372

Answers (2)

miken32
miken32

Reputation: 42725

The lack of support for testing an array of randomly ordered elements is pretty frustrating. I just came across this problem and solved it by looping over the array of things I was looking for and making sure they're all in the response data. Fortunately there's an AssertableJson::toArray() method which allows access to the JSON directly.

<?php

namespace Tests\Feature;

use Illuminate\Testing\Fluent\AssertableJson;
use Symfony\Component\HttpFoundation\Response;

use Tests\TestCase;

class ReportingTest extends TestCase
{
    public function testReportData(): void
    {
        $expected_ids = [10, 20];
        $this->getJson(route("report.view"))
            ->assertStatus(Response::HTTP_OK)
            ->assertJsonIsObject()
            ->assertJson(function (AssertableJson $response) use ($expected_ids) {
                $response
                    ->has("items", 2)
                    ->has("items", function (AssertableJson $items) use ($expected_ids) {
                        $item_ids = array_column($items->toArray(), "id");
                        foreach ($expected_ids as $id) {
                            $this->assertContains($id, $item_ids);
                        }
                    });
            });
    }
}

Upvotes: 2

Joundill
Joundill

Reputation: 7594

You can use array_filter:

$idArray = [10, 20];

$myObj = json_decode($json); // Turn JSON to obj
$items = $myObj["items"]; // Get items from object

// Filter the items for items that aren't in the ID list
$invalidItems = array_filter($items, function ($el) {
    // If the item has an id which isn't in the array, return true
    return !in_array($el["id"], $idArray);
});

// This returns true if we found 0 items with IDs not in the ID list
return $invalidItems == [];

You can similarly use array_map to simplify your array, then compare it to your ID array:

$myObj = json_decode($json); // Turn JSON to obj
$items = $myObj["items"]; // Get items from object

$outIdArray = array_map(function($el) {
    return $el["id"];
}, $items);

// Compare $outIdArray to [10, 20]

Upvotes: 0

Related Questions