Adam Johnston

Using WebDriver.IO + Jasmine + PhantomJS

To develop my skills as a front end developer I wanted to start adding acceptance testing to the web apps that I build. For a while I have found the wide selection of tools to be somewhat daunting. I found WebDriver.IO, (a NodeJS wrapper for Selenium 2.0 or WebDriver I discovered) and I thought I would give it a try and record my experience.


Author notice!

At the time of writing this very line I have not even installed WebDriver.IO and so please do not consider this a ‘how to’, it’s simply my experience using WebDriver.IO along with Jasmine and PhantomJS (which I am also fairly unfamiliar with), for good or bad.

If you find anything within this article that is incorrect or could be improved upon, please don’t hesitate to let me know. I am still new to testing so any help is greatly appreciated. Thank you!


Installation

The documentation asks you to install Selenium Server Standalone via Curl but I used HomeBrew since I am working with Mac OSX and the version is the same as the Curl version so I assume it’s safe to do so.

HomeBrew will also give you some instructions on how to start the Selenium Server. Since I am trying it out I don’t want Selenium Server to run every time I start my Mac so inside terminal I will just use:

$ selenium-server

Doing so will fire up Selenium Server, ready for use. To install WebDriver.IO it’s as easy as using NPM (Node Package Manager).

Using the terminal:

//  adds webdriverio to a local project
$ npm install webdriverio

Inside of test.js:

var webdriverio = require('webdriverio')

Once the server was up and running I put together an exact version of the demo from WebDriver.IO’s documentation. Something to note, the first time I ran the test it took quite some time for it to return the value, subsequent tests were noticeable quicker.

On the whole installation was very quick and very simply which is always good in my book. Now though I want to add it to a potential test suite.


Writing my first tiny Jasmine, WebDriver.IO & PhantomJS spec

I am going to be using Jasmine as my spec framework, I am familiar with RSpec and Jasmine seemed like a natural JavaScript alternative and also WebDriver.IO supports it (min version 2.0), I’ll also be using PhantomJS to have a browser to run the specs in. If you haven’t already installed them, it’s simply a case of using NPM again. Also to gain access to WebDriver.IO’s cli tools and test runner you’ll need to add it as a global package.

$ npm install -g webdriverio jasmine phantomjs

At this stage I don’t plan on adding it to an existing project because I want to learn more of the WebDriver.IO API and I want to start small so I am going to create a single spec file and create a WebDriver.IO config file.

//  creates a jasmine framework file structure
$ jasmine init

//  goes through the process of create a webdriver.io config
$ wdio config
// subsequent config (minus comments)
exports.config = {
  specs: ['spec/**/*.js'],
  exclude: [
    // 'path/to/excluded/files'
  ],
  capabilities: [
    {
      browserName: 'phantomjs',
    },
  ],
  logLevel: 'silent',
  coloredLogs: true,
  screenshotPath: './errorShots/',
  baseUrl: 'http://adamjohnston.co.uk',
  waitforTimeout: 10000,
  framework: 'jasmine',
  reporter: 'dot',
  jasmineNodeOpts: {
    defaultTimeoutInterval: 5000,
    expectationResultHandler: function (passed, assertion) {
      // do something
    },
    grep: null,
    invertGrep: null,
  },

  onPrepare: function () {
    // do something
  },

  before: function () {
    // do something
  },

  after: function () {
    // do something
  },

  onComplete: function () {
    // do something
  },
}

So with that said, I am going to test my portfolio site. I have a menu button that when clicked will show a list of articles. These are my specs:

  • When I visit the page I shouldn’t see any navigation.
  • When I click the menu button, I want to see the navigation.
  • When I click the menu button a second time, I stop seeing the navigation.

Also at this point I am going to introduce Jasmine to handle breaking the specs up. WebDriver.IO provides many examples including a Jasmine specific example, but this is where I ran in to some issues. I was getting the following error:

