Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
JavaScript Testing with Grunt, Mocha and Chai

JavaScript Testing with Grunt, Mocha and Chai

In the following post I would like to introduce one way how you can setup your testing workflow for JavaScript development. The central components in the testing environment are Grunt, Mocha and Chai that I will cover from the introduction and installation of each component to the cooperation of all components for the execution of tests.

If you are already an experienced Grunt user and just look for the Gruntfile.js and the Mocha / Chai setup just skip the central components section and skip to the installing components part.

You can find the sample project with all code at GitHub on: https://github.com/maicki/sample-js-testing-grunt-mocha-chai

Central Components

As mentioned in the introduction to this post, the central components of this post are Grunt, Mocha and Chai. In the following section I would like to explain these components a bit more in details, so you know what task each components is used for.

Grunt

Built on top of Node.js, Grunt is a task-based command-line tool that speeds up workflows by reducing the effort required to prepare assets for production. It does this by wrapping up jobs into tasks that are compiled automatically as you go along. Basically, you can use Grunt on most tasks that you consider to be Grunt work and would normally have to manually configure and run yourself. What kind of tasks? Well, the list is exhaustive. Suffice it to say, Grunt can handle most things you want to have within your JavaScript workflow, from minifying to concatenating JavaScript as well as running Mocha tests automatically what is pretty handy for our use case.

Mocha

Mocha is a feature-rich JavaScript test framework running on Node.js and the browser, making asynchronous testing simple and fun. It does just about everything a JavaScript developer needs, and yet remains customisable enough to support both behaviour-driven and test-driven development styles. Mocha tests run serially, allowing for flexible and accurate reporting, while mapping uncaught exceptions to the correct test cases.

Chai

Chai is a BDD / TDD assertion library for node and the browser that can be delightfully paired with any javascript testing framework.

Chai aims to be an expressive and easily approachable way to write assertions for JavaScript project testing. Developers have already started expanding on Chai’s available language through plugins such as spies, mocks/stubs, and jQuery support.

Interesting is that the motivation for Chai came about with the release of Mocha. At the time, there was no apparent assertion library to pair with it that would allow for the same assertions to be used on both server and client with the inherent simplicity that Mocha provides.

Why Chai instead of Node.js assert module?

It's not necessary to use Chai as assertion library instead of Node.js assert module, if you only want to run your tests within the terminal. As I need to run Mocha tests within the browser, to test things like the HTML5 Filesystem API, I need an extra assert library and so I decided to use Chai for that.

Preparing of the sample project

To prepare our sample project just create a folder with the name: "sample-testing-project". Within this project folder we will execute all further commands if no other instructions are given.

Installing components

All three components need Node.js installed on your machine. The installation of node should not be the topic of this post. You can find a detailed Node.js installation instruction over at Node.js wiki on GitHub: https://github.com/joyent/node/wiki/Installation

Once Node.js is installed, run the following command to install Grunt globally:

$ npm install -g grunt-cli

To make sure Grunt has been properly installed, you can run the following command:

$ grunt --version

The output should look like the following (the version number can differ):

grunt-cli v0.1.11

In the next step we have to create a package.json file within the project directory. The JSON file enables us to track and install all of our development dependencies. This is useful when someone else clones our repository; instead of tracing down our dependencies manually, they can simply run "npm install" and NPM will download the correct version of all dependencies fro them so anyone who works on the project will have the most current dependencies, which ultimately helps to keep the development environments in sync. The package.json should contain:

{
  "name": "sample-testing-project",
  "version": "0.0.1",
  "devDependencies": {
    "grunt": "latest"
  }
}

After creating the package.json file you have to execute the following command to install the currently listed dependencies for your project:

$ npm install

All dependency files will be placed within a node_modules within your project folder.

With the knowledge, how to install npm modules, it's easy to install Mocha and Chai with the following commands:

$ npm install mocha --save-dev
$ npm install chai --save-dev

Using the --save-dev flag will cause npm to automatically add this package to the dev dependencies in your package.json file. This is a handy little trick to save you some time and make sure that you don’t forget to update the file yourself.

As we learned from the introductory part, Grunt is basically only a task runner to run tasks like minifying JavaScript or like in our case, running tests. For most of the tasks, Grunt plugins already exist. Let's search on npm for plugins we could use to run Mocha tests:

$ npm search gruntplugin mocha

The shortened version of the output will look like the following:

...
grunt-jscover         Grunt task for jscover
grunt-jscoverage      Grunt task for jscoverage; which will parse your source code and generate an instrumented
grunt-mocha           Grunt task for running client-side Mocha specs in PhantomJS
grunt-mocha-appium    Run functional Mocha tests with wd and Appium.
grunt-mocha-browser   Grunt task for run mocha test suite in browser
....

It seems like we already found a good candidate for that: grunt-mocha. Let's install that via npm and add it to the dev dependencies.

npm install grunt-mocha --save-dev

After installing all necessaries components, your packaged.json should look like the following (version number can differ):

{
  "name": "sample-testing-project",
  "version": "0.0.1",
  "devDependencies": {
    "grunt": "latest",
    "grunt-mocha": "~0.4.6",
    "mocha": "~1.14.0",
    "chai": "~1.8.1"
  }
}

Create Gruntfile.js

Now it is time to create the Gruntfile. A Gruntfile is a JavaScript file that Grunt leverages to understand your projects tasks and configuration. It is essentially made up of a wrapper function that takes Grunt as an argument. When you run "grunt" from the command line, Grunt will recurse upwards till it finds your Gruntfile. This functionality allows you to run Grunt from any sub directory of your project.

The basic Gruntfile.js looks like the following:

// Gruntfile.js
module.exports = function(grunt){
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json')
  });
  grunt.registerTask('default', ['mocha']);
};

You are now set up to run Grunt from the command line at the root of your project. But if you do so at this stage, you will get the following warning:

$ grunt
Warning: Task "mocha" not found. Use --force to continue.

Aborted due to warnings.

We’d get this because we haven’t specified any tasks or dependencies yet other than Grunt. Let's change this and add the Mocha task:

// Gruntfile.js
module.exports = function(grunt){
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),

    // Mocha
    mocha: {
      all: {
        src: ['tests/testrunner.html'],
      },
      options: {
        run: true
      }
    }
  });

  // Load grunt mocha task
  grunt.loadNpmTasks('grunt-mocha');

  grunt.registerTask('default', ['mocha']);
};

Within the updated Gruntfile.js we have now added the grunt-mocha task as well as the information for executing the Grunt Mocha task within Grunt. As you can see from within the file the next step is to create a folder that is called "tests". Within the tests folder create a file called testrunner.html with the following content:

<html>
<head>
  <meta charset="utf-8">
  <title>Mocha Tests</title>
  <link rel="stylesheet" href="../node_modules/mocha/mocha.css" />
</head>
<body>
  <div id="mocha"></div>
  <script src="../node_modules/mocha/mocha.js"></script>
  <script src="../node_modules/chai/chai.js"></script>

  <script>
    mocha.setup('bdd')
    mocha.reporter('html');
  </script>

  <!-- Tests -->
  <script></script>

  <script>
    // Only tests run in real browser, injected script run if options.run == true
    if (navigator.userAgent.indexOf('PhantomJS') < 0) {
      mocha.run();
    }
  </script>
</body>
</html>

Now, everytime you type the command "grunt" within the terminal, Grunt will run Mocha and Mocha will run the testrunner.html.

Add Tests

Finally to test our setup, we will just add a sample tests. Create a new file within your test folder called tests.js and add the following test to the file:

// tests.js
describe('Array', function(){
  describe('#indexOf()', function(){
    it('should return -1 when the value is not present', function(){
      chai.assert.equal(-1, [1,2,3].indexOf(5));
      chai.assert.equal(-1, [1,2,3].indexOf(0));
    });
  });
});

Next step is to add the tests.js file to our testrunner.html. The new testrunner.html part should look like the following:

...
<script>
  mocha.setup('bdd')
  mocha.reporter('html');
</script>

<!-- Tests -->
<script src="tests.js"></script>
...

If you run the "grunt" command in the terminal you should see the following output and you be ready to add further tests to the tests.js or split tests up in more files and add this to the testrunner.html:

$ grunt
Running "mocha:all" (mocha) task
Testing: tests/testrunner.html

  ․

  1 passing (107ms)

>> 1 passed! (0.11s)

Done, without errors.

Furthermore you can see the Mocha test results within the browser, if you open the tests/testrunner.html file within your browser of choice.

References:

@steven-ferguson

This comment has been minimized.

Copy link

commented Dec 12, 2013

Very informative and helpful!

One error in the Gruntfile.js. The path for testrunner.html should be src: ['tests/testrunner.html'],

@kentcdodds

This comment has been minimized.

Copy link

commented Dec 15, 2013

Thanks! Using this to refactor my library GenieJS.

@andrewmartin

This comment has been minimized.

Copy link

commented Feb 17, 2014

This is awesome. Thank you for sharing!

@andrewmartin

This comment has been minimized.

Copy link

commented Feb 17, 2014

This is awesome. Thank you for sharing!

@jxm262

This comment has been minimized.

Copy link

commented Nov 5, 2014

This was very easy to follow and helped me alot. Been having trouble just getting through the simple basics, so Thanks!

@juliusakula

This comment has been minimized.

Copy link

commented Feb 9, 2015

Great help, I'm glad this comes up close to the top in google for "simple grunt tests". Thank you

@t0dd

This comment has been minimized.

Copy link

commented Feb 17, 2015

Uber helpful, thanks! Adding sinon.js == perfect

@miketoth

This comment has been minimized.

Copy link

commented Mar 30, 2015

This is great! Just as a heads up, the your mocha links are broken. New repo is: https://github.com/mochajs/mocha

@maicki

This comment has been minimized.

Copy link
Owner Author

commented Apr 6, 2015

@miketoth Thanks for pointing that out. Links should be fixed.

@yson

This comment has been minimized.

Copy link

commented May 28, 2015

Very helpful tutorial ! Thanks !

@DarynHolmes

This comment has been minimized.

Copy link

commented Jul 14, 2015

Thank you! This worked perfectly, and great descriptions.

@dbonsu

This comment has been minimized.

Copy link

commented Aug 9, 2015

Thanks for a drama-free set up.

@dbaltas

This comment has been minimized.

Copy link

commented Dec 16, 2015

👍

@vikene

This comment has been minimized.

Copy link

commented May 13, 2016

👍

@annemarie35

This comment has been minimized.

Copy link

commented May 18, 2016

Very helpful, thanks al lot

@pheld

This comment has been minimized.

Copy link

commented May 19, 2016

👍

@atsepkov

This comment has been minimized.

Copy link

commented Aug 27, 2016

Thanks! This is a great starting point. For next step I want to keep the relevant tests in the same directory as the js/html they're testing. Could you recommend a good setup to have testrunner scan my project directories for special js scripts to pull in (i.e. test.js) rather than having all my tests in tests folder?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.