How to do unit testing with Laravel Localization?
Asked Answered
D

2

7

I'm using mcamara/laravel-localization package and I can't figure out how to make it work with my unit tests. Both of the following fail with red:

// 1. This one results in "Redirecting to http://myapp.dev/en"
$this->get('/')->assertSee('My App Homepage');

// 2. This one results in 404
$this->get('/en')->assertSee('My App Homepage');

In the browser, http://myapp.dev returns 302 with a redirect to http://myapp.dev/en, fair enough. However, http://myapp.dev/en returns 200. So both cases work 100% fine on the front-end, but not with unit tests.

I do have some customization however, which once again, works like charm in the browser.

// in web.php
Route::group([
    'prefix' => app('PREFIX'), // instead of LaravelLocalization::setLocale()
    'middleware' => ['localeSessionRedirect', 'localizationRedirect']],
    function() {
        Route::get('/', function() {
            return view('home');
        });
    }
]);

// in AppServiceProvider.php
public function boot()
{
    // This, unlike LaravelLocalization::setLocale(), will determine the 
    // language based on URL, rather than cookie, session or other
    $prefix = request()->segment(1); // expects 'en' or 'fr'
    $this->app->singleton('PREFIX', function($app) use ($prefix) {
        return in_array($prefix, ['en', 'fr']) ? $prefix : null;
    });
}

Hopefully this code makes sense to you. Thanks!

UPDATE

I addressed this problem with the package in a GitHub issue #435.

UPDATE 2

Insofar as I could figure it out, it seems that you can safely test your localized routes as long as you specify the locale in the base URL in your phpunit XML file:

<env name="APP_URL" value="http://myapp.dev/en"/>

However, this would work for your localized GET endpoints (which start with a locale prefix, e.g. 'en'), but not for non-localized POST, PUT, etc. (which don't have any prefix). Hence, you can't really test both kinds of endpoints at the same time, unless you use Dusk (which I don't, as it's an overkill and much slower, almost the same as doing it manually).

Daily answered 16/4, 2017 at 17:48 Comment(0)
D
1

I found that if you dump the request URL during testing, it is always http://myapp.dev no matter what endpoint you're accessing. So both LaravelLocalization::setLocale() and my custom app('PREFIX') return null, meaning that not a single route is ever localized during testing. You are screwed either way because if you try to access a route without a locale prefix, you get a 302, but if you do specify the locale, the framework can't find a definition for that route.

One article helped me discover a temporary solution: you need to hideDefaultLocaleInURL to true in laravellocalization.php. This way, the routes matching your default locale won't have any prefix, so you can test them as if they were non-localized.

However, the problem still persists, because how are you supposed to test your application when it is localized? (For ex., when you have language-specific routes that need to be tested). This poses the question whether this package is even compatible with unit testing per se...

Daily answered 18/4, 2017 at 23:41 Comment(2)
I have the same issue. If I set hideDefaultLocaleInURL to true, I have some more errors in my unittests. My solution was, to set useAcceptLanguageHeader to false and hideDefaultLocaleInURL to true.Gestate
@Gestate if you want to set useAcceptLanguageHeader to true, you just have to set the session like this $response = $this->withSession(['locale' => 'en']) ->get('/'); then it will work (ofc you still need hideDefaultLocaleInURL.Rhabdomancy
D
1

The problem

Using mcamara / laravel-localization when I test a show route I get a 404 error.

For instance, testing this route returns me a 404:

Route::get('/posts/{post:slug}', [PostController::class, 'show'])->name('posts.show');

The test:

/** @test */
public function itShouldDisplayThePostsShowViewToGuestUser()
{
    $response = $this->get("/posts/{$this->post1->slug}");

    $response->assertStatus(200);
    $response->assertViewIs('posts.show');
}

The solution

I solved hiding the locale from the URL while testing.

Creating this env variable at the end of phpunit.xml.

    ...
    <env name="LOCALIZATION_HIDE_DEFAULT_LOCALE" value="true"/>
    </php>
</phpunit>

And in config/laravellocalization.php setting hideDefaultLocaleInURL like this:

'hideDefaultLocaleInURL' => env('LOCALIZATION_HIDE_DEFAULT_LOCALE', false)

This solution was inspired by this this post:
https://github.com/mcamara/laravel-localization/issues/161#issuecomment-381367191

Denney answered 13/1, 2022 at 15:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.