Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DatabaseMigrations trait doesn't work when using an in-memory SQLite database #73

Closed
mstnorris opened this issue Jan 29, 2017 · 14 comments

Comments

@mstnorris
Copy link

mstnorris commented Jan 29, 2017

I would like to know how tet up Laravel 5.4 with Dusk using phpunit.xml, .env.dusk.local, and an sqlite in-memory database as what I have so far doesn't work. It does work with a MySQL database though.

I can run the tests, but I get an error: "No such table: users"

  • I have created a new Laravel 5.4 project
  • Installed Dusk and added the Service Provider
  • I'm using the test from the laravel docs that tests authentication. It already includes the DatabaseMigrations trait
  • I can run the tests, and the first one works (navigating to the /login route) but the second where it tried to log in fails.

I have added a .env.dusk.local which contains

APP_ENV=local
APP_KEY=RANDOM_STRING_HERE
APP_DEBUG=true
APP_LOG_LEVEL=debug
APP_URL=http://laravel54.dev

DB_CONNECTION=sqlite
DB_DATABASE=':memory:' // I've also tried just :memory: and also adding these details to the config/database.php file but to no avail

This is the test I am running (directly from the docs)

<?php

namespace Tests\Browser;

use App\User;
use Tests\DuskTestCase;
use Laravel\Dusk\Chrome;
use Illuminate\Foundation\Testing\DatabaseMigrations;

class LoginTest extends DuskTestCase
{
    use DatabaseMigrations;

    public function test_login_page()
    {
        $user = factory(User::class)->create();

        $this->browse(function ($browser) use ($user) {
            $browser->visit('/login')
                ->type('email', $user->email)
                ->type('password', 'secret')
                ->press('Sign in')
                ->assertPathIs('/home');
        });
    }
}

Ref: Question on StackOverflow

Ref: Question on Laracasts

@MarceauKa
Copy link

Same here!

@mstnorris
Copy link
Author

mstnorris commented Jan 29, 2017

Taylor replied "I don't think that's gonna work. Dusk runs in a separate process", but I don't see how this makes a difference.

@MarceauKa
Copy link

Solved by editing tests/CreatesApplication.php:

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

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

    return $app;
}

@mstnorris
Copy link
Author

@MarceauKa this does not work for me, the sample LoginTest fails with a message saying the credentials do not match. Does this mean that the database was migrated?

@splatEric
Copy link
Contributor

You won't be able to use an in memory db because, as Taylor has pointed out, the tests and the web server are running under separate processes. You could use a common mysql db connection or a single sqlite file, and then do a migrate/refresh option (although this does rely on all your migrations supporting down migration steps).

The approach I have taken (which is adapted from an approach I was using pre-dusk) is to create an empty file for an sqlite db that both my web server and my tests point to. The tests create this file as part of the setup process, and migrate it, so you have a clean db at the start of each test, Much like you get with an in memory sqlite db.

If you want to see an example, take a look at my medium post that has the Trait I wrote for this:

https://medium.com/@splatEric/working-with-laravel-dusk-54d67cc0241b#.xqalwcjxi

@mstnorris
Copy link
Author

Thanks, I'll check it out.

@iveoles
Copy link

iveoles commented Jan 31, 2017

Is this the same for the DatabaseTransactions trait?

If I use it I run into errors with the credentials not being correct when logging in. If I disable it the test works, but then fails the next time because the user is still in the database.

Do we need to write Dusk tests to clean up after themselves? This is on a MySQL database that's used for local development.

@splatEric
Copy link
Contributor

splatEric commented Jan 31, 2017 via email

@brandonferens
Copy link

@MarceauKa that is what worked for me. I just used $app['config']->set('database.default','testing');. The thing I noticed is that the ChromeDriver was using the proper sqlite file, but the actual tests were defaulting to mysql. This forced the Dusk tests to use the proper db.

On another note, though, I use https://github.com/SRLabs/laravel-testing-utilities for updating the testing database. It really simplifies the testing setup.

@splatEric
Copy link
Contributor

A bit more on this, since I just spent 40 minutes wrestling with getting my tests working again. I'm not sure entirely what changed, but I was again having an issue with the consistency of the db connection used by the testing process versus that of the web server process.

There has been an update to dusk to 1.0.4 that forces a reload of the environment in the testing process after the environment files are moved around, however the reload calls Dotenv()->overload(), which means that if any environment variables are not set in your dusk env file, they will default to whatever you had in your core .env file. This was causing a problem with the database filename I was using for sqlite.

TLDR; I set up an sqlite_testing connection in my database config, and pointed at that from the dusk .env file:

    'sqlite_testing' => [
            'driver' => 'sqlite',
            'database' => database_path('testing.sqlite'),
            'prefix' => '',
        ],

This seems to have resolved my connection consistency issues.

@mnabialek
Copy link
Contributor

@splatEric Yes, there was issue that Dusk was using the wrong file so it was not working in correct way. I've fixed it to reload environment after changing Dusk env into normal env so it's possible it's working fine now

@ryancwalsh
Copy link

@splatEric Thank you. #73 (comment) was super helpful. I looked at my database config array and saw that 'sqlite' was already set up that way, so all I needed to do was delete superfluous lines in my .env files.

@avrahamappel
Copy link
Contributor

I think the issue is setting the environment to local, because then the server uses the values in .env which also has the environment set to local. When I created an .env.dusk.testing file with the following values in it, everything worked fine. No need for a new php artisan serve.

APP_ENV=testing
...

DB_CONNECTION=sqlite

@rovshan-b
Copy link

rovshan-b commented Aug 13, 2018

Putting it here if someone has same problem and gets here using search engine.
Dusk accesses different database because you are starting server in another terminal for example using ./artisan serve. And when in Dusk you do $this->browse it sends request to your started server which in turn queries the database that it is configured to query (i.e. your local database). And later in your tests if you for example do $this->assertDatabaseHas Dusk this time uses the database it is configured to query (i.e. your test database). To solve this I use a shell script to run my tests. To use it first you need to put your Dusk config into file called .env.dusk. Remember to set listen port to something different than default, for example set it to 8001 (APP_URL=http://localhost:8001). And then create a file called (I do it on Linux) run_tests in the same directory as your Laravel app with following contents and make it runnable:

#!/bin/bash
nohup ./artisan serve --port=8001 --env=dusk > art_8001.hup &
./vendor/bin/phpunit
./artisan dusk --env=dusk
kill $(lsof -t -i:8001)
rm art_8001.hup

Now you can run it from terminal using ./run_tests. What it does is run artisan on port 8001 with an environment file .env.dusk so that it picks up configuration that you did for Dusk. After this it starts to run your phpunit and Dusk tests so that all queries go to same database. Hope this helps to someone who faces the same problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants