laravel / dusk

Laravel Dusk provides simple end-to-end testing and browser automation.
https://laravel.com/docs/dusk
MIT License
1.88k stars 323 forks source link

Problems with using the loginAs #408

Closed naneri closed 6 years ago

naneri commented 7 years ago

Environment: Homestead Laravel version: 5.5 Dusk version: 2.0

I have a problem that when running Laravel Dusk I cant use the loginAs method to log in as a user. When I do authentication using

->visit('/login')
->type('email', $user->email)
->type('password', 'password')
->press('Login')

it logs in the user correctly. But when I use ->loginAs($firstUser) that does not work.

I have checked that dusk goes to internal Dusk url when triggering loginAs

$this->visit(rtrim('/_dusk/login/'.$userId.'/'.$guard, '/'));

And that maps to a controller method

    Route::get('/_dusk/login/{userId}/{guard?}', [
        'middleware' => 'web',
        'uses' => 'Laravel\Dusk\Http\Controllers\UserController@login',
    ]);

but method login is never actually run. How can I solve that?

unglud commented 7 years ago

Do you see this route in your route list? php artisan route:list Did you tried go to this address in your browser /_dusk/login/email/? Does it work? Can you put breakpoint to Route::get('/_dusk/login/{userId}/{guard?}'.... and go and see what is going on?

naneri commented 7 years ago

@unglud I need to test it on Monday, cause the behavior is different on my machines. On laptop it works correctly.

nbyloff commented 6 years ago

I am having the same issue, and it started in the last couple weeks. These tests were running fine a few weeks ago, and all of a sudden $first->loginAs($user) stopped working.

My issue seems to stem from DatabaseMigrations stopped working. Tables not generating. Saw a note not to use :memory: with Dusk, so I tried it with a sqlite file, still not working.

<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
         backupStaticAttributes="false"
         bootstrap="vendor/autoload.php"
         colors="true"
         convertErrorsToExceptions="true"
         convertNoticesToExceptions="true"
         convertWarningsToExceptions="true"
         processIsolation="false"
         stopOnFailure="false">
    <testsuites>
        <testsuite name="Browser Test Suite">
            <directory suffix="Test.php">./tests/Browser</directory>
        </testsuite>
    </testsuites>
    <filter>
        <whitelist processUncoveredFilesFromWhitelist="true">
            <directory suffix=".php">./app</directory>
        </whitelist>
    </filter>
    <php>
        <env name="APP_ENV" value="testing" force="true" />
        <env name="CACHE_DRIVER" value="array" force="true" />
        <env name="SESSION_DRIVER" value="array" force="true" />
        <env name="QUEUE_DRIVER" value="sync" force="true" />
        <env name="DB_CONNECTION" value="sqlite" force="true" />
        <env name="MONGO_CONNECTION" value="mongodb" force="true" />
        <env name="MONGO_DATABASE" value="app_testing" force="true" />
    </php>
</phpunit>

database.php

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

I feel like this stems from using two DBs in my setup, but not sure why. It is saying:

Caused by
InvalidArgumentException: Database (main_db) does not exist.

main_db is what is configured in my .env file, but I am forcing a different connection in phpunit.xml, so not sure how it's still picking up that DB name.

nbyloff commented 6 years ago

Yup, I'm one of those guys who finds their answer as soon as the question is posted online. Again, it seems my issue stemmed from having two different DBs in the same project. I solved my issue (at least on the first test) by updating tests/CreatesApplication.php. I will report back if I find any other issues.

<?php

namespace Tests;

use Illuminate\Contracts\Console\Kernel;

trait CreatesApplication
{
    /**
     * Creates the application.
     *
     * @return \Illuminate\Foundation\Application
     */
    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', database_path('database.sqlite'));

      return $app;
    }
}
simonhunt commented 6 years ago

I've run into a problem similar to this tonight - loginAs not working at all whilst using sqlite (not an in memory one though, just a normal one).

