Laravel Dusk, how to destroy session data between tests

Viewed 10406

I am getting started using Laravel Dusk for browser testing, and have created a couple of tests to test my login form. I have the following code:

class LoginTest extends DuskTestCase
{

public function testLogin()
{
    $this->browse(function (Browser $browser) {
        $browser->visit('/admin')
            ->type('email', 'inigo@mydomain.co.uk')
            ->type('password', 'MyPass')
            ->press('Login')
            ->assertSee('Loading...');
    });
}

public function testLoginFailure(){
    $this->browse(function (Browser $browser){

        $browser->visit('/admin/logout'); // I have to add this to logout first, otherwise it's already logged in for this test!

        $browser->visit('/admin')
            ->type('email', 'someemail@afakedomain.com')
            ->type('password', 'somefakepasswordthatdoesntwork')
            ->press('Login')
            ->assertSee('These credentials do not match our records.');
    });
}

See the comment. The first function runs fine, but when it comes to the second function, I have to logout first, since the user is already logged in as a result of running the first function. This came as a surprise to me as I thought unit tests were completely independent, with session data being destroyed automatically.

Is there a better way of doing this- some Dusk method that I'm missing perhaps- than having to call $browser->visit('/admin/logout'); ?

Thanks

EDIT Thanks for the 2 answers so far, which both seem valid solutions. I've updated the second function to the following:

public function testLoginFailure(){
    $this->createBrowsersFor(function(Browser $browser){
        $browser->visit('/admin')
            ->type('email', 'someshit@afakedomain.com')
            ->type('password', 'somefakepasswordthatdoesntwork')
            ->press('Login')
            ->assertSee('These credentials do not match our records.');
    });
}

Which does the job. So

  1. I can safely assume that this second browser only exists for the duration of this single function, correct?
  2. What are the obvious advantages/disadvantages of creating a second browser instance rather than using the teardown method?
8 Answers

If you just want to logout your signed in user, after login test, simply use:

 $browser->visit('/login')
     ->loginAs(\App\User::find(1))
     ...
     some assertions
     ...
     ->logout();

If in case it helps some one else. You can use tearDown method to clear all cookies. Following is the example of doing so, you can add this method in DuskTestCase.php file

public function tearDown()
{
    parent::tearDown();

    $this->browse(function (Browser $browser) {
        $browser->driver->manage()->deleteAllCookies();
    });
}

I hope this will help.

I'm not sure if its the answer you are looking for, but you can create multiple browsers to perform a test that requires clean history/cookies/cache.

For example, if you have lots of tests where the user should be logged in and you don't want to log out for only one test that checks reset password form, then you can create an additional browser for this exact case and switch to the previous browser when moving to the next tests.

It might look the next way:

public function testfirstTest()
{
  $this->browse(function ($browser) {
    //some actions where you login etc
  });
}

public function testSecondTestWhereYouNeedToBeLoggedOut()
{
  $this->browse(function ($currentBrowser, $newBrowser) {
  //here the new browser will be created, at the same time your previous browser window won't be closed, but history/cookies/cache will be empty for the newly created browser window
    $newBrowser->visit('/admin')
    //do some actions
    $newBrowser->quit();//here you close this window
  });
}

public function testWhereYouShouldContinueWorkingWithUserLoggedIn()
{
  $this->browse(function ($browser) {
    $browser->doSomething()//here all actions will be performed in the initially opened browser with user logged in
  });
}

If you are interested in only logging out the current user you can achieve it by doing

     $this->browse(function($browser) {
        $browser->visit('/logout')
                ->waitForText('Sign Into Your Account');
    });

Note: Please change the text 'Sign Into Your Account' by the text displayed on your login page.

You can pair the setUp method, alongside Dusk's logout method on the Browser instance:

/**
 * Log the user out before each test.
 *
 * @return void
 */
protected function setUp(): void
{
    parent::setUp();

    $this->browse(
        fn (Browser $browser) => $browser->logout()
    );
}
Related