Latest sites

Quick news

  • 2014-03-27: MongoDB Watchdog module ported to Drupal 8 at the Szeged Dev Days.
  • 2014-01-26: My post on the Symfony web profiler in Silex selected in Week of Symfony. w00t !
  • 2013-10-18: My first commit went into MongoDB today. And, guess what ? It's in JavaScript
  • 2013-09-20 to 29: Working on Drupal 8 EntityAPI at the extended code sprints during and around DrupalCon Prague
  • 2012-08-19: Working on Drupal 8 EntityAPI at Drupalcon Munich
  • 2012-06-15: Working on Drupal 8 EntityAPI at DrupalDevDays Barcelona
  • 2012-03-23: Working on the future Drupal Document Oriented Storage at DrupalCon Denver. D8 or later ? Bets are on Later

When Behat does not find features or bootstrap...

The issue

I was checking a bunch of Behat features left by former developers on a project, and noticed that the Rake rule to run them looked like:

$ behat -c config/behat.yml features

But this looked suspiciously like defaut options. How about running them more simply like just $ behat ? Alas, this would throw something like:


  [InvalidArgumentException]                         
  Can't find applicable feature loader               
  Maybe you've forgot to create `features/` folder?

Specifying the Behat configuration file but not the features directory like this didn't change a thing:

$ behat -c config/behat.yml


  [InvalidArgumentException]                         
  Can't find applicable feature loader               
  Maybe you've forgot to create `features/` folder?

And yet the behat.yml appeared to look sane:

default:
    paths:
        features: '%behat.paths.base%/features'
        bootstrap: '%behat.paths.features%/bootstrap'
    extensions:
        Behat\MinkExtension\Extension:
            goutte: ~
            selenium2: ~
            base_url: http://some.site
        Drupal\DrupalExtension\Extension:
            blackbox: ~
            api_driver: 'drupal'
            drupal: 
                drupal_root: 'public/drupal'            
            drush:
                alias: 'somealias'
            region_map:
                content: "#content"
                'left header': '#header-left'
                'right header': '#header-right'
                'right sidebar': '#column-right'
                footer: "#footer-region"
            selectors:
                message_selector: '.messages'
                error_message_selector: '.messages.messages-error'
                success_message_selector: '.messages.messages-status'

The features were indeed in the (project dir)/features, the bootstrap was indeed from (project dir)/features/bootstrap. Modifying the bootstrap line showed that it was being used correctly. And yet the features line never worked. I tried multiple variants like these:

# As per the Behat docs at http://docs.behat.org/guides/7.config.html#paths :
default:
    paths:
        features: features

# Trying to specify the base path :
default:
    paths:
        features: %behat.paths.base%/features

# Trying to get rid of the IDE YAML parser warnings :
default:
    paths:
        features: '%behat.paths.base%/features'

All of which didn't change a thing. What could be going wrong ?

The diagnostic

I dug into the LocatorProcessor::process() function, and decided to dump what was going on. The function looks like this:

<?php
   
public function process(InputInterface $input, OutputInterface $output)
    {
       
$this->container->get('behat.console.command')->setFeaturesPaths(
            array(
$input->getArgument('features'))
        );

        if (
is_dir($bootstrapPath = $this->container->getParameter('behat.paths.bootstrap'))) {
           
$this->loadBootstrapScripts($bootstrapPath);
        }
    }
?>

Some data printing easily showed that the setFeaturesPaths() call received an empty string as the value of the features argument, while the loadboostrapScripts() received a well-formed value from the behat.paths.bootstrap parameter.

Well, that made sense: when a Symfony2 Command like the Behat console is called without an argument, it does not default to the matching parameter. But then, how about looking into the behat.paths.features parameter ?

That turned out to be the missing link: the value of the features parameter was actually something like (project dir)/config/features, not (project dir)/features as expected. In other words, that parameter is relative to the Behat config file, not to the current working directory. Which of course, the Behat documentation had been explaining all along:

%behat.paths.base% - current working dir or configuration path (if configuration file exists and loaded).

The solution

After Reading The Fine Manual armed with the results of this diagnostic, the solution was painfully obvious. Since the config file was in config/behat.yml, just climb back one level from it:

default:
    paths:
        features: '%behat.paths.base%/../features'
        bootstrap: '%behat.paths.features%/bootstrap'
# ...snip...

And, of course, the test suite now ran with just a simple:

$ behat