Halz's avatar
Level 1

Laravel5 - How to test middleware redirect ?

Hello everybody,

I have created a simple localization & routing system to allow my application to work with language subdomains.

Here's a brief description:

a class Localize is in charge of detecting the locale ( from the url, the cookies, the browser settings or the application settings) a class Router is in charge of translating routes a middleware Localization is in charge of redirecting the requests reaching the filtered routes without language subdomain.

Here's how my routes.php file looks like:

/**
 * Detects the current locale with the following order:
 *
 * - Parses the requested host to find a language subdomain ( de.mydomain.com => de )
 * - If previous step failed, checks if a cookie value exists for the key 'locale'
 * - If previous step failed, tries to find a locale in the browser settings
 * - If previous step failed, uses the fallback locale
 *
 * Set the application locale app()->setLocale( )
*/
Localize::detectLocale();

/**
 * Without the 'localize' middleware, the route can be reached with or without language subdomain
 */
Route::get('test', function() {
    return response('This route works without language subdomain');
});

/**
 * Routes filtered by the 'localize' middleware can only be reached witha language subdomain
 */
Route::group([ 'middleware' => [ 'localize' ]], function() {

    /**
     * Router::resolve( $routeName ) returns the translated route path
     * 
     * en.mydomain.com/welcome
     * fr.mydomain.com/bienvenue
     * 
     */ 
    Route::get(Router::resolve('welcome'), 'WelcomeController@index');

    Route::get('hello', 'WelcomeController@index');

});

And here is the Localization ( 'localize' ) middleware:

class Localization {

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {

        /**
         * The shouldRedirect() method compares the previously detected locale to the locale guessed from the requested URL
         * If they are different, then the request should be redirected
         */
        if (Localize::shouldRedirect()) {

            return new RedirectResponse(Router::getRedirectURL(), 302, [ 'Vary', 'Accept-Language' ]);

        }

        return $next($request);
    }

}

The system works as intended. However, I cannot find a way to properly test it. For example, the following test fails:

/**
 * It should not redirect if the locale is not missing
 *
 * @test
 */
public function itDoesNotRedirectIfLocaleIsNotMissing()
{
    $response = $this->call('GET', 'https://de.mydomain.dev/hello');

    $this->assertEquals('200', $response->getStatusCode());
}




There was 1 failure:

1) LocalizeTest::itDoesNotRedirectIfLocaleIsNotMissing
Failed asserting that 302 matches expected '200'.

/var/www/Refactoring/IndustryArena/tests/LocalizeTest.php:55

FAILURES!
Tests: 1, Assertions: 1, Failures: 1.

I have come to understand why but it isn't easy to explain. To summarize: $this->call('GET', 'https://de.mydomain.dev/hello') does not trigger the detectLocale( ) method. My guess is that the routes.php file isn't the right place to call detectLocale( ). To make my test work, this method should be triggered when a request is created in the application, and not when the application is bootstrapped.

But maybe I'm just testing this the wrong way. I think testing the routing must be a bit tricky.

Any help would be appreciated.

Thank you :)

0 likes
1 reply
lazyboywu's avatar

In My test file

public function testRedirectWithNotAuth() {
    $response = $this->call('GET', URL::to('/admin/'));

    $this->assertEquals('302', $response->getStatusCode());

    $this->assertEquals(URL::to('/auth/login'), $response->getTargetUrl());

    $response = $this->call('GET', $response->getTargetUrl());

    $this->assertEquals('200', $response->getStatusCode());
}

run my test file

root@homestead:~/www/projects/boxs# ./vendor/bin/phpunit --filter testRedirectWithNotAuth AdminControllerTest tests/Http/Controllers/Admin/AdminControllerTest.php
PHPUnit 4.7.2 by Sebastian Bergmann and contributors.

.

Time: 3.33 seconds, Memory: 13.25Mb

OK (1 test, 3 assertions)
root@homestead:~/www/projects/boxs# 
4 likes

Please or to participate in this conversation.