I read you last post and decided to just try it with an alternative mysql database and it worked.

I don't understand this!

staudenmeir commented 6 years ago

Does nbyloff's workaround fix your SQLite problem?

WalrusSoup commented 6 years ago

I'm having the same issue. Seeding works, and from inside the test I can see that the database is created, and the user is created. However, during the actual test execution the table doesn't actually exist.

At the top of login (vendor/laravel/dusk/src/Http/Controllers/UserController.php) I put the following:

var_dump(DB::table('users')->exists());

Then I made another test to just go directly to the dusk url ('/_dusk/login/1') and take a screenshot. Sure enough - it's not there (file exists, but no tables exist inside of it. It's like it has no idea the sqlite database was prepped).

I am running inside docker containers, so maybe I'll check if that is part of the issue tomorrow.

Update

So I ended up dumping some information into the UserController from dusk to even see if the SQLITE3 extension was functional and it threw up an exception. I have no idea why, so i rebuilt my php-fpm container, relaunched the others, and it's fine now. No idea whats up with that, compared to yesterdays behavior. I guess it gracefully let itself build despite failing to get the sqlite extension? makes no sense.

laclance commented 6 years ago

I have had the same problem for months now, user exits in db, dusk UserController@login gets runs fine but user just does not get logged in.

laclance commented 6 years ago

Seems to have to do with the fact that I am using cartalyst/sentinel for user authentication considering dusk uses laravel's auth.

UPDATE

Dusk's UserController always uses database set in .env and not .env.dusk.local but test cases do, using mysql.

This is what i have tried:

phpunit.xml

      <env name="DB_CONNECTION" value="mysql_testing" force="true"/>
      <env name="DB_DATABASE" value="fastlms_testing" force="true"/>

createApplication()

    $app->loadEnvironmentFrom('.env.dusk.local');

    $app['config']->set('database.default','mysql_testing');
    $app['config']->set('database.connections.mysql_testing.database', 'fastlms_testing');

UPDATE 2

Managed to use my testing db by overriding route to use my own controller with \Sentinel::login($user), which works, but when a try $browser->visit any page I still get redirected to login.

driesvints commented 6 years ago

Closing this issue because it's already solved, old or not relevant anymore. Feel free to reply if you're still experiencing this issue.

RicardoRamirezR commented 5 years ago

@driesvints I just install Dusk 5.5.5 in an old laravelphp app updated to 6.0.3. loginAs does not log in the given user.

jorgenb commented 5 years ago

Even though I have a .env.dusk.local with a seperate db it is fething the user from the db defined in my main .env file.

RicardoRamirezR commented 5 years ago

Hi @driesvints, is there any config expected for dusk?

The first one works as it should be:

    $browser
        ->visit('/login')
        ->type('email', $user->email)
        ->type('password', 'password')
        ->press('Login')
        ->assertAuthenticatedAs($user)

With this one:

    $browser
        ->loginAs($user)
        ->assertAuthenticatedAs($user)

I got:

There was 1 failure:

1) Tests\Browser\CreateOwnerTest::a_owner_is_created
The currently authenticated user is not who was expected.
Failed asserting that null is identical to Array &0 (
    'id' => 1
    'className' => 'App\User'
).
driesvints commented 5 years ago

@RicardoRamirezR I'll need a little more info in order to reproduce that. Can you maybe first try a support channel? And if that fails please open up a new issue and provide a repo that reproduces the problem.

interludic commented 5 years ago

Randomly (maybe when errors in test syntax) i get a screenshot of the login screen (unauthenticated), running the same test again after some time or removing some assertions works.

interludic commented 5 years ago

Randomly (maybe when errors in test syntax) i get a screenshot of the login screen (unauthenticated), running the same test again after some time or removing some assertions works.

may have something to do with my misconfigured error handler, (rollbar) connects to the internet..

Siddharth-Ashri commented 4 years ago

