Running Behat Tests in a Vagrant Box

by Matt Oliveira

For a while now, Vagrant has been my local development environment of choice. It’s great for a lot of reasons but sometimes working in what is essentially a remote environment, has its challenges. One such challenge is running Behat Tests in a native browser like Chrome with Selenium.

Behat tests are the bee's knees. They are especially so when you can see your tests executed automatically in your desktop browser for easy debugging:

However, if you use Vagrant for local development you often lose the benefit of visualizing your test run because many off-the-shelf boxes you find on the internet are configured to run Behat tests using headless browsers like PhantomJS or headless Firefox with xvfb. It's certainly easier to get set up running your tests using PhantomJS, but it doesn’t have to be this way:

You can configure your Behat tests to run in your desktop browser so you can see everything. You can even get fancy and set breakpoints in your tests using an IDE like PHPStorm, halting the browser execution and giving you the opportunity to pop open Chrome dev tools or the like to really understand what’s going on during your test.

This article assumes a few things:

  • Local development environment using Vagrant for your Drupal site
  • Familiarity with Behat and Selenium
  • Chrome for running the tests

If you’re unfamiliar with Behat, Selenium and/or Vagrant, they are awesome, and you should check them out. Also, while we’re going to use Chrome here, you could use any browser supported by Selenium and your host operating system. Onwards.

Setup

There are a few things to get set up. Following is a diagram to help you understand the interaction between all the pieces as a way to visualize what you need:

Behat test flow

The above diagram shows the test suite run by Behat (1) on the Vagrant box. Behat talks to the Selenium hub (2) server running on the Vagrant box, which talks to the Selenium node (3) server on the host machine. Finally, the Selenium node server is what drives Chrome (4) to execute the test suite. Not to worry if you don’t understand what these things do, we’ll get into that below.

To get started with the setup, first ensure that you have the Java Runtime Environment (JRE) installed on your host machine and in the Vagrant box, which is required to run Selenium. You may already have it installed, but can check with:

$ java -version

I’m running JRE 1.8. If you need to install or update, Google is your friend.

Next, you’ll need Selenium. It’s handy to download it into a shared folder between the host machine and the Vagrant box. The important thing is that it’s available on both the host machine and Vagrant box.

$ wget http://selenium-release.storage.googleapis.com/2.53/selenium-server-standalone-2.53.1.jar

Finally, you’ll need Chrome driver on the host machine. For convenience move it somewhere on your PATH:

$ wget https://chromedriver.storage.googleapis.com/2.29/chromedriver_mac64.zip
$ unzip chromedriver_mac64.zip
$ mv chromedriver /usr/local/bin

Run tests

Now that you have all the software you need, it’s time to run the tests. First thing you’ll want to do is start Selenium server in hub mode in the Vagrant box:

$ java -jar /path/to/selenium/selenium-server-standalone-2.53.1.jar -role hub

Notice the -role hub option. This tells Selenium to run in hub mode. Running Selenium in hub mode allows Selenium to receive tests to be executed and forward them to any registered Selenium servers running in node mode. The Selenium server running in node mode is what controls the browser, driving the browser through the tests. In this way you can bridge the gap between the Vagrant box and the host machine, so that you can see the tests running in a browser on the host machine. You’ve already got the Selenium server in hub mode running on the Vagrant box. Now lets start a Selenium server in node mode on the host machine:

$ java -jar /path/to/selenium/selenium-server-standalone-2.53.1.jar -role node -hub http://my-vbox.local:4444/grid/register -Wdriver.chrome.driver=/path/to/chromedriver

Here, you’re telling Selenium to run in node mode, using the -role node option. You’re also registering the Selenium node with the Selenium hub running in your Vagrant box using the -hub http://my-vbox.local:4444/grid/register option. Replace my-vbox.local with the host name or IP address of your Vagrant box.

Next you’ll need to adjust your behat.yml file to register a Selenium Mink session, that points to the Selenium hub server running in the Vagrant box e.g.,

selenium2:
  wd_host: "http://my-vbox.local:4444/wd/hub"

So that your behat.yml file looks something like this:

default:
  suites:
    default:
      contexts:
        - FeatureContext
        - Drupal\DrupalExtension\Context\DrupalContext
        - Drupal\DrupalExtension\Context\MinkContext
  extensions:
    Behat\MinkExtension:
      goutte: ~
      selenium2:
        wd_host: "http://my-vbox.local:4444/wd/hub"
      base_url: http://my-vbox.local
      browser_name: 'chrome'
    Drupal\DrupalExtension:
      blackbox: ~
      api_driver: 'drupal'
      drush:
        alias: 'local'
      drupal:
        drupal_root: '/var/www/docroot'

With all that setup, you’re finally ready to run your tests. From your Vagrant box, run:

$ ./vendor/bin/behat -v -c /path/to/behat.yml /path/to/behat/features

If everything worked out, you’ll see Selenium open up a new instance of Chrome and drive it through the test suites:

newsletter-bot