Selenium Screenshot on Behat Scenario Step Failure

I love me some behat ... despite losing 8 hours chasing down an addition to a YAML file. No, I don't think I'll cool off about that any time soon.

One of the things that has enchanted me about behat is not having to write many of the tedious methods I would have to otherwise write to get Selenium2 to work with it, as I would with SimpleTest. There are still a few things, however, that I've needed to chase down, like a method to take a snapshot of a failed step, automatically. Thanks to Kunstmann, I have a method for this, and thanks to my laziness, I have the image opening automatically in Mac's Preview app.

<?php
  
/**
   * Take screenshot when step fails. Works only with Selenium2Driver.
   *
   * If on a Mac, runnining from the command line, with the SHOW_SNAPSHOT
   *  environment variable set to 1, the snapshot will open in Preview.
   *
   * Screenshot is saved at [Date]/[Feature]/[Scenario]/[Step].jpg .
   *
[email protected]@javascript
   */
  
public function takeScreenshotAfterFailedStep(Behat\Behat\Event\StepEvent $event) {
    if (
$event->getResult() === Behat\Behat\Event\StepEvent::FAILED) {
      
$driver $this->getSession()->getDriver();
      if (
$driver instanceof Behat\Mink\Driver\Selenium2Driver) {
        
$step $event->getStep();
        
$path = array(
          
'date' => date("Ymd-Hi"),
          
'feature' => $step->getParent()->getFeature()->getTitle(),
          
'scenario' => $step->getParent()->getTitle(),
          
'step' => $step->getType() . ' ' $step->getText(),
        );
        
$path preg_replace('/[^\-\.\w]/''_'$path);
        
$filename '/tmp/behat/' .  implode('/'$path) . '.jpg';

        
// Create directories if needed.
        
if (!@is_dir(dirname($filename))) {
          @
mkdir(dirname($filename), 0775TRUE);
        }

        
file_put_contents($filename$driver->getScreenshot());
        if (
PHP_OS === "Darwin" && (bool) getenv('SHOW_SNAPSHOT') === TRUE && PHP_SAPI === "cli") {
          
exec('open -a "Preview.app" ' $filename);
        }
      }
    }
  }
?>

So, the basic idea is, you edit your ~/.bash_profile and add export SHOW_SNAPSHOT=1 and run behat as you normally would. When behat hits a step in a scenario or feature tagged @javascript, Selenium2 will be instructed to snap a shot of the screen that failed. If you're on a Mac (I know I am. What's keeping you?), the screenshot will open in Preview, and you don't have to go hunting for it. In the current setup above, I'm storing those in the /tmp folder, because then, I don't have to clean up after myself!

Caveat: If, for example, you're getting "Element XZY not found" type messages, and Selenium2 has not scrolled far enough down the page, you may not see anything useful. You may want to add a step before the one that fails that clicks an element above where you expect your element to be. This has helped me half a dozen times since last night, mainly with cases where I copy-paste from one feature to another and I don't correct the URL I think I'm on. Eg: When I am on "node/add/content-type-a" and I think I should be on "node/add/content-type-b". In any case, I hope you find it useful!