SmartLogic Logo (443) 451-3001

The SmartLogic Blog

SmartLogic is a web and mobile product development studio based in Baltimore. Contact us for help building your product or visit our website to learn more about what we do.

Testing AJAX with Test::Unit

October 8th, 2010 by

If you want real end-to-end testing of a page with functioning AJAX, use Selenium. But I was interested in doing just a bit of JS speccing to make sure that the AJAX routes I called worked and that the data that came back fit the JS that I had written.

So, I figured with a little capybara and a little therubyracer, I could test my javascript with real route calls. Let’s check it out.

The Javascript I want to test:

var dataObject = {};
var getRemoteData = function() {
  $.getJSON('/remote_path.json', function(data) {
    dataObject = $.parseJSON(data);
  });
}

We will pretend that hitting /remote_path.json returns the following response in JSON:

{ "my_information": "my response data" }

I want to test:

  1. That /remote_path.json is accessible and returns information
  2. That dataObject is populated with a Javascript Object containing the params I pass down

Here is my commented testing code:

  test 'get some information via ajax' do
    # Create a new JS Context. :with => self means that
    # the global namespace is the current context
    js = V8::Context.new(:with => self)

    # Load up our JS file
    js.load(File.join(Rails.root, 'public', 'javascripts', 'application.js'))

    # Define a mock method for getting JSON data
    def getJSON(url, callback)
      # When the JS wants some data, get it for real w/ capybara
      visit url
      # And call the JS function passed in (ruby => js)
      callback.call(page.body)
    end

    js.eval %{
      /* Mock out jQuery */
      var $ = {};

      /* Setup the mock in the right place (JS => ruby) */
      $.getJSON = getJSON; 

      /* Mock out jquery parseJSON to call ruby JSON.parse
         Since the args are the same, it is plug and play!
         (JS => ruby) */
      $.parseJSON = JSON.parse;

      /* Trigger our JS */
      getRemoteData();

      /* Assert what we expect (JS => ruby) */
      assert_equal(" ", dataObject.access_key);
    }
  end

This is not an example of an incredibly useful test, but I found the ability to bind back and forth easily between ruby and javascript to be mind-blowingly incredible. I mean, look at that last line, where I call assert and pass a javascript object to it!

Huge thanks to Charles Lowell (cowboyd) for his hard work on therubyracer.

Enjoy the weekend!