Testing the javascript prompt() popup function with Celerity
4 October 2009 in Ruby on Rails, TestingUpdate: 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.
No comments yet.
Leave a comment
Tweets
- study: "In 2 years, work perf of high school recruited devs indistinguishable from more experienced peers"(paraphrase)http://tcrn.ch/daXoHA (link)
- Attention Software Developers: We better be rich before we turn 50 http://tcrn.ch/daXoHA :( (link)
- @integrum was mentioned in the devshow podcast #14 for its hiring practice of having developers download a project from Git and re-factor. (link)
- @supairish good point! (link)
- Like the unobtrusive js in Rails 3 but stuck on 2.3.dumb? Just include Rv3 jquery adapter (a .js file) in ur project! http://bit.ly/bqjVGH (link)
- Introducing netrecorder, my first ruby gem.
3 January 2010 - How to build a ruby gem and host it on gemcutter
3 January 2010 - DEMO!
18 December 2009 - It puts the lotion on its skin
14 December 2009 - Cucumber Code Ratio
14 December 2009
- Tobi:
^^ shit, ok now I see it's not your fault, its (my... - Tobi:
Thanks for this great writeup! btw. you missed... - Chris Young:
Thanks for letting me know. I updated the link.... - maxjgon:
The link of the project in Github is broken!... - Chris Young:
Oh I see . . . Maybe I should check out this so-c...