dusk: Dusk env file not being loaded correctly

I have the following two files: .env and .env.dusk.local

.env:

APP_ENV="local"
APP_KEY=base64:358E4UyIq+Zbg+H+Pm03dYA2B/vz3ViPJ+U48ikg6qE=
APP_DEBUG=true
APP_LOG_LEVEL="debug"
APP_URL="http://localhost"

DB_CONNECTION="mysql"
DB_HOST="127.0.0.1"
DB_DATABASE="homestead"
DB_USERNAME="homestead"
DB_PASSWORD="secret"

CACHE_DRIVER="redis"
SESSION_DRIVER="redis"
QUEUE_DRIVER="sync"

.env.dusk.local

APP_ENV="local"
APP_KEY=base64:358E4UyIq+Zbg+H+Pm03dYA2B/vz3ViPJ+U48ikg6qE=
APP_DEBUG=true
APP_LOG_LEVEL="debug"
APP_URL="http://localhost"

DB_CONNECTION="sqlite"

CACHE_DRIVER="file"
SESSION_DRIVER="file"
QUEUE_DRIVER="sync"

But when I run php artisan dusk I get errors about the sqlite database not existing. Illuminate\Database\QueryException: Database (homestead) does not exist. (SQL: select * from sqlite_master where type = 'table' and name = migrations)

So, I suspect that the env files are not correctly being copied and swapped into place. It seems they are simple being merged together, which is causing issues for tests not working.

I am currently using this on Manjaro Linux, and have not tried it on any other OS.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 22 (8 by maintainers)

Most upvoted comments

@francoislevesque not necessarily. Dusk will backup your .env and move .env.dusk.{APP_ENV} to .env so the browser can match the same environment as yours. This, however, fails to happen when using php artisan serve because serve will cache your env variables the moment of starting to serve. This can be solved by running php artisan serve --env=dusk.local (switch local for anything you use locally). But all of you are suffering from different kinds of problem somewhat related to the same thing. If everyone were using serve, it would make sense to implement a dusk:serve, perhaps.

This is still an issue

I opted for making another database array entry in config/database.php

'dusk-sqlite' => [
    'driver' => 'sqlite',
    'database' => database_path('database.sqlite'), // env() in sqlite option was using .env value
    'prefix' => '',
],

and used this in my .env.dusk.local

DB_CONNECTION=dusk-sqlite

@taylorotwell Looks like env() is being used from .env file before dusk file is loaded. Is the environment loaded via .env before .env.dusk.local is copied to .env?

I came by a very similar problem. I had DB_DATABASE as homestead in .env.dusk.local and when any of my tests accessed a route that was querying the database, I would get:

Database (homestead) does not exist.

I finally solved by changing:

    'sqlite' => [
        'driver' => 'sqlite',
        'database' => env('DB_DATABASE', database_path('database.sqlite')),
        'prefix' => '',
    ],

To this:

    'sqlite' => [
        'driver' => 'sqlite',
        'database' => database_path(env('DB_DATABASE', 'database.sqlite')),
        'prefix' => '',
    ],

It’s all explained in this answer.

Fixed this issue today by adding into the phpunit.dusk.xml file

  </testsuites>

  <php>
    <env name="APP_ENV" value="testing" force="true"/>
    <env name="CACHE_DRIVER" value="redis" force="true"/>
    <env name="SESSION_DRIVER" value="redis" force="true"/>
    <env name="QUEUE_DRIVER" value="redis" force="true"/>
    <env name="DB_CONNECTION" value="mysql" force="true"/>
    <env name="DB_DATABASE" value="testing" force="true"/>
    <env name="TELESCOPE_ENABLED" value="false"/>
  </php>

</phpunit>

UPDATE I also had to change my .env.dusk.local to .env.dusk.testing

  • php artisan cache:clear --env=testing
  • php artisan cache:clear

Having a similar/related issue

I’m using Homestead on a Windows machine. When running php artisan dusk, the .env’s content is replaced by .env.dusk.local’s content. However, the tests still use the “old” .env.

My .env

APP_NAME=Laravel
APP_ENV=local
APP_KEY=base64:6R5VxSoy2djjIQ0ah6BUCgBmrLNpdOcr37LemBag8wg=
APP_URL=http://laravel-boilerplate.dev

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret

