Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

bwrigley's avatar

Feature test always gets 'session expired' message

Just starting out with feature testing so starting with basic login test that looks like this

    //use custom traits to create a user and activate with Sentinel
        $email = $this->safeEmail('example.com');
        $this->createAuthenticatedUser($email, "secret");
    

        $credentials = [
            'email' => $email,
            'password' => 'secret'
        ];

        $this->post('login', $credentials)
                ->assertSee('The logged in page');

The assertion always fails showing the session expired page, which I presume means I'm not using a session.

I can't use actingAs() or 'withSession()` as I'm using Sentinel and not Laravel's auth.

Any tips please?

0 likes
13 replies
shez1983's avatar

laravel has a test to check that its inbuilt login functionality works - if you go to github -> tests and see how it does it.

I know why you are getting this because normally to post you need a CSRF token which you dont have.. actually i have looked at my test

$user = factory(User::class)
            ->states('client')
            ->create();

        $this->post('/login', ['email' => $user->email, 'password' => 'secret'])
            ->assertLocation('/clients/dashboard');

and i dont have anything about CSRF even in the verifyCSRF middleware :/

bwrigley's avatar

@shez1983 I read somewhere that the feature tests ignore the need for the CSRF token?

shez1983's avatar

that makes sense but then i dont see why YOU get a session expired... what is your phpunit.xml look like? & for fun if you add in login to verifyCSRF middleware does it work?

bwrigley's avatar

@shez1983

I haven't touched my phpunit.xml so it looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
         backupStaticAttributes="false"
         bootstrap="vendor/autoload.php"
         colors="true"
         convertErrorsToExceptions="true"
         convertNoticesToExceptions="true"
         convertWarningsToExceptions="true"
         processIsolation="false"
         stopOnFailure="false">
    <testsuites>
        <testsuite name="Feature">
            <directory suffix="Test.php">./tests/Feature</directory>
        </testsuite>

        <testsuite name="Unit">
            <directory suffix="Test.php">./tests/Unit</directory>
        </testsuite>
    </testsuites>
    <filter>
        <whitelist processUncoveredFilesFromWhitelist="true">
            <directory suffix=".php">./app</directory>
        </whitelist>
    </filter>
    <php>
        <env name="APP_ENV" value="testing"/>
        <env name="CACHE_DRIVER" value="array"/>
        <env name="SESSION_DRIVER" value="array"/>
        <env name="QUEUE_DRIVER" value="sync"/>
    </php>
</phpunit>

so I've tried adding a token to my post. I think this is right?

        $credentials = [
            'email' => $email,
            'password' => 'secret',
            '_token' => csrf_token()
        ];


        $this->post('login', $credentials)
            ->assertSee('The logged in page');

Still get session expired :(

shez1983's avatar

can u add login to middleware and see if that helps? ideally you shouldnt but i just want to see where the error is...

bwrigley's avatar

sorry I'm being dumb. Can you explain what you mean a bit more?

wrap the login route in some middleware which will check something?

Really appreciate your ongoing help with this!

realrandyallen's avatar

@BWRIGLEY - Does logging in through the UI work fine?

Also, what does createAuthenticatedUser do? It may be that your password isn't encrypted there but I feel like that would result in a different error

bwrigley's avatar

@realrandyallen yes UI is fine and all my dusk testing is ok.

createAuthenticatedUser should actually be called createActivatedUser (I will rename). All it does is calls the User factory (with encrypted password) and calls Sentinel's Activation methods so the user can log in. I use this method all over my dusk tests with no issues.

shez1983's avatar
shez1983
Best Answer
Level 23

what i meant was open up your verifyCSRF middleware and theres an except property.. add in '/login' and then see what happens..

1 like
bwrigley's avatar

@shez1983

Sorry, or course that's what you meant! Not sleeping enough! And you, are a star!

And so what I went on to realise is that I probably was logging in but because I had no session I was being told it had expired. What I needed wasSession::start() and now all works fine without bypassing CSRF.

Thank you so much!

p.s. I noticed that these feature tests don't actually hit the webserver do they? I was watching the log file which is why I assumed it wasn't even hitting the login page.

shez1983's avatar

i have never needed to do Session::start().. which makes me think you might need to add the session middleware in the web array in app/http/kernal

 protected $middlewareGroups = [
        'web' => [
            EncryptCookies::class,
            AddQueuedCookiesToResponse::class,
            StartSession::class,  //// <<< this one i think 
            // \Illuminate\Session\Middleware\AuthenticateSession::class,
            ShareErrorsFromSession::class,
            VerifyCsrfToken::class,
            SubstituteBindings::class,
            SetDefaultUserTypeForUrls::class,
            SetLocale::class,
            CheckUserHasOnBoarded::class,
        ],

        'api' => [
            'throttle:60,1',
            'bindings',
        ],
    ];

but i see that it is already there by default - so i am not really sure why you need to add that but it does look like your session isnt starting,.

bwrigley's avatar

@shez1983 I have just checked and I have it too

    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            // \Illuminate\Session\Middleware\AuthenticateSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
        'api' => [
            'throttle:60,1',
            'bindings',
        ],
    ];

not sure what that really means if that's not working.

Is it possible that this is something that actingAs() or withSession() would run in the background?

bwrigley's avatar

Just a final update on this and the reason I was having to instantiate the Session.

I am using Homestead which my default in it's config file has

variables:
    - key:  APP_ENV
      value: local

So even though my .env file was:

APP_NAME=Laravel
APP_ENV=testing

and my phpunit.xml had

    <php>
        <env name="APP_ENV" value="testing"/>
        <env name="CACHE_DRIVER" value="array"/>
        <env name="SESSION_DRIVER" value="array"/>
        <env name="QUEUE_DRIVER" value="sync"/>
    </php>

$~ php artisan env

always showed as local and it needs to be testing

Changing the homestead.yaml file and running vagrant provision fixed the issue.

Thanks again!

1 like

Please or to participate in this conversation.