4

I have a little problem when I want to test an array in my unit test.

I want to test both structure and type of keys, but I don't know how to process it (I tried, I promise!).

Here is the json input:

{
    "success": true,
    "data": [
        {
            "id": 1,
            "domains_id": 1,
            "sub": "",
            "type": "",
            "ip_or_fqdn": "",
            "created_at": "2022-05-14T08:30:18.000000Z",
            "updated_at": "2022-05-14T08:30:18.000000Z"
        }
    ],
    "message": "Domain retrieved successfully."
}

And there is, for the moment, the test:

it('fetch zone entries [GET] with json response and check response type', function () {

    TestCase::initDatabase();

    Passport::actingAs(
        User::factory()->make()
    );

    $response = $this->withHeaders([
            'Accept' => 'application/json'
        ])
        ->json('GET', '/api/zone')
        ->assertStatus(200)
        ->assertJson(function (AssertableJson $json) {
            $json->has('success')
                 ->whereType('success', 'boolean')
                 ->has('data')
                 ->whereType('data', 'array')
                 ->has('message')
                 ->whereType('message', 'string');
    });

    TestCase::resetDatabase();
});

I want to test the "data" array keys/values with this process and, of course, in this Closure; but is it possible?

3 Answers 3

2

You may use dot notation, for instance

->assertJson(fn (AssertableJson $json) =>
    $json->has('data.id')
        ->where('data.id', 1)
        ->missing('data.x')
    );
Sign up to request clarification or add additional context in comments.

2 Comments

I forgot to precise the data array is a indexed array, so do I have to use the "has" method like this? $json->has('data.0.id') or a joker notation like $json->has('data.*.id')?
Yes. Don't think you can use the joker like that. Maybe you want to take a look at assertJsonStructure: laravel.com/docs/9.x/http-tests#assert-json-structure
2

Finally, with @ajthinking tips, here is the final test and it works, thank you very much!

it('fetch zone entries [GET] with json response and check response type', function () {

    TestCase::initDatabase();

    Passport::actingAs(
        User::factory()->make()
    );

    $response = $this->withHeaders([
        'Accept' => 'application/json'
    ])
        ->json('GET', '/api/zone')
        ->assertStatus(200)
        ->assertJson(function (AssertableJson $json) {
            $json->has('success')
                 ->whereType('success', 'boolean')
                 ->has('data')
                 ->whereType('data', 'array')
                 ->has('data.0')
                 ->has('data.0')
                    ->has('data.0.id')
                    ->has('data.0.sub')
                    ->has('data.0.type')
                    ->has('data.0.ip_or_fqdn')
                    ->has('data.0.created_at')
                    ->has('data.0.updated_at')
                    ->whereType('data.0.id', 'integer')
                    ->whereType('data.0.sub', 'string')
                    ->whereType('data.0.type', 'string')
                    ->whereType('data.0.ip_or_fqdn', 'string')
                    ->whereType('data.0.created_at', 'string')
                    ->whereType('data.0.updated_at', 'string')
                 ->has('message')
                 ->whereType('message', 'string');
    });

    TestCase::resetDatabase();
});

I'll improve this test with an assertJsonStructure() in the future to test base structure and test types in assertJson() closure.

EDIT:

Here is the test with assertJsonStructure() method, and it works fine:

it('fetch zone entries [GET] with json response and check response type', function () {

    TestCase::initDatabase();

    Passport::actingAs(
        User::factory()->make()
    );

    $response = $this->withHeaders([
        'Accept' => 'application/json'
    ])
        ->json('GET', '/api/zone')
        ->assertStatus(200)
        ->assertJsonStructure([
            'success',
            'data' => [
                '*' => [
                    'id',
                    'sub',
                    'type',
                    'ip_or_fqdn',
                    'created_at',
                    'updated_at'
                ]
                ],
            'message'
        ])
        ->assertJson(function (AssertableJson $json) {
            $json->whereType('success', 'boolean')
                 ->whereType('data', 'array')
                 ->whereType('data.0.id', 'integer')
                 ->whereType('data.0.sub', 'string')
                 ->whereType('data.0.type', 'string')
                 ->whereType('data.0.ip_or_fqdn', 'string')
                 ->whereType('data.0.created_at', 'string')
                 ->whereType('data.0.updated_at', 'string')
                 ->whereType('message', 'string');
    });

    TestCase::resetDatabase();
});

Comments

0

You can use macro, e.g. for structure testing


TestResponse::macro('assertJsonCollectionStructure', 
    fn (array $structure) =>
        $this->assertJsonStructure([
           'success,
           'data' => [$structure], 
           'message',
        ])
);

and than use it

->assertJsonCollectionStructure([
    'id',
    'domains_id',
    // ...
])

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.