Codeception: Keep a logged in state Codeception: Keep a logged in state selenium selenium

Codeception: Keep a logged in state


I think that the accepted answer is a way of accomplish it, but not the best. Doing that you'll always have to reproduce all the steps to log in into the system, when you only need to share the user session. I think that grabbing the session cookie and pass it through the required user logged tests is better. To do that, you create a login function, get the cookie, and make your tests depends on the login test first:

<?phpuse \AcceptanceTester;class testingCest{    private $cookie = null;    public function _before(AcceptanceTester $I)    {    }    public function _after(AcceptanceTester $I)    {    }    // tests    public function login(AcceptanceTester $I)    {        $I->wantTo('entrar al sistema');        $I->amOnPage('/');        $I->seeInCurrentUrl('/admin/login');        $I->fillField('user','perry');        $I->fillField('pass','pass-perry');        $I->click('Login');        $I->see('You\'re logged!');        $this->cookie   = $I->grabCookie('your-session-cookie-name');    }    /**     * @depends login     */    public function listUsers(AcceptanceTester $I)    {        $I->setCookie( 'your-session-cookie-name', $this->cookie );        $I->amOnPage('/admin/users');        $I->seeInCurrentUrl('/admin/users/1');    }    /**     * @depends login     */    public function listRols(AcceptanceTester $I)    {        $I->setCookie( 'your-session-cookie-name', $this->cookie );        $I->amOnPage('/admin/rols');        $I->seeInCurrentUrl('/admin/rols/1');    }}

That way, if the login test fails, you won't get the cookie, and you won't pass the other tests.

I prefer this @depends annotation instead of the @before proposed in the other answer, because if you use @depends you'll ALWAYS execute the code in the test before, and the tests will be only executed after the login.

UPDATE

There exists another answer bellow, https://stackoverflow.com/a/41109855/1168804 that may also help you, as the framework for Codeception has evolved since the writing of this answer.


All earlier answers are old, now it's done directly in _before method which takes Actor class as argument.

<?phpnamespace Test\Api;use ApiTester;class TrainingCest{    public function _before(ApiTester $I)    {        $I->amLoggedInAs('kgkg');    }    public function _after(ApiTester $I)    {    }    // tests    public function testForLoggedInUser(ApiTester $I)    {    }    public function anotherTestForLoggedInUser(ApiTester $I)    {    }}

And if you want to log in just once for all CEST files, you can use global Registry class implementing Registry design pattern (see https://dzone.com/articles/practical-php-patterns/basic/practical-php-patterns-0) along with some lazyloading. Here is working code for my api integration tests defined in Actor class (in my case ApiTester):

public function amLoggedInAs($userLogin){    $I = $this;    if (Registry::getInstance()->exists($userLogin)) {        // get data from registry        $storedUserData = Registry::getInstance()->get($userLogin);        $newAccessToken = $storedUserData['accessToken'];        $playerId = $storedUserData['playerId'];    }    else {        // no registry data - log in and save data in registry        $I->tryToLogin($userLogin);        $newAccessToken = $I->grabDataFromResponseByJsonPath('data.newToken');        $playerId = (int)$I->grabDataFromResponseByJsonPath('data.userId');        Registry::getInstance()->set($userLogin, [            'accessToken' => $newAccessToken,            'playerId' => $playerId        ]);    }    // finally set headers and some other data    $I->haveHttpHeader('X-Token', $newAccessToken);    $I->havePlayerId($playerId);}protected function tryToLogin($userLogin){    $I = $this;    $I->wantTo('login into api');    $I->amGoingTo('try to log to API using login and password');    $I->sendPOST('/system/login', ['login' => $userLogin, 'password' => self::getPassword($userLogin)]);    // ...some other checking if user was correctly logged in ...}

This code basically stores accessToken along with some additional data in Registry after user logged for first time. If another call to $I->amLoggedInAs('kgkg') is invoked, it gets these values from registry. You can have many logged users this way, each of them logged only once per suite.

You can use another method for autorization instead of custom token, logic will still be the same.

Also if you're using WebDriver (not PhpBrowser), you can use loadSessionSnapshot and saveSessionSnapshot instead of Registry to get quite the same result.


Right now Codeception takes care of this thanks to saveSessionSnapshot and loadSessionSnapshot methods.

<?php// inside AcceptanceTester class:public function login(){     // if snapshot exists - skipping login     if ($I->loadSessionSnapshot('login')) return;     // logging in     $I->amOnPage('/login');     $I->fillField('name', 'jon');     $I->fillField('password', '123345');     $I->click('Login');     // saving snapshot     $I->saveSessionSnapshot('login');}?>

then in your test classes you just do it like this

public function _before(AcceptanceTester $I){    $I->login();}