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

Is it possible to use dependency injection (a la Laravel's IoC) in a Cest? #1115

Closed
andrewhl opened this issue Jun 19, 2014 · 9 comments
Closed

Comments

@andrewhl
Copy link

I like to use helper classes to group various tests and provide additional support for tests. I'd like to inject these into my Cest classes via the constructor. But Codeception, unlike the Laravel IoC, doesn't automatically initialize dependencies. How can I accomplish this?

Please see the relevant gist:
https://gist.github.com/andrewhl/bb9303f0c0cd479c759a

@DavertMik
Copy link
Member

Sure you can. Just do not reinvent the wheel )
There are Codeception Hellpers (see Modules & Helpers chapter in Guides)

You should create a few helpers with generate:helper command. Put your methods inside them. And enable helpers in your suite configuration. Now you can use helper methods inside the actor object ($I) of Cest.

@andrewhl
Copy link
Author

Thanks. I figured out I can just put my page objects and helper classes in _bootstrap.php. Pretty good documentation in the advanced section of the site.

@andrewhl
Copy link
Author

I'm reopening this issue because I'm still having some trouble with it. I investigated Codeception helpers, and I believe they're intended for adding methods to AcceptanceTester.php (or FunctionalTester, depending on where you include them), as a module. This isn't quite what I'm looking for. I don't need individual methods, but rather a full class devoted to specific page elements (like NavBarHelper). Codeception builds its Helper classes into the AccepterTester.php class, but this also means that all static references point to AcceptanceTester, and not the Helper class itself.

I'm trying to find SOME way of injecting my own custom classes into a Cest, but I simply can't do it. Because Cests are dynamically instantiated, they can't take a constructor function with parameters. Codeception doesn't resolve the dependencies. I'd love to be able to do something like:

class SignUpCest {

    private $navBar;

    function __construct(NavBarHelper $navBarHelper)
    {
        $this->navBar = $navBarHelper;
    }

    public function alreadySignedUp(AcceptanceTester $I)
    {
        $args = [
            'first_name'            => 'Joe',
            'last_name'             => 'Jones',
            ...
        ];
        $I->expectTo('be already signed up');
        $I->amOnPage('sign_up');
        $I->submitForm('#sign_up', $args);

        $this->navBar->logout();

        $I->amOnPage('sign_up');
        $I->submitForm('#sign_up', $args);

        $I->see('That email has already been taken');
    }
}

Because that way I can reference static properties on the NavBarHelper class, and organize my helpers on a per-component or page element basis. I like the added control versus a simple module that contains individual helper functions.

My helper class might look something like this:

class NavBarHelper
{
    static $element = '#navBar';

    static $logoutLink = '#navBar a[href=/logout]';

    public function logout($I)
    {
        $I->click(static::$logoutLink);
        return $this;
    }
}

or like this:

use AcceptanceTester;

class NavBarHelper
{
    static $element = '#navBar';

    static $logoutLink = '#navBar a[href=/logout]';

    /**
     * @var
     */
    private $AcceptanceTester;

    function __construct(AcceptanceTester $I)
    {

        $this->AcceptanceTester = $I;
    }

    public function logout()
    {
        $this->AcceptanceTester->click(static::$logoutLink);
        return $this;
    }
}

@andrewhl andrewhl reopened this Jun 21, 2014
@andrewhl
Copy link
Author

As it stands, I tried doing something like this:

Creating a NavBarHelper module and adding it to AcceptanceTester.php via acceptance.suite.yml.

class NavBarHelper extends \Codeception\Module
{
    static $element = '#navBar';

    static $logoutLink = '#navBar a[href=/logout]';

    public function logout($I)
    {
        $I->click(static::$logoutLink);
        return $this;
    }
}

In SignupCest.php:

public function alreadySignedUp(AcceptanceTester $I)
{
    ...

    NavBarHelper::logout($I);

    ...
}

I get the following error: PHP Fatal error: Access to undeclared static property: SignUpCest::$logoutLink in /home/vagrant/code/myapp/tests/_support/NavBarHelper.php on line 15

Naturally, hard coding a dependency into my Cest like this isn't optimal to begin with, but I can't even do this much:)

@DavertMik
Copy link
Member

Did you read about PageObjects in Codeception?
They are pretty similar to what you are trying to achieve.

@andrewhl
Copy link
Author

Yep. I'm using PageObjects. They're great. The only problem is that I also want to use Cests to group my tests and have access to the before and after filters. I'd like to be able to inject a PageObject INTO a Cest. I think that's really what I'm trying to accomplish here.

@DavertMik
Copy link
Member

@andrewhl well, probably I can't propose anything of this kind. Unfortunately neither Codeception nor PHPUnit itself provide constructor injections into test cases. Probably we could implement such thing for Cest format but that's not something I'd implement in nearest future.

@splinter89
Copy link
Contributor

@andrewhl please take a look at #1164. Maybe it's better to use fabpot/Pimple or something similar?

@andrewhl
Copy link
Author

andrewhl commented Jul 1, 2014

@splinter89 Your pull request is pretty much exactly what I was looking for. Thanks! I hope it gets merged in soon.

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

3 participants