Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHPUnit: Expected status code 200 but received 419 with Laravel

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');
}
like image 909
baselsoftwaredev Avatar asked Sep 20 '17 15:09

baselsoftwaredev


People also ask

How to solve 419 status code (unknown status) Laravel?

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.

What is PHPUnit testing in Laravel?

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.

How to run a test while running in PHPUnit?

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.

What does the test prefix mean in PHPUnit?

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.


4 Answers

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.

like image 84
piscator Avatar answered Oct 27 '22 21:10

piscator


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
like image 33
Farid shahidi Avatar answered Oct 27 '22 20:10

Farid shahidi


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();
like image 13
Maraboc Avatar answered Oct 27 '22 19:10

Maraboc


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:

  • Am I being ran via a command line
  • Am I being ran in an environment type of 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:

  • Misconfigured phpunit.xml file. It should contain <server name="APP_ENV" value="testing" />
  • A shell session that has an explicit value set in APP_ENV that overrides this value
  • A Docker/docker-compose/kubernetes session that has an explicit value set in APP_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.

like image 4
Jouva Moufette Avatar answered Oct 27 '22 21:10

Jouva Moufette