Started /Users/adrjohnston/Sites/webdriver-test/node_modules/webdriverio/node_modules/q/q.js:141
throw e;
Error: POST /session//url
Build info: version: '2.46.0', revision: '87c69e2', time: '2015–06–04 16:16:47'
System info: host: 'Adams-MBP', ip: '192.168.0.4', os.name: 'Mac OS X', os.arch: 'x86_64', os.version: '10.10.3', java.version: '1.8.0_45'
Driver info: driver.version: unknown
at new ErrorHandler.RuntimeError (/Users/adrjohnston/Sites/webdriver-test/node_modules/webdriverio/lib/utils/ErrorHandler.js:92:12)
at RequestHandler.<anonymous> (/Users/adrjohnston/Sites/webdriver-test/node_modules/webdriverio/lib/utils/RequestHandler.js:168:25)
at Request.self.callback (/Users/adrjohnston/Sites/webdriver-test/node_modules/webdriverio/node_modules/request/request.js:373:22)
at Request.emit (events.js:110:17)
at Request.<anonymous> (/Users/adrjohnston/Sites/webdriver-test/node_modules/webdriverio/node_modules/request/request.js:1318:14)
at Request.emit (events.js:129:20)
at IncomingMessage.<anonymous> (/Users/adrjohnston/Sites/webdriver-test/node_modules/webdriverio/node_modules/request/request.js:1266:12)
at IncomingMessage.emit (events.js:129:20)
at _stream_readable.js:908:16
at process._tickCallback (node.js:355:11)

So turns out that the documentation and the examples confused me somewhat and after a few of hours trying to figure things out I now have everything working.

I was following through the example and was trying to run it with WebDriver.IO’s test runner and when that failed, trying Jasmine’s runner but the error persisted. I think because I used wdio config it’s a way of using WebDriver.IO’s test runner which works a little bit differently and I found how to use the WebDriver.IO’s test runner in this example elsewhere. I prefer this approach so I am going to continue using:

$ wdio wdio.config.js

One thing to note. I currently don’t know what is setting the browser object. I cannot find a reference to it on the WebDriver.IO docs and so I am assuming it comes from Selenium or PhantomJS.

One last little issue I ran into. I was not calling Jasmine’s done callback after my specs and thus would cause a timeout exception.

Error: Timeout — Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.

I am not super familiar with Jasmine either so this is something worth reading into. So without further-ado here’s my spec with notes or just the basic version:

// ====== nav-menu.spec.js ======
describe('adamjohnston.co.uk', function () {
  beforeAll(function (done) {
    browser.url('/').call(done)
  })

  afterAll(function (done) {
    browser.end(done)
  })

  describe('when a user visits index', function () {
    it('should not have navigation visible', function (done) {
      browser
        .getCssProperty('nav[role=”navigation”]', 'opacity')
        .then(function (opacity) {
          expect(opacity.value).toBe(0)
        })
        .call(done)
    })
  })

  describe('when a user clicks the menu button', function () {
    it('should show the navigation', function (done) {
      browser
        .click('#jsNavBtn')
        .getCssProperty('nav[role=”navigation”]', 'opacity')
        .then(function (opacity) {
          expect(opacity.value).toBe(1)
        })
        .call(done)
    })

    it('should hide navigation if clicked again', function (done) {
      browser
        .click('#jsNavBtn')
        .getCssProperty('nav[role=”navigation”]', 'opacity')
        .then(function (opacity) {
          expect(opacity.value).toBe(0)
        })
        .call(done)
    })
  })
})
//  ======  terminal output  ======
$ wdio wdio.conf.js
․․․
3 passing (6.20s)

Summary

All in all not a bad couple of hours of work and a toolset that I definitely think I will invest more time in knowing. I think acceptance testing is very important and the combination of WebDriver.IO + Jasmine + PhantomJS seems promising.

I think my next steps will be to look into using it with Gulp (another tool WebDriver.IO supports) and try testing out a MeteorJS application (There are few WebDriver.IO packages on Atmosphere). Surely not long before I am JS acceptance testing machine!