You are here

Headless Browser Testing for Drupal using Zombie.js

An alternative to using Drupal to replicate and test itself with SimpleTest: One could employ a third-party to test a "living" Drupal environment.

Zombie.js provides a headless browser that can inspect the contents of a page, return assertions, process events and test for errors. It does all of this very quickly. Zombie can be installed using Homebrew (OSX) or through apt-get. Tests are written in Javascript (or Coffeescript) and they can be triggered server-side by through CI systems.

Below you will find an example test for a Drupal user login. It uses an extremely fast, headless browser provided by Zombie.js. It is written in Coffeescript. In my tests, the script takes less than a few seconds to run but that obviously depends on how fast your test environment is.

To test this way, we must first install the dependencies, Node, Zombie and Coffeescript. Note: I use a Macintosh so these directions apply to my brand of UNIX. Visit for Ubuntu instructions and full docs for Zombie.js and its API.

$ brew install node
$ curl | sudo sh
$ npm install zombie
$ npm -g install coffee-script

Next, a breakdown of the Coffeescript in a new file named

We need the Browser object and the assert method.

Browser = require("zombie")
assert = require("assert")

Just a couple of variables used for testing our user login.

user = "admin"
pass = "password"

We create a new browser and set it to debug mode for verbose output.
Next pass in an additional option for a default site URL.
Then tell the browser to visit the homepage where a login form should exist...

browser = new Browser(debug: true) = "http://sandbox.d7"
browser.visit "/", ->

We tell the browser to fill username/password and submit the form.

   browser.fill("name", user).fill("pass", pass).pressButton "Log in", ->

The form is submitted so a new page is loaded.
We check for an element provided by the admin_menu_toolbar.module.
If no failures, the script logs a friendly message to console.

    assert.ok browser.success
    assert.equal browser.text(".admin-menu-account a"), "Hello " + user
    console.log "Logged In"

That's it. Run the test with a single line in the console:

$ coffee

Since we went out of our way to declare debug:true lets revel in some verbose output.

Zombie: Opened window http://sandbox.d7/ un-named
Zombie: GET http://sandbox.d7/ => 200
Zombie: Loaded document http://sandbox.d7/
Zombie: GET http://sandbox.d7/misc/jquery.once.js?v=1.2 => 200
Zombie: GET http://sandbox.d7/misc/drupal.js?me5z5w => 200
Zombie: Event loop is empty
Zombie: submit form to /node?destination=node
Zombie: Opened window http://sandbox.d7/node?destination=node un-named
Zombie: 302 => http://sandbox.d7/node
Zombie: POST http://sandbox.d7/node?destination=node => 200
Zombie: Loaded document http://sandbox.d7/node
Zombie: GET http://sandbox.d7/misc/jquery.once.js?v=1.2 => 200
Zombie: GET http://sandbox.d7/modules/contextual/contextual.js?v=1.0 => 200
Zombie: GET http://sandbox.d7/misc/drupal.js?me5z5w => 200
Zombie: GET http://sandbox.d7/sites/all/modules/admin_menu/admin_menu.js?me5z5w => 200
Zombie: GET http://sandbox.d7/sites/all/modules/admin_menu/admin_menu_toolbar/admin_menu_toolbar.js?me5z5w => 200
Zombie: Event loop is empty
Logged In

For more examples and to see this code unadulterated from formatting/comments, see:

Submitted by brant on Tue, 11/27/2012 - 17:32