Setting Up a Jasmine Unit Testing Environment with Testem

Jasmine Unit Testing with TestemEveryone knows now that unit testing is good and that they should do it, but it’s not exactly simple to get started, but once you’re going, it’s pretty simple and highly valuable. But how do you get started? I’ll show you a great setup for Jasmine to get you up and running with unit testing and doing it with style with Testem. Testem and Jasmine come together to make unit testing fun and simple.

What is Testem?

Testem is a command line tool that runs on Node.js (what doesn’t run on Node.js these days?). It allows you to launch unit tests for practically any framework straight from the command line. These tests are then run in every single browser you’ve specified – either through configuration or arguments on the command line.

Once Testem is running and the browsers are launched, every time you save a file, the browsers (known as “launchers” by Testem) will automatically refresh and run all of your tests again. Not only are the results of the testing shown in each of the launchers, Testem provides a clean, tabbed interface within the console to display the results returned from each of the launchers. This means you can keep the browsers in the background and still see all the results of all of the tests. See the image below to see what I mean.

Testem Command Line Interface

Testem command line interface. Click to enlarge.

This interface is controlled with the keyboard. You can use the left and right arrows to switch between tabs, and as the note at the bottom of the above screenshot says, you can hit Enter to rerun the tests or you can quit with q. You can read more about the keyboard controls and everything else related to Testem at their Github repository. You can also watch a great introduction to Testem, courtesy of Jeffrey Way from Nettuts+, over on the Nettuts+ website.

For right now, all you really need to know is that you can install Testem with NPM: npm install testem –g. Now you can run testem straight from the console to start testing.

Organization: File and Folder Structure

Now that we have Testem installed, we need to talk about setting up the project to use Testem and Jasmine. I’ve actually got a little repository up on Github with my Jasmine-Testem Boilerplate. You can just clone that repository to get started. I’ll explain a bit about it here first, though. Here’s what the main file structure looks like:

