I have been using grunt for a while but some of my tasks started getting a little ugly because I started abusing grunt-shell. Because of this I decided to create a grunt plugin for something that I need for most of my JS projects, unit tests.

To run unit test I use VenusJS test runner for which there wasn’t a grunt plugin. So I decided to create one. Grunt documentation has some information on creating plugins but I felt there were some things missing.

This is the process I followed to create my plugin:

Install grunt-init by running:

1
npm install -g grunt-init

Install a template if you haven’t done it before:

1
git clone git://github.com/gruntjs/grunt-init-gruntplugin.git ~/.grunt-init/gruntplugin

Create a folder, move there and create an empty plugin:

1
2
3
mkdir my-plugin
cd my-plugin
grunt-init gruntplugin

You will be asked a series very straight forward questions. After this you will see a bunch of files created for you in the current folder. The first thing I did after my files were generated was to strip all the things that I wasn’t going to need from package.json and Gruntfile.js.

I then modified my Gruntfile to have a venus task:

1
2
3
4
5
my-plugin: {
  all: [
    'examples/arrays.spec.js'
  ]
}

And added it to my default task so it would run every time:

1
grunt.registerTask('default', ['jshint', 'venus', 'nodeunit']);

If you try to run grunt now it will probably fail because the file examples/arrays.spec.js doesn’t exist. Before I create it I’m going to modify my task file (tasks/venus.js). I want to make my plugin a little more modular and testable, so I kept tasks/venus.js small and put most of my logic under tasks/lib/venus.js. This is how my tasks/venus.js looks:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
'use strict';

var venusRunner = require('./lib/VenusRunner');

module.exports = function(grunt) {
  grunt.registerMultiTask('venus', 'Run JS unit tests using venus', function() {
    var done = this.async();

    venusRunner.runVenusForFiles(this.files).then(function() {
      done(0);
    })['catch'](function() {
      grunt.log.error('There was an error');
      done(1);
    });
  });
};

You can see that this file is very small so it is very easy to read. Most of the work happens on venusRunner.runVenusForFiles(). This function will loop through all the given files (in this case examples/arrays.spec.js) and run venus against them. You can change your plugin to do whatever you want using node.

Publishing

Once you are done you probably want to make your plugin available to the public. To do that you will need to create an account at npm. After you create your account you can publish very easily by running:

1
2
npm adduser
npm publish
[ grunt  javascript  productivity  ]
Using Webpack with React javascript productivity
Introduction to Browserify javascript productivity
Deploying node apps with Flightplan javascript productivity
Unit testing angular with karma javascript productivity
Building modular apps with Angular javascript productivity