phpunit test returns 302 for bad validation, why not 422
Solution 1
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);
Solution 2
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']
]);
Related videos on Youtube
Comments
-
cre8 over 1 year
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
-
patricus over 8 yearsIf you use ajax, failed validation returns a 422. If you don't, failed validation returns a 302 redirect. Your test either needs to make the request as ajax, or follow the redirect. We can't help further because you didn't post any code, show your test, etc.
-
-
cre8 over 8 yearsIt worked. Also stetting a header with
'HTTP_X-Requested-With' => 'XMLHttpRequest'
works fine withnormal $this->post
-
Rutvij Kothari over 4 years@patricus thanks mate. I've been trying to solve this issue past 8 hours but couldn't figure it out. $this->json was the key. +1