My .env.dusk.local

APP_NAME=Laravel_test
APP_ENV=local
APP_KEY=base64:6R5VxSoy2djjIQ0ah6BUCgBmrLNpdOcr37LemBag8wg=
APP_URL=http://laravel-boilerplate.dev

DB_CONNECTION=testing

config/database.php

'testing' => [
            'driver' => 'mysql',
            'host' => '127.0.0.1',
            'port' => '3306',
            'database' => 'testing',
            'username' => 'homestead',
            'password' => 'secret',
            'unix_socket' => '',
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'strict' => true,
            'engine' => null,
        ],

While running the tests

LoginTest.php

    use DatabaseMigrations;

    private $user;

    public function test_login_interact()
    {
        var_dump(env('APP_NAME'));
        $this->user = factory(User::class)->create([
            'password' => bcrypt('secret')
        ]);

        $this->browse(function (Browser $browser) {
            $browser->visit('/login')
                    ->waitForText('Remember Me')
                    ->type('email', $this->user->email)
                    ->type('password', 'secret')
                    ->click('input[type="submit"]')
                    ->waitFor('.panels')
                    ->assertPathIs('/home');
        });
    }

The var_dump of APP_ENV is Laravel_test, which is fine.

However, the DatabaseMigrations trait is doing its migrations on the homestead database instead of testing.

Also, in my blade file, I’m doing the following: <h1>{{ config('app.name') }}</h1>

The output on the dusk screenshot is “Laravel” instead of “Laravel_test”. capture

Partial Solution

Adding this line in tests/Browser/CreatesApplication.php to force the database change worked for me:

public function createApplication()
    {
        $app = require __DIR__.'/../bootstrap/app.php';

        $app->make(Kernel::class)->bootstrap();
        $app['config']->set('database.default','testing');

        return $app;
    }

However, it seems chrome is still using the old database connection since I still see “Laravel” instead of “Laravel_test” in the <h1>.

As @bbashy said, it looks like env() is being used from .env file before dusk file is loaded.

Edit It worked perfectly on anoter machine (Windows 10, similar specs, vagrant 1.9.2, Homestead 5.2.3). Still trying to figure out what’s wrong on the first machine.

@mustafaaloko I already did and got #249 and then I tried #250 to make it possible to easily extend, but also no luck because of the construct actions. Furthermore, I tried https://github.com/laravel/framework/pull/18973 to make #250 look better, but also no. Now I just gave up.

@bbashy I am not sure about your last assumption. Or maybe we’re talking about different issues.

But anyway, I tried running Dusk today while overriding some of the env values and as a result I don’t even have APP_KEY from main .env file loaded in tests and my APP_DEBUG is assumed to be false while .env explicitly states it to be true. 😄

Indeed, it seems like Dusk replaces the contents of .env file in it’s entirety rather than performing merge and the working workflow is as follows:

cp .env .env.dusk.local
sed -i "s/DB_CONNECTION=.*/DB_CONNECTION=sqlite/" .env.dusk.local
sed -i "s#DB_DATABASE=.*#DB_DATABASE=/opt/project/database/database.sqlite#" .env.dusk.local

But this all sounds very confusing to me after overriding env variables in phpunit.xml. I think it should be clearly stated in the docs how exactly Dusk processes .env file.

I had a similar issue using Homestead, which was permissions related. Dusk would dump the contents of .env.dusk.local into my .env but fail to perform the backup/replace, leaving my .env over-written with test settings.

In your case, I don’t think it can write into your .env period, which means it’ll just be using your local settings.

I believe the issue is in the code below, as well as restoreEnvironment(). For example, given you have a .env.dusk.local (returned by $this->duskFile()), the code assumes this gets written into .env, and moves on with the tests:

protected function backupEnvironment()
    {
        // this can fail due to permissions
        copy(base_path('.env'), base_path('.env.backup'));
       // this can also fail. In my case, since the file exists, the write did succeed
        copy(base_path($this->duskFile()), base_path('.env'));
    }

// at this point restoreEnvironment() will obviously fail since no backup was made

I would personally prefer this code to throw an exception if the backup/replace is not working.

That might be causing your issue - to verify, run a test php script from the command line which copies files in the app root, writes into an existing file, and performs an unlink. My fix was a vagrant reload, but it will depend on your setup.