Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save nackjicholson/7ccdbb8030844b4e404a to your computer and use it in GitHub Desktop.
Save nackjicholson/7ccdbb8030844b4e404a to your computer and use it in GitHub Desktop.
The Best Way to Test RequireJs Code with Mocha, PhantomJs and Grunt.

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.

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

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

#!javascript
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:

#!javascript
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.

#!bash
$ 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

#!javascript
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:

#!bash
$ grunt shell:mocha-phantomjs

To start the watcher:

#!bash
$ 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

@dschinkel
Copy link

can you talk a little more about this: bower_components/requirejs/require.js

@kettanaito
Copy link

kettanaito commented Oct 3, 2017

@dschinkel That is just including of RequireJS from Bower.
You can include it from any package manager you prefer (i.e. NPM).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment