Please enable JS

Part 2: Automated Drupal testing with Behat, Selenium, and Headless Firefox

How to: Install and configure Selenium to control a headless FireFox and use BeHat to test your Drupal site.
March 16/Brian Young/Drupal 7Software

I strongly suggest you read part 1 where I explain how each of these libraries and applications interact with each other.

Part 1: Automated Drupal testing with Behat, Selenium, and Headless Firefox

Verify Prerequisites

I assume you have the following already installed:

Installation

Have Composer Install Dependencies

We'll let Composer handle the majority of the work. We'll need to tell Composer what dependencies our project requires.

Create composer.json

Create a composer.json file that contains all our required packages by pasting in the following:

  1. {
  2. "require": {
  3. "behat/behat": "~3.0",
  4. "behat/mink-goutte-driver": "~1.2.0",
  5. "behat/mink-extension": "~2.1",
  6. "behat/mink-selenium2-driver": "~1.3",
  7. "drupal/drupal-extension": "~3.1"
  8. }
  9. }

Composer Install

Have Composer install our needed packages. From the same directory the composer.json file is in, run:

  1. composer install

Troubleshooting

If you get an error like the following:

  1. PHP Fatal error: Uncaught exception 'ErrorException' with message 'proc_open(): fork failed - Cannot allocate memory'

Composer executes PHP on the CLI so it should be configured to have no memory limit by default thus exhausting all the machine has to offer. You will need to enable Virtual Memory (Swap File).

Setup Behat

Behat will handle all the actual test cases. We'll configure some path settings and have Behat initialize our directory structure.

Create behat.yml

Create a new file called behat.yml and paste in the following:

  1. default:
  2. autoload:
  3. '': %paths.base%/features/bootstrap
  4. suites:
  5. default:
  6. paths:
  7. - %paths.base%/features
  8. contexts:
  9. - FeatureContext
  10. - Drupal\DrupalExtension\Context\DrupalContext
  11. - Drupal\DrupalExtension\Context\MinkContext
  12. - Drupal\DrupalExtension\Context\MessageContext
  13. extensions:
  14. Behat\MinkExtension:
  15. goutte: ~
  16. selenium2: ~
  17. base_url: https://drupal.org/
  18. Drupal\DrupalExtension:
  19. blackbox: ~
  20. region_map:
  21. header_nav: ".wx-header-tools"

We're using Behat 3.x so the autoload and path settings look a little different from the old 2.5 version.

Notice the use of blackbox. It comes with the DrupalExtension; it allows us to find elements within a "region" for situations where the target element doesn't have a unique selector. See Blackbox docs for more information.

Initialize Behat Config

Now that we have our behat.yml file configured, let's have Behat initialize a working directory tree.

  1. ./vendor/bin/behat --init

You should get some green outputs about where to put features and context classes.

Install Firefox

Nothing special here. Just use apt-get to install the current stable release of Firefox.

  1. sudo apt-get install firefox

Install & Configure Xvfb

We'll use Xvfb to create a dummy display for Firefox to run in.

Install Xvfb

  1. sudo apt-get -y install xvfb gtk2-engines-pixbuf
  2. sudo apt-get -y install xfonts-cyrillic xfonts-100dpi xfonts-75dpi xfonts-base xfonts-scalable

Configure Xvfb Display

We need to configure a display number kind of high to avoid collision with existing displays.

  1. sudo Xvfb :10 -ac -screen 0 1024x768x8 &

You may get a warning about missing font paths; this is okay, just ctrl+c. Verify Xvfb is running by running:

  1. ps aux | grep -P "^root.*Xvfb"

You should get one or two lines back that look like:

  1. root 11345 0.0 2.7 136480 13724 pts/0 S 00:24 0:00 Xvfb :10 -ac

Set Environment Display Variable

We need to update the DISPLAY environment variable so Firefox will know what to attach to.

  1. export DISPLAY=:10

Download & Configure Selenium

Download Selenium Standalone

Download the latest jar file.

  1. curl -J -O -L http://selenium-release.storage.googleapis.com/2.53/selenium-server-standalone-2.53.0.jar

We'll make a symbolic link to a filename without Selenium's version number.

  1. ln -s ./selenium-server-standalone-2.53.0.jar ./selenium-server-standalone.jar

Selenium - Hub (aka Server)

Selenium can be configured to run as a hub, a node, or standalone. For this tutorial, we'll configure the hub first, then add a node.

Create a script called start-selenium-hub.sh that will start our Seleniun Hub.
Paste the following code in this new file:

  1. #!/bin/bash
  2.  
  3. java -jar ./selenium-server-standalone.jar -role hub -host 0.0.0.0 > ./selenium-hub.log 2>&1 &

Give the script executable permissions and run it:

  1. chmod u+x ./start-selenium-hub.sh
  2. ./start-selenium-hub.sh

Notice we're outputting to a selenium-hub.log file. We'll do the same for the node.

Warning! Selenium binds to 0.0.0.0

Selenium binds to the 0.0.0.0 interface regardless of the host settings you provide. You should not run this on a publicly accessible machine without blocking external connections via a firewall or iptables.

Selenium - Node

Create a script called start-selenium-node.sh that will start our Selenium node.
Paste the following code in this new file:

  1. #!/bin/bash
  2.  
  3. if [ ! -f /tmp/.X5-lock ]; then
  4. /usr/bin/Xvfb :10 -ac -screen 0 1024x768x8 &
  5. fi
  6.  
  7. export DISPLAY=:10 # firefox needs this to know where to find a display to run on
  8.  
  9. java -jar ./selenium-server-standalone.jar -role node -hub http://127.0.0.1:4444/grid/register/ > ./selenium-node.log 2> ./selenium-node.err &

Give the script executable permissions and run it:

  1. chmod u+x ./start-selenium-node.sh
  2. ./start-selenium-node.sh

Troubleshooting

If Selenium fails to start fully and you are on a VPS hosting service such as Digital Ocean or a VM; see this entropy related problem and solution:
Selenium Node, slow hub register

Behat Test Scripts

We're almost ready to run our test scripts!

Write our first test script!

We're going to do a test search on drupal.org for our test.
When we ran /vendor/bin/behat --init earlier, a file features/test.feature was created. This is where we'll store our test cases.

Add the following to the features/test.feature file:

  1. Feature: Drupal.org search
  2. Searching for behat from drupal.org's search box.
  3.  
  4. @javascript
  5. Scenario: Searching for "behat"
  6. Given I go to "https://www.drupal.org"
  7. When I search for "behat"
  8. Then I should see "Behat Drupal Extension"

Tell Behat how to search

We'll be testing Drupal.org's search box. For this, we need to write a custom step definition for: "I search for".

Earlier when we ran /vendor/bin/behat --init, it generated a file: features/bootstrap/FeatureContext.php. In this file, add the follow snippet:

  1. /**
  2.  * @When /^I search for "([^"]*)"$/
  3.  */
  4. public function iSearchFor($search_term)
  5. {
  6. $page = $this->getSession()->getPage();
  7. $page->fillField('Search', $search_term);
  8. $page->pressButton('Search');
  9. }

Run our tests

Make sure you are currently in the directory that contains the behat.yml. Run the following command:

  1. vendor/bin/behat

You should get an output similar to:

  1. Feature: Drupal.org search
  2. Searching for behat from drupal.org's search box.
  3.  
  4. @javascript
  5. Scenario: Searching for "behat" # features/test.feature:5
  6. Given I go to "https://www.drupal.org" # Drupal\DrupalExtension\Context\MinkContext::visit()
  7. When I search for "behat" # FeatureContext::iSearchFor()
  8. Then I should see "Behat Drupal Extension" # Drupal\DrupalExtension\Context\MinkContext::assertPageContainsText()
  9.  
  10. 1 scenario (1 passed)
  11. 3 steps (3 passed)
  12. 0m9.66s (14.59Mb)

Troubleshooting

If you receive errors like:

  1. Unable to connect to host 127.0.0.1 on port 7055 after 45000 ms.

It's likely your version of Selenium is not compatible with the version of Firefox you have installed. You'll need to downgrade to a previous version.
Here is an example of manually installing a previous release of Firefox.



RELATED POSTS


Comments/ 0


LEAVE A COMMENT

(If you're a human, don't change the following field)
Your first name.
(If you're a human, don't change the following field)
Your first name.
(If you're a human, don't change the following field)
Your first name.
But why?

My random thoughts and documentation on the various hardware and software projects that occupy my day-to-day. My only hope is that other people can benefit from my notes.

Recent posts
Categories