How to Setup Behat with Sahi Testing on OSX

Behavior driven development (BDD) really takes the ideas of Test Driven Development (TDD) to the next level. By using popular libraries like Cucumber or the PHP focused Behat you can expand your acceptance criteria into a set of executable acceptance scenarios. Using one of these libraries will let your run your integration tests automatically, which is good for everyone!

This article is about setting up Behat to us the Sahi extension so that you can automate a browser interaction in your tests. This is important because out of the box the Behat / Mink web application test combination can't execute javascript. And of course many a modern web application relies on javascript for key parts of the user interaction; and these need to be tested! Below you will set up a sample project that tests part of this very blog! Cool.

Things you will need:

  • PHP 5.3 (of course)
  • Composer (install from here)
  • A Java Runtime Environment (Check with java --version)

1. Create a test project.

mkdir behat-sahi
cd behat-sahi

2. Install dependencies.

Create a composer.json file in the root of your behat-sahi directory with these contents:

{
    "name": "behat-sahi",
    "description": "Behat and Sahi Example",
    "require": {
        "behat/behat": "2.4.*",
        "behat/mink": "1.4@stable",
        "fabpot/goutte": "1.0.x-dev",
        "behat/mink-extension": "dev-master",
        "behat/mink-goutte-driver":"dev-master",
        "behat/mink-sahi-driver": "*"
    },
    "config": {
        "vendor-dir": "vendor/",
        "bin-dir": "bin/"
    }
}

Then use composer to install the dependencies:

composer install

You should see a slew of downloading information and then have a bin and vendor directory in your project, plus a composer.lock file. Moving on...

3. Initialize Behat.

bin/behat --init

This will create a features directory structure.

4. Set up Sahi

Taking a break from the sample project setup, let's set up the Sahi server. Head on over to http://sourceforge.net/projects/sahi/files/ and download the latest version.

Installing Sahi

Double click the file to run the installer, which let's you select which location you want to place the files. I put mine in /usr/local/share/sahi/

Important Configuration

You will want to edit the file located at /usr/local/share/sahi/config/ff_profile_template/pref.js adding this line to the bottom:

user_pref("toolkit.startup.max_resumed_crashes", 999999999);

What this does is up the limit of how many times Firefox can crash before it complains and askes you to start it in safe mode. As Narayan explains here: "Sahi force kills a browser, and Firefox sees it as a crash." This way you will be able to run you Sahi tests with no problems using firefox.

Starting the Server

Navigate to /usr/local/share/sahi/userdata/bin and run this:

./start_sahi.sh

And the server should start!

5. Configure Behat.

First create your configuration file in the root of your sample project:

touch behat.yml

Now add this information to your behat.yml file:

default:
  paths:
    bootstrap:  '%behat.paths.features%/bootstrap'
  extensions:
    Behat\MinkExtension\Extension:
      base_url: http://www.neverstopbuilding.com
      javascript_session: sahi
      browser_name: firefox
      goutte: ~
      sahi: ~

And finally add this line under the "use" statements in your features/bootstrap/FeatureContext.php file:

use Behat\MinkExtension\Context\MinkContext;

And change that class to extend the MinkContext instead:

class FeatureContext extends MinkContext
{
    ...
}

At this point if you run:

bin/behat

From the root of your sample project you should see:

No scenarios
No steps
0m0.002s

Let's change that!

6. Create a sample test.

First create a file features/test-feature.feature and add this to it:

Feature: Test Behat with Sahi
    As a developer
    I want to see behat work with sahi
    So I can test my javascript web application, like a pro

Scenario: Go to my blog and check something static
    Given I am on "/"
    Then I should see "{never stop building}"

Adding a javascript test

When you run this (again bin/behat) it should pass. Cool! Now let's add a specific javascript test, add this to the bottom of your feature file:

@javascript
Scenario: go to my blog and click on the side bar toggle
    Given I am on "/"
    When I click on the ".toggle-sidebar" element
    Then the sidebar should be collapsed

Make sure to include the @javascript annotation as it tells the test runner to use the Sahi component for this test.

Extending your context file

If you run the tests now you should see the Sahi spawn a browser but the tests will fail because you have not implemented the custom functions we are using in this scenario. Add these inside your Feature Context class:

    /**
     * @When /^I click on the "([^"]*)" element$/
     */
    public function iClickOnTheElement($cssQuery)
    {
        $session = $this->getSession();
        $page = $session->getPage();
        $element = $page->find('css', $cssQuery);
        $element->click();
    }

    /**
     * @Then /^the sidebar should be collapsed$/
     */
    public function theSidebarShouldBeCollapsed()
    {
        $session = $this->getSession();
        $page = $session->getPage();
        $element = $page->find('css', "body");
        $class = $element->getAttribute("class");
        if ($class != "collapse-sidebar") {
            throw new \Exception('Side bar is not collapsed!');
        }
    }

NOW, when you run Behat you should see a browser be spawned and work through the simple test you have defined, showing all the tests having passed.

OMG a Screencast!

I got so excited by this project I made a screencast to walk you through it:

If you are interested in a source code for this tutorial, check it out here.

Next up: Off with their head!

My ultimate goal is to have all this run through a headless browser, likely PhantomJS. When that starts to work there will for sure be a post about it.

Enjoy this article? Read more like it in the Test Driven Development category.