Archive for June, 2009

03
Jun
09

Javascript testing in Ruby with Selenium

InvisibleHand, a Firefox plugin that checks alternative prices as you are shopping online and alerts you if a bargain is found, consists of client part (the extension itself, in Javascript) and server part (the database of products, in Ruby). In order for the extension to always stay up-to-date it downloads pieces of JS code with price scraping logic from the server when it starts. I look after the JS code updating it whenever the layout of pages on retailers’ websites changes.

The challenge was to test this stuff automatically because the JS code makes part of a Ruby project and I want to ‘rake test’ it all. Getting a JS engine in my project would be an overkill, so I resorted to Selenium.

So, how to test a piece of Javascript code stored in your Ruby project?

First, download Selenium :)

Then, launch the server
java -jar selenium-server.jar

Then, install selenium client
sudo gem install selenium-client

In your unit test, launch Selenium:

attr_reader :browser

def setup
  @browser = Selenium::Client::Driver.new "localhost", 4444, "*firefox", "http://www.google.com/", 10000
  browser.start_new_browser_session
end

def teardown
  browser.close_current_browser_session
end

 

The base address that you use to launch Selenium (google in this example) doesn't matter as long as your code isn't doing cross-domain requests.

Then, in your test:

def test_js
  str = "Ah, Satan sees Natasha".to_json
  js = %Q[
    function reverseString(str) {
      var rstr = '';
      for (var i=str.length-1; i>=0; i--)
        rstr += str.charAt(i);
      return rstr;
    } 
    reverseString(#{str});
  ]
  result = browser.js_eval(js)
  assert_equal 'ahsataN sees nataS ,hA', result
end

A few comments:

  1. The conversion to json is not necessary in this example but if you are sending an array of data or strings with characters which should be escaped, use json.
  2. js_eval() function returns the result of the last line in the script.
  3. If you need to return anything more complex than a string or a number, consider converting your data to json before returning and then parsing it in ruby (that's what I'm doing in my tests but I omitted it here for clarity)

The problem with this code is that is damn slow because a new instance of Firefox is started for this test and it's not fast. However, it's better than no tests at all and if you don't need to start a new instance of firefox for every test, it's actually tolerable.
Loaded suite /Users/evgeny/invisiblehand/test/selenium/js_test
Started
.
Finished in 7.403807 seconds.

1 tests, 1 assertions, 0 failures, 0 errors

Good luck!




June 2009
M T W T F S S
« May    
1234567
891011121314
15161718192021
22232425262728
2930