Testing the javascript prompt() popup function with Celerity

4 October 2009 in Ruby on Rails, Testing

Update: read my post on how to make this all work with culerity

The solution


require "rubygems"
require "celerity"

browser = Celerity::Browser.new(:browser => :firefox)
browser.webclient.setJavaScriptEnabled true
browser.webclient.setPromptHandler {'Javascript testing is so fun'}
browser.goto "localhost:3002/test.html"
browser.link(:text, 'hi').click
puts browser.document.asXml

There’s nothing worse than watching a grown programmer cry. Luckily I was mostly alone when it happened. My current project is pure testing. We have a client who has an existing app that is fairly robust, however there is no testing so they are afraid to make changes. In order to get their groove back, they came to Integrum hoping we could provide full testing coverage.

I’m a big fan of cucumber testing. It tests the full stack and so I’m able to achieve better coverage with less test code. There is definitely some debate as to whether cucumber should replace unit testing or other more granular testing frameworks - using a full stack integration testing framework has very little impact on the way you write your code - cucumber makes it easy to test spaghetti code. To test well with Rspec, however, it really helps to have very DRY, declarative code, which is a great thing. But let’s put this debate aside for now and look at what made me cry.

Out of the box, cucumber comes with webrat. Webrat simulates a browser for you, allowing you to test your code as if you were running it in a real browser. It is much faster than doing integration tests on a real browser and has a great interface for navigating the dom. The problem is that it doesn’t test Javascript.

Javascript testing! It’s enough to make a shy, bald Buddhist repent and commit a mass murder. Well not that bad, honestly, but its a great song if you can stand Morrisey. If you want to test javascript you have to abandon webrat (at least for the scenario you are testing that is implemented with Javascript) and use something a little bit more heavy duty like Selenium or Celerity, which is my choice for this project. Celerity is a jruby wrapper of Java’s htmlunit - a “headless browser”, which goes further than webrat in that it supports Javascript calls and Ajax (haven’t had to test ajax yet, please send your prayers my way). Later I’ll do a post on how to set up Cucumber to work with Celerity and webrat but right now I need to get something off my chest.

How do you test calls to Javascript prompt() ? The prompt function shows a dialog box that asks for user input and returns the value to the calling function. When I am running my tests, I want to be able to specify a value for the prompt dialog as I move through my cucumber steps. The documentation on doing this is abysmal and it seems to me that it doesn’t work at all! Here’s some sample HTML I want to test:

<a href="#" onclick="changeThePage()">hi</href>

<script>
  function changeThePage() {
    answer = prompt('what up?')
    document.body.innerHTML = answer
  }
</script>

This code produces a link that will prompt a user for input when clicked. Whatever the input is will be used to replace the html in the document body.

After banging my head trying to get this work in cucumber, I switched over to a jruby prompt and tested celerity directly. This is what SHOULD work according to the docs:


# THIS CODE DOES NOT WORK
require "rubygems"
require "celerity"

browser = Celerity::Browser.new(:browser => :firefox)
browser.webclient.setJavaScriptEnabled true
browser.add_listener(:prompt) {'Javascript testing is so fun'}
browser.goto "localhost:3002/test.html"
browser.link(:text, 'hi').click
puts browser.document.asXml

However, instead of my message replacing the HTML, I get this horrible bit of news:


<html>
  <head/>
  <body>
    #
    <proc:0x124805/>
  </body>
</html>

So the banging of my head and the welling up of tears and the lonely wife and the unfed dog, etc. I’m obsessed. Finally I decided to go under the hood - straight to the source - htmlunit. The documentation there was also scary but after trying several incantations I finally arrived at the working code:


require "rubygems"
require "celerity"

browser = Celerity::Browser.new(:browser => :firefox)
browser.webclient.setJavaScriptEnabled true
# add_listener doesn't seem to work
# browser.add_listener(:prompt) {'Javascript testing is so fun'}
browser.webclient.setPromptHandler {'Javascript testing is so fun'}
browser.goto "localhost:3002/test.html"
browser.link(:text, 'hi').click
puts browser.document.asXml

So the moral of the story - if something isn’t working in celerity the way you expect, learn htmlunit. And maybe its okay for programmers to cry.

Tags: , , , , , , ,

4 October 2009 Ruby on Rails, Testing

No comments yet.

Leave a comment



Tweets

  • Chris Young:
    Oh I see . . . Maybe I should check out this so-c...
  • Nicholas Orr:
    Oh I see. I've read it a bit closer and there are ...
  • Chris Young:
    Thanks Clayton, I updated the post....
  • Clayton:
    One problem I ran into using this guide is that yo...
  • Chris Young:
    @Nicholas, I didn't go manual, I used 'echoe' - ma...