# Asserting API Response

### **Status Code Asserts:**

Status code asserts ensures that the call to the endpoint returns a specific status code when returned.

The most commonly used will be:

`->assertOk()`

`->assertCreated()`

`->assertNotFound()`

`->assertNoContent()`

`->assertStatus()`

{% hint style="info" %}
Laravel Documentation for all available [assertions](https://laravel.com/docs/9.x/http-tests#response-assertions)
{% endhint %}

#### **Example:**

{% code lineNumbers="true" %}

```php
/**
 * Test that the route /user/mobilenumber returns 200
 *
 * 'number' => 'required|min:10|max:10',
 * 
 * @test
 * @return void
 */
public function user_put_method_mobile_number_returns_200(): void
{
    $this->actingAsAdmin()
        ->authenticate()
        ->put('/user/mobilenumber', [
            "number" => "1555".rand(100000,999999)
        ])
        ->assertOk();
}
```

{% endcode %}

{% hint style="info" %}
An alternative way of testing the status code is by using **`->assertStatus(X)`** , where **`X`** is the expected status code value e.g. `->assertStatus(200)`.
{% endhint %}

### **JSON Response Asserts:**

When the request has returned with a response during the functional tests, an assert should be used to determine if the correct response has returned. Add a message to an assert when possible to increase the maintainability of the tests.

Using `->assertExactJson` , the test can compare the response to the exact expected response. The test will fail if there is a difference, and a message within the terminal will print the discrepancy.

**Example:**

{% code lineNumbers="true" %}

```php
/**
 * Test that the route /user/mobilenumber returns 200
 *
 * 'number' => 'required|min:10|max:10',
 * 
 * @test
 * @return void
 */
public function user_put_method_mobile_number_returns_200(): void
{
    $randomNumber = "1555".rand(100000,999999);
    $this->actingAsAdmin()
         ->authenticate()
         ->put('/user/mobilenumber', [
            "number" => $randomNumber
         ])
         ->assertOk()
         ->assertExactJson([
             'status' => 'success',
             'mobile_number_verified' => false,
             'message' => 'The phone number has been updated successfully to ' . $randomNumber . '.',
         ]);
}
```

{% endcode %}

{% hint style="danger" %}
Note that this example is using `assertExactJson()`, ensure that the JSON returned by the API matches the array **exactly**. If a single property is absent, the assertion will fail.&#x20;
{% endhint %}

If it is undesirable to assert the entire JSON response, then use `->assertJsonFragment()`

{% code lineNumbers="true" %}

```php
->assertJsonFragment(
  [
      'event_title' => 'Test Event 1',
      'course_id' => 1,
      'event_duration' => 60,
  ],
  [
      'event_title' => 'Test Event 3',
      'course_id' => 4,
      'event_duration' => 60,
  ]
);
```

{% endcode %}

**Fluent JSON Testing**

Laravel offers an alternative way to assert JSON responses using the `AssertableJson` utility. For example, when a more complex assertion is needed.&#x20;

{% hint style="info" %}
For more info about fluent JSON assertions, check out the [official documentation](https://laravel.com/docs/9.x/http-tests#fluent-json-testing).
{% endhint %}

{% code lineNumbers="true" %}

```php
$this->actingAsAdmin()
      ->authenticate()
      ->put('/user/mobilenumber', [
            "number" => $randomNumber
      ])
      ->assertOk()
      ->assertJson(fn(AssertableJson $json) => 
            $json->where("status", "success")->has("message")->etc()
      );
```

{% endcode %}

**AssertableJson asserts**

Here are some examples of fluent assertions

<details>

<summary><code>->count()</code></summary>

{% code lineNumbers="true" %}

```php
->assertJson(fn (AssertableJson $json) => $json
    ->count(5) // Validate the number of expected events
)
```

{% endcode %}

We can assert to see how many elements have been returned in a JSON response.

</details>

<details>

<summary><code>->each()</code></summary>

{% code lineNumbers="true" %}

```php
->each(fn ($json) => $json->count(4))
```

{% endcode %}

This will run the anonymous function on each element in the response.&#x20;

</details>

<details>

<summary><code>->whereAllType([])</code> / <code>->whereType()</code></summary>

```php
->whereAllType([
    'event_id' => 'integer',
    'event_title' => 'string',
    'cunit_id' => 'integer|null', // optional value
    'course_id' => 'integer',
    'event_start' => 'string',
    'event_finish' => 'string',
    'event_duration' => 'integer',
])
->whereType('audience_types', 'array');
```

The `whereAllType` assertion checks if the data type returned from the endpoint is correct. Adding a vertical bar `|` acts as an `or` if the value can be a mixed value type. Adding `null` specifies that it’s an optional value returned.

</details>

{% hint style="warning" %}
When there is a delay between when the request is received and the response is returned by the server, do not use the current timestamp `time()` directly in JSON assertions. Instead, save the value of the timestamp in a variable prior to making the request so that it may be asserted against later.
{% endhint %}

{% hint style="info" %}
See Laravel API Docs for more advanced fluent methods: [Laravel API Documentation](https://laravel.com/api/9.x/Illuminate/Testing/AssertableJsonString.html)
{% endhint %}

**Testing File Uploads**

Laravel simplifies testing file uploads using the `Illuminate\Http\UploadedFile::fake()`   method. For example, when testing a CSV file upload, do the following:

{% code lineNumbers="true" %}

```php
$data = implode("\n", [
    'Number/Email,First Name,Last Name',
    'developer2@elentra.com,Jane,student',
]);

$response = $this->actingAsAdmin()
    ->authenticate()
    ->post('clinical/schedules/3/audience/csv', [
        'file' => UploadedFile::fake()->createWithContent('foo.csv', $data)
    ])
    ->assertOk()
    ->assertJson( /** ... */);
```

{% endcode %}

{% hint style="info" %}
Check the [official documentation](https://laravel.com/docs/9.x/http-tests#testing-file-uploads) for information on testing file uploading.
{% endhint %}

#### **Interacted**

Verifying that the test has interacted with all the properties of the JSON response will ensure that updated endpoints not reflected in the test will be caught. The assertion `->interacted()` can be used:

{% code lineNumbers="true" %}

```php
->whereAll([
    'event_id' => 2, // Second will be first since the start date is the earliest.
    'event_title' => 'Test Event at Fixed Time',
    'cunit_id' => null,
    'course_id' => 1,
    'event_start' => '1644974420',
    'event_finish' => '1644984420',
    'event_duration' => 60,
])
->interacted();
```

{% endcode %}

**See and Don't See Asserts**

```php
->assertDontSeeText("Cases/Week_DELETED")
->assertDontSeeText("DELETED_CASE")
->assertDontSeeText("Deleted_Unit", false)
->assertSeeText("Case Created with week in Published");
```

These are very easy assertions to see if a specific search string can be found. This can help ensure that deleted entities are not being returned. It is recommended to save data with titles like `Deleted_` so that assertions do not misidentify similarly worded entities.

#### What and what not to assert

When asserting the contents of a JSON response from an HTTP request, only test specific values that are not likely to change.

The ID field from a POST request will likely change as auto-increment values for primary keys may differ.

```php
->asertJson(fn (AssertableJson $json) =>
     $json→whereType('id', 'integer')
)
```

In GET requests, especially if the seed data specified the same ID for inserting a record, it can be helpful to test if the ID is precisely as expected to ensure the correct records are retrieved.

```php
->asertJson(fn (AssertableJson $json) =>
     $json→where('id', 3)
)
```

The created date, updated date, and updated by are likely to change. Avoid checking for exact values.

```php
->asertJson(fn (AssertableJson $json) =>
     $json→whereType('created_date', 'integer')
          →whereType('updated_date', 'integer|null')
          →whereType('deleted_date', 'integer|null')
)
```

Use the `->has()` assertion to check if the response contains the correct number of elements.

```php
->asertJson(fn (AssertableJson $json) =>
     $json→has('users', 3)
)
```

### Incomplete Tests

Mark a test as incomplete for either an unimplemented method or a test that can’t be fully asserted for a specific reason.

```php
$this->markTestIncomplete('This test has not been implemented yet.');
```

`markTestIncomplete` should be added to the top of the test method with the context of why the test is incomplete. This prevents the execution of any assertions that follow in the test method.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.elentra.org/api/automated-testing/functional-tests/asserting-api-response.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
