Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

phpunit test returns 302 for bad validation, why not 422

I have a request class that fails for a post request. When I call it with ajax I get an 422 because the validation rules failed. But when I use phpunit for test for the same route with same values, it returns a 302.

I also get no error messages like "field foobar is required" just the 302.

So how can I get the error messages to check if they are equals or not?

Here is my testcode:

//post exam
$this->post('modul/foo/exam', [
    'date' => '2016-01-01'
])
    ->assertResponseStatus(200);

//post exam again
$this->post('modul/foo/exam', [
    'date' => '2016-01-01'
])
    ->assertResponseStatus(302); //need to get 422 with th errors because its an api
like image 622
cre8 Avatar asked Jan 26 '16 22:01

cre8


2 Answers

When the validation on the FormRequest fails, it checks to see if the request was ajax or if it accepts a json response. If so, it will return a json response with the 422 status code. If not, it will return a redirect to a specified url (previous, by default). So, in order to get the response on failure you're looking for (422), you need to make a json request or an ajax request.

JSON

To make a json request, you should use the json() method:

//post exam
$this->json('POST', 'modul/foo/exam', [
        'date' => '2016-01-01'
    ])
    ->assertResponseStatus(200);

//post exam again
$this->json('POST', 'modul/foo/exam', [
        'date' => 'some invalid date'
    ])
    ->assertResponseStatus(422);

There are also getJson(), postJson(), putJson(), patchJson(), and deleteJson() shortcut methods if you think that looks cleaner than passing the method as a parameter.

//post exam
$this->postJson('modul/foo/exam', [
        'date' => '2016-01-01'
    ])
    ->assertResponseStatus(200);

AJAX

To make an ajax request, you need to add in the ajax headers. For this, you can continue to use the post() method:

//post exam
$this->post('modul/foo/exam', [
        'date' => '2016-01-01'
    ], ['HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest'])
    ->assertResponseStatus(200);

//post exam again
$this->post('modul/foo/exam', [
        'date' => 'some invalid date'
    ], ['HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest'])
    ->assertResponseStatus(422);
like image 98
patricus Avatar answered Nov 18 '22 18:11

patricus


For Laravel 6 this works:

withHeaders(['Accept' => 'application/json'])

For an example:

 $this->withHeaders(['Accept' => 'application/json'])
     ->post(route('user.register'), $data)
     ->assertStatus(422)
     ->assertJson($expectedResponse);

If it's needed for multiple test classes, it can be placed in tests/TestCase.php and it will be set up for all test cases.

For an example:

public function setup(): void
{
    $this->withHeaders([
        'Accept' => 'application/json',
        'X-Requested-With' => 'XMLHttpRequest'
    ]);
}

Those headers set in tests/TestCase.php can be extended at any point by the same way. For an example:

$this->withHeaders([
    'Authorization' => 'Bearer '.$responseArray['access_token']
]);
like image 4
azurecorn Avatar answered Nov 18 '22 18:11

azurecorn