I want to test the delete method but I am not getting the expected results from PHPUnit. I receive this message when running the test:
Expected status code 200 but received 419. Failed asserting that false is true.
/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestResponse.php:77
/tests/Unit/CategoriesControllerTest.php:70
Laravel version: 5.5
Thank you for any help!
Controller constructor:
public function __construct()
{
$this->middleware('auth');
$this->middleware('categoryAccess')->except([
'index',
'create'
]);
}
Controller method:
public function destroy($categoryId)
{
Category::destroy($categoryId);
session()->flash('alert-success', 'Category was successfully deleted.');
return redirect()->action('CategoriesController@index');
}
categoryAccess middleware:
public function handle($request, Closure $next)
{
$category = Category::find($request->id);
if (!($category->user_id == Auth::id())) {
abort(404);
}
return $next($request);
}
Category model:
protected $dispatchesEvents = [
'deleted' => CategoryDeleted::class,
];
Event listener
public function handle(ExpensesUpdated $event)
{
$category_id = $event->expense->category_id;
if (Category::find($category_id)) {
$costs = Category::find($category_id)->expense->sum('cost');
$category = Category::find($category_id);
$category->total = $costs;
$category->save();
}
}
PHPUnit delete test:
use RefreshDatabase;
protected $user;
public function setUp()
{
parent::setUp();
$this->user = factory(User::class)->create();
$this->actingAs($this->user);
}
/** @test */
public function user_can_destroy()
{
$category = factory(Category::class)->create([
'user_id' => $this->user->id
]);
$response = $this->delete('/category/' . $category->id);
$response->assertStatus(200);
$response->assertViewIs('category.index');
}
The following 3 soluction of 419 status code (unknown status) laravel are also work with laravel 7, 6, 5. 5.5, 5, 4 version. In this first solution, open your blade view file and add the following line of code into your blade view file head section: Next, open again your blade view file.
Laravel, as one of the popular PHP frameworks was built with testing in mind and comes with a testing suite named PHPUnit. PHPUnit is a testing framework built to enhance PHP developers’ productivity during development.
This is important for phpunit to recognize your test while running. Go to your terminal and run the test by executing the following commmand. The test will fail since, with following message. 1) Tests\Feature\PostsTest::a_user_can_browse_posts Expected status code 200 but received 404.
Like the Test suffix for class names, this test prefix tells PHPUnit what methods to run when testing. If you forget the test prefix, then PHPUnit will ignore the method. Before we run our test suite for the first time, it is worth pointing out the default phpunit.xml file that Laravel provides.
Solution: When you cached your configuration files you can resolve this issue by running php artisan config:clear
.
Explanation: The reason why this can resolve the issue is that PHPUnit will use the cached configuration values instead of the variables defined in your testing environment. As a result, the APP_ENV
is not set to testing, and the VerifyCsrfTokenMiddleware
will throw a TokenMismatchException
(Status code 419).
It won't throw this exception when the APP_ENV
is set to testing since the handle
method of VerifyCsrfTokenMiddleware
checks if you are running unit tests with $this->runningUnitTests()
.
It is recommended not to cache your configuration in your development environment. When you need to cache your configuration in the environment where you are also running unit tests you could clear your cache manually in your TestCase.php
:
use Illuminate\Support\Facades\Artisan;
public function createApplication()
{
....
Artisan::call('config:clear')
....
}
Example based on https://github.com/laravel/framework/issues/13374#issuecomment-239600163
Read more about configuration caching in this blog post or the Laravel documentation.
This is the exact solution:
Laravel environment will set after bootstraping application, so you cant change it from appServiceProvider or another source. for fix this error you need to add this function to App\Http\Middleware\VerifyCsrfToken
public function handle($request, \Closure $next)
{
if(env('APP_ENV') !== 'testing')
{
return parent::handle($request, $next);
}
return $next($request);
}
you need to use env('APP_ENV') that is set in .env.testing file with
APP_ENV=testing
Sometimes in testing you will need to disable middlewares to proceed :
use Illuminate\Foundation\Testing\WithoutMiddleware;
class ClassTest extends TestCase
{
use WithoutMiddleware; // use this trait
//tests here
}
and if you want to disable them just for one specific test use :
$this->withoutMiddleware();
The message here is indeed related to the CSRF middleware. But there is a much better way of attacking this problem than disabling the middleware.
The middleware comes with code built-in that detects if it is being used in a test. This check looks for 2 things:
testing
Default, proper setup of the software correctly causes both flags to be true when running PHP unit. However, the most likely culprit is the value in your APP_ENV
. Common ways for this to to be incorrect include:
phpunit.xml
file. It should contain <server name="APP_ENV" value="testing" />
APP_ENV
that overrides this valueAPP_ENV
. Seeing about getting this value set via the .env and/or phpunit.xml files is perhaps better if possible. Or ensuring the build/test process sets the value.This one stumped me as well and I was not convinced that I would need the use of WithoutMiddleware
since I did not for a different project, but it turned out I had experimented with something on the command line and overrode APP_ENV
in bash.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With