Testing JavaScript with Jasmine and RequireJS

at June 14th, 2012

Jasmine is a great JavaScript testing framework, but I grew tired of managing the Jasmine gem to work with my JavaScript code in a Rails application. In an application that does not use the asset pipeline, for each new file, you have to add it to your jasmine.yml manifest (either explicitly or using a wildcard include). This means that every file is loaded every time you run your tests, even if you are only running a small batch of tests.

In a parallel endeavor, I grew tired of namespacing my JavaScript code. So, I brought in RequireJS and setup all of my modules to use the AMD format it requires. RequireJS is an asynchronous JavaScript module loader. It allows you to reference your modules directly without attaching them to an object in the global namespace.

However, testing became a problem. I needed a way for Jasmine to play well with RequireJS. I could just require the modules I want inside a test, then use waitsFor (which waits for some condition to be true) to wait for it to be loaded, but that felt rather messy. So, I decided to patch Jasmine’s it and describe methods to do what I wanted.

Adding RequireJS Support to Jasmine

When the jasmine server runs, it exposes a path to your app’s /public folder under the URL route /public. The problem is that you would normally reference those files from your website root. So, your bootstrap file needs to know if it is being used in a testing environment. You can test for that and act accordingly.

jasmine.yml

The jasmine.yml file doesn’t need to include any specific (or wildcarded) spec files.

Patching it and describe

This step involved a lot of work. Essentially, we override the global it and describe methods to support the following.

  • One argument => pending
  • Two arguments => normal behavior
  • Three arguments => requirejs behavior

The standard way to use RequireJS to import a module is to call define ['module1', 'module2'], (module1, module2) ->. So, I decided to follow the same signature in the it and describe calls, making this method signature valid

When using the jasmine gem, the jasmine test runner page is set up to run the tests in a window.onload event handler. The problem here is that we want to wait for our modules to be loaded before registering our specs. The new spec methods will use RequireJS to load the necessary modules asyncronously. If we leave the window.onload handler there, it will run before our modules are loaded and our specs will never be registered.

Thus, we need to wait for our specs to be registered before running the test suite. I handled this with a simple load counter, but there’s probably a race condition with nested module requirements in specs. For now, this works pretty well.

Putting It All Together

Now, I can write specs that look like this!

Giving Back

I considered submitting a pull request to jasmine to add requireJS support, but I’m not completely happy with how it works right now. The more I manipulate jasmine to do what I want, the more I realize I should write my own testing framework (again, although attempt #1 was many years ago and pretty awful). But, I’ll save that for another day.

No Tags


One thought on “Testing JavaScript with Jasmine and RequireJS

  1. Just curious if this is still working for you of if you have evolved it more since Jun.

    by Jon Ross on November 29, 2012 at 1:44 pm

Leave a Reply

Your email address will not be published. Required fields are marked *