I am trying to write some Behat tests for an application and I need to separate the Contexts so I can use some core elements in different other contexts for example the logged in user step.
behat.yml
suites:
common:
type: symfony_bundle
bundle: CommonBundle
mink_session: symfony2
mink_javascript_session: selenium2
autoload:
'CommonContext': %paths.base%/src/xxx/CommonBundle/Features/Context
contexts: [ xxx\CommonBundle\Features\Context\CoreContext ]
user:
type: symfony_bundle
bundle: UserBundle
mink_session: symfony2
mink_javascript_session: selenium2
autoload:
'UserContext': %paths.base%/src/xxx/UserBundle/Features/Context
contexts:
- Behat\MinkExtension\Context\MinkContext
- xxx\CommonBundle\Features\Context\CoreContext
- xxx\UserBundle\Features\Context\UserContext
DefaultContext.php
namespace XXX\CommonBundle\Features\Context;
use ...
/**
* Class DefaultContext
*/
class DefaultContext extends MinkContext implements Context, KernelAwareContext
{
/**
* @param AbstractEntity $oEntity
*
* @return object
*/
protected function getRepository(AbstractEntity $oEntity)
{
return $this->getService($oEntity);
}
/**
* @return mixed
*/
protected function getEntityManager()
{
return $this->getService('doctrine')->getManager();
}
/**
* @param $id
*
* @return object
*/
protected function getService($id)
{
return $this->getContainer()->get($id);
}
CoreContext.php
namespace XXX\CommonBundle\Features\Context;
use ...
/**
* Class SubContext
*/
class CoreContext extends DefaultContext implements Context, SnippetAcceptingContext
{
/**
* @Given I visit the homepage
* @When I visit the homepage
*/
public function iVisitHomepage()
{
$this->visitPath('/');
}
/**
* @And /^I am logged in as "([^"]*)"$/
* @Then /^I am logged in as "([^"]*)"$/
*/
public function iAmLoggedInAs($username)
{
$user = $this->getContainer()->get('fos_user.user_manager')->findUserByUsername($username);
$this->visit('/login');
$this->fillField('_username', $user->getEmailCanonical());
$this->fillField('_password', self::USER_PASSWORD);
$this->pressButton('_submit');
}
UserContext.php
namespace xxx\UserBundle\Features\Context;
use ...
/**
* Defines application features from the specific context.
*/
class UserContext extends CoreContext implements Context, SnippetAcceptingContext
{
/**
* Initializes context.
*
* Every scenario gets its own context instance.
* You can also pass arbitrary arguments to the
* context constructor through behat.yml.
*/
public function __construct()
{
}
}
register_user.feature
Feature: Register user
@javascript
Scenario: Register user
Given I am on homepage
And I go to "/register/"
And I am logged in as "foo@bar.com"
Then I should see "Terms and Conditions"
So when I run the test I get an error saying this:
Given I am on homepage
Step "I visit the homepage" is already defined in xxx\CommonBundle\Features\Context\CoreContext::iVisitHomepage()
xxx\CommonBundle\Features\Context\CoreContext::iVisitHomepage()
xxx\CommonBundle\Features\Context\CoreContext::iVisitHomepage()
And I go to "/register/"
Step "I visit the homepage" is already defined in xxx\CommonBundle\Features\Context\CoreContext::iVisitHomepage()
xxx\CommonBundle\Features\Context\CoreContext::iVisitHomepage()
xxx\CommonBundle\Features\Context\CoreContext::iVisitHomepage()
Do i understood this completely wrong or I am missing some settings here?
Do not extend contexts that provide step definitions. There's no way around this.
Good extensions provide contexts with handy methods but no step definitions. In case of the Mink extension, next to the MinkContext
you also have RawMinkContext
. First provides step definitions and should not be extended. The other one provides helper methods you might be interested in. The RawMinkContext
is the one you should extend. Alternatively you can also use the MinkAwareTrait
.