I tried to make reusable steps from DrupalContext's available steps (see http://docs.behat.org/guides/2.definitions.html).

For exemple, I have my custom context .behat.inc correctly loaded, when I create a step like this:

 /**
   * @When /^Reusable step$/
   */
  public function reusableStep() {
    return new When('Given I am logged in as a user with the "administrator" role');
  ...

It won't be find if my context class is like

class CustomModuleContext extends BehatContext implements DrupalSubContextInterface {

So I tried to extend DrupalContext to get the step definitions, but then I get

PHP Fatal error:  Maximum function nesting level of '100' reached, aborting! in {project/}sites/all/vendor/symfony/finder/Symfony/Component/Finder/Expression/Regex.php on line 299
...
PHP  86. Behat\Behat\Context\ContextDispatcher->initializeContext() /home/didier/Projets/wakiris/sites/all/vendor/behat/behat/src/Behat/Behat/Context/ContextDispatcher.php:136
PHP  87. Drupal\DrupalExtension\Context\Initializer\DrupalAwareInitializer->initialize() /home/didier/Projets/wakiris/sites/all/vendor/behat/behat/src/Behat/Behat/Context/ContextDispatcher.php:129
PHP  88. Drupal\DrupalExtension\Context\Initializer\DrupalAwareInitializer->findAvailableSubContexts() /home/didier/Projets/wakiris/sites/all/vendor/drupal/drupal-extension/src/Drupal/DrupalExtension/Context/Initializer/DrupalAwareInitializer.php:62
PHP  89. Symfony\Component\Finder\Finder->getIterator() /home/didier/Projets/wakiris/sites/all/vendor/symfony/finder/Symfony/Component/Finder/Finder.php:0
PHP  90. Symfony\Component\Finder\Finder->searchInDirectory() /home/didier/Projets/wakiris/sites/all/vendor/symfony/finder/Symfony/Component/Finder/Finder.php:692
PHP  91. Symfony\Component\Finder\Adapter\PhpAdapter->searchInDirectory() /home/didier/Projets/wakiris/sites/all/vendor/symfony/finder/Symfony/Component/Finder/Finder.php:785

It seems there is a problem with the way DrupalSubContextInterface is implemented.

Comments

b2f’s picture

Issue summary: View changes

improve readability

b2f’s picture

If you create a custom context like the one foo.behat.inc in the doc, and try to extend DrupalContext or extending with useContext, you can reproduce this issue easily.

b2f’s picture

After adding a var_dump, I found that the infinite nesting occur in the Regex parsePattern method with the pattern:

"string(28) "^(?=[^\.])[^/]*\.behat\.inc$"".

The only place where I could see a call to this pattern is DrupalAwareInitializer in findAvailableSubContexts, so I went up to the initialize method.

        foreach ($paths as $path) {
  var_dump('path : ' . $path);
          if ($subcontexts = $this->findAvailableSubContexts($path)) {
            $context->initializeSubContexts($subcontexts);
          }
        }

Then initializeSubContexts...

93   /**
  94    * Initialize subcontexts.
  95    *
  96    * @param array $subcontexts
  97    *   Array of sub-context class names to initiate, keyed by sub-context alias.
  98    */
  99   public function initializeSubContexts(array $subcontexts) {
 100     foreach ($subcontexts as $path => $subcontext) {
 101       if (!file_exists($path)) {
 102         throw new \RuntimeException(sprintf('Subcontext path %s path does not exist.', $path));
 103       }
 104 
 105       // Load file.
 106       require_once $path;
 107     }
 108 
 109     // @todo this seems overkill.
 110     $classes = get_declared_classes();
 111     $subcontext_classes = array();
 112     foreach ($classes as $class) {
 113       $reflect = new \ReflectionClass($class);
 114       if ($reflect->implementsInterface('Drupal\DrupalExtension\Context\DrupalSubContextInterface')) {
 115         $alias = $class::getAlias();
 116         $this->useContext($alias, new $class);
 117       }
 118     }
 119   }

At some point there is an infinite recursion on DrupalContext itself, still digging, but I think I understood how: DrupalContext will search for DrupalSubContextInterface interfaces and initialize them, which will never end because this process is contained in DrupalContext, which is constructed in DrupalSubContextInterface interfaces...

Is it possible to use DrupalContext methods and steps within a DrupalSubContextInterface implementation ?

b2f’s picture

I'll try to make a patch with the singleton pattern or something likewise, it should solve this issue.

b2f’s picture

Status: Active » Closed (won't fix)

I fixed the infinite recursion loop locally only to find out that you can't have step inheritance in Behat:

"Behat will not let you define a step expression’s corresponding regular expression more than once. For example, look at the two @Given regular expressions defined in this feature context: ..."

http://docs.behat.org/guides/2.definitions.html

So anyway you can't have more than one DrupalContext (subclass included) in your app or it will generate the error above.

b2f’s picture

Status: Closed (won't fix) » Closed (works as designed)

Actually, I should have been able to use steps from the parent context of the subcontext with Behat\Behat\Context\Step\ methods... I'll try to reproduce this issue tomorrow but now it seems that when extending BehatContext it is working... So I shouldn't have ran in this issue in the first place.

b2f’s picture

Can't believe I didn't see it earlier...
I typed:
return new When('Given I am logged in as a user with the "administrator" role');

Instead of
return new When('I am logged in as a user with the "administrator" role');

A fresh look on debuging is always a huge gain of time...

b2f’s picture

Issue summary: View changes

php fix