The Best Way to Test RequireJS code with Mocha, PhantomJS, and Grunt.

code slug

In my last blog on this topic, I claimed that the choice to use RequireJS handcuffed you to the less than awesome experience of using a browser based test runner. I was wrong! Surprised? Yeah, me neither.

I describe my ideal testing experience to be this: Anytime something changes, my personal robot army runs unit tests and tells me what I broke without me having to lift a god damned finger. I’m a programmer, I’m lazy, that’s why I do this; so I can automate my life, my code, my income, and just retire to an island while my robots run shit. I’m not quite there yet, but this is here to share with you, how I finally figured out step 1337 of this plan – Automated Javascript Unit Testing.

rooster skull line

Get Some Background

In this post, I’m not planning to go deep into how to write unit tests, mock, spy, or any of that. This is going to be about where and how the tests are run, not how to write them. If you’re just getting started with testing your RequireJS modules, check out amd-testing and RequireJS + Chai + Mocha. These are both superb at getting you up and running.

I’m going to help you refine upon those two brilliant examples, by introducing you to some tools built by some other brilliant people.

Additionally, if you want to see an example of my process in action with actual tests, backbone-gcl can serve as a simple, yet complete, real world reference. I highly encourage you to skim through it, and ask me any questions you may have.

mocha-phantomjs, PhantomJS, and Grunt

PhantomJS is a Headless Webkit with a javascript API. What that means is, its a web browser, that you can’t see. The library mocha-phantomjs is a PhantomJS Driver that helps you run your HTML mocha tests on the command line. With these two projects together we’re going to be able to see the output of an HTML mocha test runner in the terminal.

$ mocha-phantomjs http://localhost:8000/testrunner.html

Screen Shot 2013-05-11 at 10.05.48 AM

Still physically switching applications to run a command everytime we want to see our test output. AAARG! That’s where we bring in GruntJS, grunt-contrib-watch, and grunt-shell.

Mocha Test Runner RequireJS Style

A test runner is an HTML page where your tests can run and report in the browser. In the backbone-gcl project the tests can be run by visiting http://localhost:8000/testrunner.html. My testrunner.html calls a RequireJS config file to resolve my javascript dependencies and initialize the tests. What we’re going to do is take this exact same setup and use PhantomJS to headlessly load the specrunner and return test output to the terminal.

testrunner.html

<html>
  <head>
    <meta charset="utf-8">
    <title>TESTRUNNER backbone-gcl</title>
    <link rel="stylesheet" href="bower_components/mocha/mocha.css" />
  </head>
  <body>
    <div id="mocha"></div>
    <script type="text/javascript" src="bower_components/mocha/mocha.js"></script>
    <script type="text/javascript">
      // MOCHA SETUP
      mocha.setup('bdd');
    </script>
    <script data-main="test/test.config.js" src="bower_components/requirejs/require.js"></script>
  </body>
</html>

test.config.js

require.config({
  // ...paths and stuff
});

require([
  // FILE(S) BEING TESTED
  'test/test.backbone-gcl'
], function() {
  // INITIALIZE THE RUN
  mocha.run();
});

The only thing that needs to change to accommodate mocha-phantomjs is the mocha.run() line above. Make it:

if (window.mochaPhantomJS) { mochaPhantomJS.run(); }
else { mocha.run(); }

With that conditional you can now view the tests via phantomjs or by navigating normally to the testrunner. Try running the tests on the command line.

$ mocha-phantomjs http://localhost:8000/testrunner.html

Watching for file changes with Grunt

There is a lot of good documentation about how to configure a GruntFile and install grunt plugins on the http://gruntjs.com website. All you need to know right now is, that there IS a Gruntfile and this is how set it up to run mocha-phantomjs everytime a javascript file changes.

Gruntfile.js

module.exports = function(grunt) {
  grunt.initConfig({
    shell: {
      'mocha-phantomjs': {
        command: 'mocha-phantomjs -R dot http://localhost:8000/testrunner.html',
        options: {
          stdout: true,
          stderr: true
        }
      }
    },
    watch: {
      jsFiles: {
        files: ['**/*.js'],
        tasks: ['shell:mocha-phantomjs']
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-shell');
}

To run the tests once:

$ grunt shell:mocha-phantomjs

To start the watcher:

$ grunt watch

Go change any .js file and you’ll see a dot matrix report of the tests in the terminal. This is the holy grail of RequireJS unit testing as far as I know. Thanks to the contributors on all of these amazing projects! Enjoy!

Real Test Example: backbone-gcl

Please go check out testrunner.html, the test/ directory, and testing documentation for backbone-gcl. Looking around in that project will help you figure out how to write mochajs specs in your requirejs projects. There are even some tweeks to the Gruntfile to make it able to run tests on travis-ci.

If you have anything, and I mean anything, to say, please comment or hit me on twitter @nackjicholsonn

Will VaughnThe Best Way to Test RequireJS code with Mocha, PhantomJS, and Grunt.

6 Comments on “The Best Way to Test RequireJS code with Mocha, PhantomJS, and Grunt.”

  1. Jay

    Excellent insight, I didn’t even think to combine the power of grunt and phantomJS.

    Great peice

  2. treshugart

    I found the Mocha runners available for Grunt to be frustrating especially when a lot of async behaviour is involved in the tests (RequireJS, etc) so I wrote http://github.com/treshugart/grunt-ghoul. You ad a single line of code to your runner and it allows you to run your tests in the browser as you normally would or it integrates seamlessly with grunt allowing them to be run by your CI server.

  3. Chris Luebcke

    Absolutely invaluable in getting this set up. Just wanted to say thanks.

  4. Pingback: Roll Your Own Yeoman Generators

  5. Pingback: Testing Javascript with RequireJS modules and Mocha.

Leave a Reply

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