root
|- js/
|   |- lib/            // All third party scripts
|   |- models/         // Backbone models
|   |- routers/        // Backbone Routers
|   |- templates/      // Underscore/Handlebars templates
|   |- views/          // Backbone Views
|   |- app.js          // Marionette application
|   |- config.js       // RequireJS configuration
|   `- main.js         // Main file for bootstrapping/starting the app
|- test/
|   |- helpers/        // Any objects/functions to help with testing
|   |- lib/            // Jasmine's library files
|   |- spec/           // All tests
|   |- index.html      // HTML page to open in browser for running tests
|   `- spec-runner.js  // loads tests and configures RequireJS
`- testem.yml          // Testem configuration

You may see some notes mentioning Backbone and RequireJS. Indeed, this boilerplate is designed to get me up and running with a Backbone.Marionette/TwitterBootstrap/RequireJS application quickly and have it ready to test from the start. Some quick notes: /js/config.js and /test/spec-runner.js both have exactly the same RequireJS configuration in them except:

  • spec-runner.js includes a couple path aliases specifically for testing
  • spec-runner.js specifies a baseUrl, which is the /js/ folder

Everything related to testing is in the /test/ folder and everything related to the actual application (at least JavaScript files and templates) is in the /js/ folder. You might want to change this file structure, but you’ll want to make a couple configuration changes in spec-runner.js and testem.yml if you do.

Setting Up Jasmine

We need to set up the HTML file that runs the Jasmine tests. Within the boilerplate that I mentioned above, everything is already configured, but I would like to explain some of the choices and how things work.

First, Testem is able to be configured in a way that it’ll create its own HTML file to run the tests in just by specifying where the source JavaScript files are and where the spec files are. There are two reasons that I create my own HTML file rather than taking that route:

  1. My applications utilize RequireJS, and I don’t know any other way to get Testem to use RequireJS correctly.
  2. If we have our own HTML file, we can run the tests without Testem. This is great if a project is cloned to a machine that doesn’t have Testem – or even Node.js – installed. I set things up so that the tests will run just as well with or without Testem.

Let’s take a look at the HTML file closely to see what I’ve done:

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Jasmine Spec Runner</title>

    <link rel="shortcut icon" type="image/png" href="lib/jasmine_favicon.png">
    <link rel="stylesheet" type="text/css" href="lib/jasmine.css">
</head>

<body>
    <!-- sandbox that tests can use for things that require the DOM -->
    <div id="sandbox"></div>

    <script src="lib/jasmine.js"></script>
    <!-- Pull in Testem helper when using Testem -->
    <script src="/testem.js"></script>
    <script src="lib/jasmine-html.js"></script>
    <!-- Using RequireJS. Specs and config are done in spec-runner.js -->
    <script type="text/javascript" src="../js/lib/require.js" data-main="spec-runner"></script>
</body>
</html>

This is mostly just normal stuff. If you look at jasmine.css, it’s altered from the standard CSS. I think mine looks nicer, and it also hides all of the individual specs – except failed specs. If you hover your cursor over a suite, all of its specs slide down to reveal the entire list. This shrinks down the amount of space required to list the specs considerably.

New CSS for Jasmine

My Jasmine CSS. Hover over a suite to see its specs. Click to enlarge this image.

The rest of the noteworthy stuff is in the body. First, there is a “sandbox” element. If a unit test requires the use of the DOM, make sure it’s done in here and then cleaned up when you’re done. Next, we pull in the main jasmine.js file, testem.js, and then jasmine-html.js. These three files are loaded outside of RequireJS’s mechanisms for a couple reasons.

  • Order matters. RequireJS will run dependent files in the order they are finish downloading, not in the order specified in the array, so we need to make sure we have these in the right order.
  • testem.js isn’t always available. This file is made available only when Testem is running the tests and reports the results between the browser and the console. If we tried loading testem.js via RequireJS, then if we opened the HTML file straight in the browser without Testem, it would break and the tests wouldn’t run.

Next we load in require.js, which, due to the data-main attribute of the script tag, loads spec-runner.js. So, let’s take a look at spec-runner.js.

require.config({
    baseUrl: "../js",
    urlArgs: "cb=" + Math.random(),

    paths: {
        // Libraries.
        jquery: "lib/jquery",
        underscore: "lib/lodash",
        backbone: "lib/backbone",
        marionette: "lib/backbone.marionette",
        // Marionette's extra dependencies
        "backbone.babysitter": "lib/backbone.babysitter",
        "backbone.eventbinder": "lib/backbone.eventbinder",
        "backbone.wreqr": "lib/backbone.wreqr",
        // RequireJS Plugins
        tpl: "lib/require.tpl",
        // jQuery Plugins
        bootstrap: "lib/bootstrap",

        // Jasmine Testing: Folder Aliases
        spec: "../test/spec",
        helpers: "../test/helpers"
    },

    shim: {
        "backbone": {
            deps: ["jquery", "underscore"],
            exports: "Backbone"
        },

        "bootstrap": ["jquery"]
    }
});

require([], function(){
    var jasmineEnv = jasmine.getEnv();
    var htmlReporter = new jasmine.HtmlReporter();

    jasmineEnv.addReporter(htmlReporter);

    // Add links to the spec files here
    var specs = [];
    specs.push("spec/example_spec");

    // Execute specs
    require(specs, function(){
        jasmineEnv.execute();
    });
});

There’s a lot to see here. At the top we’re configuring RequireJS. You’ll notice that we set the baseUrl to the /js/ directory so that the source files will work the same way they did before. Also, we added urlArgs in there to add a random query string so that we don’t run into any cached files. The rest of the configuration is normal path stuff for the libraries and matches the config.js file found in the js folder, except you’ll see near the bottom of paths that I also added the spec and helpers folders so that it’s easier to pull those in.

After the configuration we move on to start setting up Jasmine the same way you normally would. Then we have the specs array. This array holds all the string paths to all of the specs you wish to run. Just keep pushing more on. Then we require the specs and run them.

Configuring Testem

Now we need to configure Testem so it knows what to files to load. Take a look at the testem.yml file in the root directory.

framework: jasmine
src_files:
- js/**
- test/**
test_page: test/index.html
launch_in_dev:
- Firefox

The first thing you’ll notice is that I’m using the YML format instead of JSON. The only reason for that is that I was having difficulties getting the JSON configuration to work on my Windows machine. It seems to have something to do with saving to UTF-8 or something. In any case, when Testem was reading the configuration file, it was finding some extra characters that weren’t actually in the file. If I used Notepad, made the .yml file and explicitly saved it as UTF-8 (instead of the default ANSI), it worked. Otherwise, I kept running into troubles.

Anyway, the first property is framework. The default is Jasmine, so this isn’t necessary, but I put it in here anyway. Next we have src_files. This lets Testem know where the source and spec files are. Normally, Testem would just load all of these files up (in the order specified, so the js/ files would be before the test/ files) and put them into the HTML file itself, but since we have our own HTML file, as specified by the next property: test_page, it just watches these files for changes so it can rerun the tests.

As I said test_page lets Testem know that we’re using our own HTML page and points Testem to where it is. Finally, we have launch_in_dev, which controls which launchers are used when you run Testem in your “dev” environment. Check out the docs if you want to know more about these launchers and running tests in environments other than just “dev”. I’m just using Firefox here, but you can easily change this to whatever browser you tend to develop in.

Run It

Now’s the fun part: we get to run Testem. In your console, go to the root directory and type in testem. If you’re using the boilerplate, you should see a really short test suite that passes. Make some changes to any of the files in the /js/ or /test/ folders and the tests should automatically refresh for you too!

Conclusion

Testem can make testing a lot more fun, but you still have to get it set up first. I hope this helped a few of you out and maybe even will get someone new onto the unit testing train. If you still need a little more shoving, next week’s article will show you how to write tests with Jasmine, so you won’t have any more excuses. It’s too easy not to try. God Bless and happy coding!

About the Author

Author: Joe Zim

Joe Zim

Joe Zimmerman has been doing web development ever since he found an HTML book on his dad's shelf when he was 12. Since then, JavaScript has grown in popularity and he has become passionate about it. He also loves to teach others though his blog and other popular blogs. When he's not writing code, he's spending time with his wife and children and leading them in God's Word.


  • Valentin Vago

    I used something like that to deal with requireJS and jasmine testing:

    describe(“My site”, function() {
    it(“should load”, function(done) {
    var loaded;

    // obviously, we need “require”
    expect(require).toBeDefined();

    // my tests are in a “tests” directory,
    // my scripts are located in a “src” directory
    // we need to adjust that
    require.config({

    baseUrl: ‘/src’
    });

    runs(function() {
    require(['javascripts/foundation/jquery'], function(jq) {
    expect(jQuery).toBeDefined();
    loaded = true;
    });

    });

    // called to check if the loading process is over
    // the last argument is the timeout
    waitsFor(function() {

    return loaded;
    }, “with requirejs”, 500);

    });

    });

  • Bruno Barros

    Nice tip! Works great for me!

  • keripix

    I’ve just read your article, and used testem straight away. And boy, it’s awesome. very easy to setup. Thanks for article.

    Btw, in the testem readme.md, it says that if we use the “test_page” key, we dont need the “framework” and “src_files” keys, as it will detect them automatically.

    • http://www.joezimjs.com Joe Zimmerman

      Thanks for that tip. I wonder if that has changed or if RequireJS makes it impossible for it to find the files it needs, because I seem to remember it not working if I skipped the src_files.