Javascript BDD with Cucumber and Harmony

Inspired by tooky‘s recent post Exploring Harmony for javascript BDD with RSpec i have become determined to become better at writing javascript in a BDD kind of way.

On Monday we were privileged to have Corey Haines visit Eden for the day. I paired with Corey for a couple of hours learning about BlueRidge for unit-testing javascript classes in a Rails application. I liked what i learned but i am disappointed by the need to maintain HTML fixtures. I would like to run the specs directly on my application.

I was pairing with Tris today and we really wanted to run javascript straight from Cucumber scenarios, so we had another look at Harmony. The first thing we noticed that it needed to load a file (rather like a fixture), which we didn’t like very much. We went to see how HolyGrail does it.

Maybe it’s because we’re using Capybara not Webrat, or maybe it’s because we did something wrong, but we couldn’t get HolyGrail to work right. However, a quick peek at the source code gave us a few clues. We pulled out and tweaked the following:

def js(code)
  @__page ||= Harmony::Page.new(page.body.to_s)
  @__page.execute_js(code)
end

This worked pretty nicely for a step involving simple javascript, like:

Then /^the page is titled "([^\"]*)"$/ do |title|
  js('document.title').should == title
end

It was actually pretty exciting when we first saw that working! On to something more meaningful …

  Scenario: Use javascript to hide a box
    Given I am on a page with a box that can be hidden
    When I use javascript to click "Hide"
    Then the box should be hidden

Clicking the link with javascript actually wasn’t hard:

When /^I use javascript to click "([^\"]*)"$/ do |text|
  js("$('a:contains(#{text})')").click
end

We used jQuery to find the right link and click it using Harmony. Harmony sends the ‘click’ method straight through to the javascript object, which is pretty cool.

Ensuring the box disappears was a little more tricky. For the moment we’re just checking that the contents becomes empty.

Then 'the box should be hidden' do
  js("$('.hide_box')").html.should be_nil
end

Sure enough, when we plug in the unobtrusive jQuery code to bind the click and remove the box, the feature passes! Alright, this is a very small step down a long road, but to me it is very exciting indeed!

Next steps: we have already begun writing a Capybara driver to run Harmony. So that we don’t have to write a separate step definition When I use javascript to click “Hide” but we simply use the standard When I follow “Hide” and we tag the scenario with @harmony to use the alternative driver. That will first attempt to click it with javascript and, if nothing happens, it will follow the link in the normal way. We will also use the driver to handle when the @__page cached copy gets refreshed.

An important next step is make it a proper integration test, interacting with the full stack, such as clicking something which triggers an AJAX request to the server which must run a bit of code and send the response back to the page. I can foresee this presenting some challenges, we’ll see!

Exciting things are happening, and this is just the beginning! Web development these days is all about standing on the shoulders of giants. This is only possible thanks to the great work already being done by Harmony, Johnson and SpiderMonkey. I’m hoping that other people will become inspired by the possibilities and take this further. Watch this space for more news!

Advertisements

4 comments on “Javascript BDD with Cucumber and Harmony

  1. Pingback: uberVU - social comments

  2. Thanks for the write-up. This is great, and I’m really interested to see where this goes.

    Do you think this approach compliments or replaces testing through the browser (with Selenium, etc)?

  3. Hi Louis, i think it is an alternative to Selenium. Maybe a bit easier for continuous integration testing, once we have it all set up.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s