Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I fix "419 - Page expired" error in a Laravel 8 test?

I'm a Laravel newbie going through some tutorials.

I got stuck of a rather simple testing exercise where the test should make a simple post in a form and then check that the new data is in the database.

Unfortunately my test is failing because the "post" call is getting a "Page Expired" answer.

The test code:

<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Tests\TestCase;

class SubmitLinksTest extends TestCase
{
    use RefreshDatabase;

    /** @test */
    public function guest_can_submit_a_new_link()
    {
      $response = $this->post('/submit', [
          'title' => 'Example Title',
          'url' => 'http://example.com',
          'description' => 'Example description.',
      ]);

      $response->dump();

      $this->assertDatabaseHas('links', [
          'title' => 'Example Title'
      ]);

      $response
          ->assertStatus(302)
          ->assertHeader('Location', url('/'));

      $this
          ->get('/')
          ->assertSee('Example Title');
    }
}

And the result of calling php artisan test:

...

                    <div class="px-4 text-lg text-gray-500 border-r border-gray-400 tracking-wider">\n
                        419                    </div>\n \n
                    <div class="ml-4 text-lg text-gray-500 uppercase tracking-wider">\n
                        Page Expired                    </div>\n
                </div>\n
            </div>\n
        </div>\n
    </body>\n </html>\n """

   FAIL  Tests\Feature\SubmitLinksTest   ⨯ guest can submit a new link

  ---

  • Tests\Feature\SubmitLinksTest > guest can submit a new link   Failed asserting that a row in the table [links] matches the attributes {
      "title": "Example Title"   }.
     The table is empty..

  at tests/Feature/SubmitLinksTest.php:28
     24▕ 
     25▕       $response->dump();
     26▕ 
     27▕       $this->assertDatabaseHas('links', [   ➜  28▕           'title' => 'Example Title'
     29▕       ]);
     30▕ 
     31▕       $response
     32▕           ->assertStatus(302)


  Tests:  1 failed   Time:   0.14s

I tried several hacks (calling "$this->get('/submit');" before the post, manually setting "APP_DEBUG" to true, "APP_ENV" to testing, etc.) but none worked.

Anyway, AFAIU, calling "php artisan test" should take care of disabling CSFR Token verification during testing as per Laravel's 8 documentation: https://laravel.com/docs/8.x/http-tests#customizing-request-headers

I've read several similar questions mentioning error 419 in Laravel but none is test related. The fixes proposed on them didn't work for me.

When I manually try the form, it works perfectly. It's only when called by Laravel's test infrastructure that I get the 419 error.

How can I make this simple test work?

like image 733
Rsevero Avatar asked Oct 27 '25 18:10

Rsevero


2 Answers

Try artisan cache:clear or artisan config:clear

I finally did this:

I renamed /bootstrap/cache/config.php to /bootstrap/cache/config.hidden.php

Then it worked for me.

Also consider this: https://medium.com/@fatboyxpc/laravel-testing-woes-token-mismatch-d9c00fbef263

like image 167
Magmatic Avatar answered Oct 29 '25 09:10

Magmatic


Despite Laravel's 8 documentation stating otherwise, it seems that the developer need to manually disable Middleware execution on the tests.

In my case, just including use WithoutMiddleware; in my test solved the failing post issue:

...

class SubmitLinksTest extends TestCase
{
    use RefreshDatabase;
    use WithoutMiddleware;

    /** @test */
    public function test_guest_can_submit_a_new_link()

...

The other, better but more cumbersome solution, is to actually get the token through a previous get call to the form page. It can go like this:

...

    /** @test */
    public function test_guest_can_submit_a_new_link()
    {
      $response = $this->get('/submit');

      $token = session('_token');

      $response = $this->post('/submit', [
        'title' => 'Example Title',
        'url' => 'http://example.com',
        'description' => 'Example description.',
        '_token' => $token,
      ]);

      $this->assertDatabaseHas('links', [
        'title' => 'Example Title'
      ]);

      $response
        ->assertStatus(302)
        ->assertHeader('Location', url('/'));

      $this
        ->get('/')
        ->assertSee('Example Title');
    }

...

It's definitely not pretty but works.

like image 23
Rsevero Avatar answered Oct 29 '25 08:10

Rsevero