Search code examples
phpcodeception

How to properly replicate StepObject from Cept to Cest


Consider the following StepObject:

namespace Step\Acceptance;

class UserStep extends \AcceptanceTester
{
    public function login()
    {
        $I = $this;
        $I->amOnPage('/user/login');
        $I->fillField('username', 'user');
        $I->fillField('password', '123456');
        $I->click('Login');
    }
}

And now I'm going to use it in a Cept:

use Step\Acceptance\UserStep;

$I = new UserStep($scenario);
$I->login();
// change e-mail
// change password
// change profile
// etc
// log out

In the above scenario, the user will login once and attempt to accomplish all listed tasks.

Now, I'll use the same principle in a Cest:

class UserCest 
{    
    function changeEmail(\Step\Acceptance\UserStep $I)
    {
        $I->login();
        // task        
    }

    function changePassword(\Step\Acceptance\UserStep $I)
    {
        $I->login();
        // task        
    }

    function changeProfile(\Step\Acceptance\UserStep $I)
    {
        $I->login();
        // task        
    }

    function logout(\Step\Acceptance\UserStep $I)
    {
        $I->login();
        // task        
    }
}

Now using Cest when I run the tests the user will actually login 4 times over. This will also happen if I use @before or @depends annotations and also when using _before().

Is there a way to persist and run the login() step object once when using Cest?


Solution

  • The StepObject should be changed to the following:

    public function login()
    {
        $I = $this;
    
        if ($I->loadSessionSnapshot('login')) return;
    
        $I->amOnPage('/user/login');
        $I->fillField('username', 'user');
        $I->fillField('password', '123456');
        $I->click('Login');
    
        $I->saveSessionSnapshot('login');
    }
    

    This will not only persist and run the step object only once, but also brings the convenience of showing only one time the login steps in the console output.

    Another great convenience is being able to properly leverage the @before annotation.

    You could for example call the login step from a BaseCest, so login is now available in all your Cests and you can use @before login conveniently everywhere.