GivenWhenThen: Simple, Powerful Acceptance Testing for Node.js

January 25th, 2012 by Doug Wright

Over the last year or so, interest in and development for Node.js has accelerated dramatically. There is no shortage of excitement and promise in this burgeoning community and for many of the same reasons cited by others, about six months ago we decided it made sense to dive in ourselves.

Coming from a committed testing background on multiple web frameworks, including Rails, we are strong adherents to BDD. Naturally the first thing we did when spinning up on the Node stack was look around for good BDD acceptance testing tools. Not finding anything that fit for us, we went ahead and rolled our own. In this post, we’ll introduce GivenWhenThen, a DSL and runner that allows anyone to easily construct acceptance tests with BDD semantics in straightforward, sentence-like statements and then run them against Sauce Labs.

Writing a Story

Although you can also directly access the Selenium RemoteWebDriver that is under the covers, GivenWhenThen is primarily intended to provide a DSL for writing executable stories in the Dan North format. To write a story, begin with a BDD description in a xxx_test.coffee file:

 

story 'Executing a Google search',
  """
  As a human
  I want to perform a search
  So that I can access the world's information
  """, ->

 

And then add one or more scenarios:


scenario "Search for info about Node.js", (browser) ->
  browser
    .given "I am on the homepage", ->
      browser.step(steps.visitHomepage)
    .when "I enter search terms", ->
      browser.typeInElement('q', 'nodejs', using:'name')
    .and "submit the search", ->
      browser.clickElement('btnG', using:'name')
    .then "I see search results", ->
      browser.assertTextPresent('results')
    .and "the results contain information about nodejs", ->
      browser
        .assertTextPresent('node.js')
        .assertTextPresent('nodejs.org')

 

Each scenario has “given“, “when“, and “then” steps.
  • Given: Set up the initial conditions for the scenario.
  • When: Take the action the scenario is testing.
  • Then: Assert the conditions expected after taking the tested action.

Each step contains one or more chained calls to WebDriver commands in the form of browser.someCommand.

Each step (given, when, then) can have an arbitrary number of and steps following it (see above example).

Steps

Often there are steps that are repeated throughout many scenarios, for example “visit homepage” or “sign in”. This kind of functionality can be defined in steps and referred to in scenarios via browser.step():

 

scenario "Search for info about Node.js", (browser) ->
  browser
    .given "I am on the homepage", ->
      browser.step(steps.visitHomepage)

 

Steps are defined in *_steps.coffee files. Multiple steps per file can be defined as follows:

 

steps.visitHomepage = (browser) -> browser.get 'http://www.google.com'

 

Multiple steps files can be created to organize your steps in a manageable way.

Configuration

Configuration is simple and contains:
  • Overall story and Sauce Labs configuration.
  • Browser / OS definitions. Stories will be run against each browser/os configuration defined.

For example:

config.credentials =
  'username':   'sauce_labs_username'
  'access-key': 'sauce_labs_access_key'

config.settings =
  'max-duration': '180'

config.browsers = [
  {
    'platform':     'VISTA'
    'browserName':  'firefox'
    'version':      '7'
  }
  {
    'platform':     'LINUX'
    'browserName':  'firefox'
    'version':      '7'
  }
]

 

Subtitles In Test Videos

One of our favorite features of Sauce Labs is test videos. It is incredibly useful to be able to view a video of a failed test and quickly understand what went wrong. However, one issue that has been raised about the videos is that they could sometimes benefit from some context about what is happening on screen.Well, it just so happens that this context is conveniently codified in the steps of BDD scenarios! So, by flipping a switch in GivenWhenThen, you can add BDD subtitles to your Sauce test videos. When the subtitle flag is passed to the GivenWhenThen runner, subtitle divs will be inserted into the test browser, which will show up in the Sauce Labs test videos and illustrate which of the BDD steps is currently being executed:

 

 

Design Background

In addition to being built on top of Sauce Labs and Selenium 2, GivenWhenThen is heavily influenced by the BDD movement.

While it is also clearly influenced by Cucumber, aficionados will surely notice differences. Most obviously, in GivenWhenThen there is no prose-to-code translation step. Cucumber uses the Gherkin language, which parses the prose into features, scenarios, and steps.

In GivenWhenThen, the DSL is embedded directly in the host language. We do realize there is real benefit to the full Cucumber vision – including Gherkin – but we took a leaner approach to getting the BDD structure without completely porting Cucumber.  To us, the core power of the BDD approach comes from the conceptual framework Dan North developed. Just stating the story and scenario in that formal way and using the “given, when, then” flow gives powerful structure and coherence to your specifications.

Conclusion

GivenWhenThen fills a need we have by providing a Selenium 2 driver and Sauce Labs integration for Node.js, and adding BDD structure to our tests, while staying light and keeping us close to the host language. We hope you find it useful as well!
Share

Comments (You may use the <code> or <pre> tags in your comment)

  1. cd says:

    Suggestion: put your videos on youtube. On my damn tablet can’t play the video above:)

Leave a Comment