One thing I tried was to remove the port number from my env('APP_URL'). That apparently fixed it for me. Using Laravel 5.5 with dusk 2.0 on MacOS Catalina.

lucasroman commented 4 years ago

I remembered that my test database always is empty before run tests, so Dusk have not nobody for login. I created a new user before to do loginAs.

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

        $this->browse(function (Browser $browser) {
            $browser->visit('/login')
                    ->assertSee('Forgot Your Password?')
                    ->loginAs(User::find(1))
                    ->visit('/home')
                    ->assertSee('Dashboard');
    });

That worked for me.

Flashwade1990 commented 3 years ago

For me the issue was in an incorrectly specified sqlite file path. Needed to specify the full file path in "env.dusk.local":

DB_DATABASE=/home/vagrant/code/projectName/database/testing.sqlite

thiagorb commented 3 years ago

For me the issue was with SESSION_DOMAIN. I'm running dusk in docker containers, and selenium and php are running in separate containers. I'm starting the php test server with APP_URL=http://php:8000 php artisan serve, so I had to set SESSION_DOMAIN=php.

fidan-mkdir commented 1 year ago

I have the same issue, but SESSION_DOMAIN is not helping. I'm immediately returned to login page after using loginAs()

JeffreyKrist commented 11 months ago

@naneri @fidan-mkdir In our tests, when using Google Chrome to access the login route, we encounter an issue where the process does not progress beyond this point. The tests stall and do not advance to subsequent steps. We've found a workaround that seems to resolve this - it's unclear whether the solution is due to the HTTP code or simply because the response is not empty. But that can be validated within a minute. laravel-dusk-src-http-controllers-usercontroller-php.patch

fidan-mkdir commented 11 months ago

Will give that a try, thanks

bradleybernard commented 11 months ago

TLDR: Add APP_ENV=dusk to your .env.dusk.local or .env.dusk.{environment} file since the DuskServiceProvider only registers authentication/loginAs routes if the APP_ENV != production. The default APP_ENV if not defined is production. See code link: https://github.com/laravel/dusk/blob/2eaa14a67ef9931fa13dab175f00a6bd7aad8236/src/DuskServiceProvider.php#L17

You can probably set this through phpunit.dusk.xml as well, but if you don't have APP_ENV set, you'll get a 404 on those dusk routes:


How I found out: I realized while running my tests in Laravel Sail, the Dusk runner will swap around your .env files. In that deep dive, I enabled video mode for my tests:

sail dusk --browse

And added a pause in my tests:

class CoreSanityCheckPagesTest extends DuskTestCase
{
    public function testExpensesPage(): void
    {
        $this->browse(function (Browser $browser): void {
            $browser->pause(10_000);
            $browser->loginAs($this->user);
            $browser->pause(10_000);

            $browser->visit(new ExpensesPage())->createNewExpense($this->user);
        });
    }

And visited the video URL: http://192.168.214.5:4444/ui#/sessions and refreshed that screen when I ran the sail dusk --browse command.

The session will pop up, there will be a video icon, click on that, and you can enter the password: secret and then view. what's going on in your tests. I was getting a 404 on the login route: laravel.test/_dusk/login/1 was returning a 404. Dove into source code to understand why those routes weren't being registered and figured it was the APP_ENV value.

Hope this helps!

bradleybernard commented 11 months ago

One last addition here: I added a disable flag to the Chrome options for Selenium I found online, which helped! --disable-dev-shm-usage

in DuskTestCase.php:

/**
     * Create the RemoteWebDriver instance.
     */
    protected function driver(): RemoteWebDriver
    {
        $options = (new ChromeOptions())->addArguments(collect([
            $this->shouldStartMaximized() ? '--start-maximized' : '--window-size=1920,1080',
            '--disable-dev-shm-usage',
        ])->unless($this->hasHeadlessDisabled(), function (Collection $items) {
            return $items->merge([
                '--disable-gpu',
                '--headless=new',
            ]);
        })->all());

        ...