laravelhttp-status-codes

Laravel 9.x different status code while automated testing


One of my automated tests is returning status code 302 whereas it should return 422.

CategoryTest.php

class CategoryTest extends TestCase {
    use RefreshDatabase;

    ...

    public function test_categories_cannot_create_without_payload_should_receive_422() {
        $response = $this->post(route('categories.store'), []);

        $response->assertStatus(Response::HTTP_UNPROCESSABLE_ENTITY);
        $response->assertJson([
            'message',
            'errors',
        ]);
    }

    ...
}

I have also created a global class for handling this situation.

namespace App\Http\Requests;

use Illuminate\Http\Response;
use Illuminate\Validation\ValidationException;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Http\Exceptions\HttpResponseException;

class FormRequest extends \Illuminate\Foundation\Http\FormRequest {
    protected function failedValidation(Validator $validator) {
        if ($this->expectsJson()) {
            throw new HttpResponseException(
                response()->json([
                    'message' => 'Please check the following error(s)',
                    'errors'  => (new ValidationException($validator))->errors(),
                ], Response::HTTP_UNPROCESSABLE_ENTITY)
            );
        }

        parent::failedValidation($validator);
    }
}

The incorrect response while automated testing

The correct response while application is running


Solution

  • Let me try helping.

    I assume that your postman request has a header Accept: application/json, and that makes the $this->expectsJson() to true.

    To make this work in your phpunit, you have to set the request header with the following:

    public function test_categories_cannot_create_without_payload_should_receive_422() {
        $response = $this
            ->withHeader('accept', 'application/json')
            ->post(route('categories.store'), []);
    
        $response->assertStatus(Response::HTTP_UNPROCESSABLE_ENTITY);
        $response->assertJson([
            'message',
            'errors',
        ]);
    }
    

    This should pass the assert status with 422 instead of 302.

    Hope you find this helpful.

    Regards,