Monday, May 2, 2016

Laravel 5 - "Session store not set on request" running functional tests

tl;dr - If your Laravel functional tests fail with "RuntimeException: Session store not set on request.", don't use the withoutMiddleware trait in your tests and selectively disable middleware components you don't need when executing tests by using APP_ENV in your middleware.

In a Laravel 5.2 project I had some initial problems setting up the functional tests. The test code was really simple as shown below:


/**
 * Just a simple functional test case
 *
 * @test
 */
public function indexTest()
{
    $this->visit('/')
        ->see('some text');
}

The test did not execute successfully and resulted in a NotFoundHttpException with the error message "A request to [http://localhost/de] failed. Received status code [404].". Root cause for this problem was my language middleware, which redirected the user to a predefined default language by adding the de/ URL prefix if a language prefix was not set.

My first approach was to disable all middleware components by using the withoutMiddleware trait in my tests. Again, the test did not execute successfully and thew the RuntimeException "Session store not set on request.". Since I used the withoutMiddleware trait, I also disabled middleware components which were required by my application (e.g. VerifyCsrfToken, Authenticate).

After some research on the internet, I found this helpful answer and modified my languageMiddleware, so it will be skipped when running tests as shown below:


/**
 * Handle an incoming request.
 *
 * @param  \Illuminate\Http\Request $request
 * @param  \Closure $next
 * @return mixed
 */
public function handle($request, Closure $next)
{
    if (env('APP_ENV') === 'testing') {
        return $next($request);
    }

    // Redirecting to default language if not set. 
    // Code skipped to keep the example simple. 

    return $next($request);
}

This technique can be applied to any middleware component, which you want to disable when running functional tests.