A few months ago we posted about our new build process, and we mentioned starting to use Grunt for the “freedom and customization” that it provided. In addition, we noted that we’re using the Jasmine plugin, which allows for JavaScript testing.
Recently, Rob Tarr released a new application called Stuntman. This application (using node.js) had the need for both client and server-side JavaScript testing. Our new build process already had Jasmine running our client JavaScript specs, but we also had to test our server-side JavaScript.
Grunt to the Rescue
Running both server and client-side JavaScript specs was an issue. We had not yet seen a good implementation of Jasmine running both server and client specs, nor did we find a Mocha plugin that ran server and client specs.
Our solution:
Test client side JavaScript with Jasmine
Test our server side JavaScript with Mocha
Not very challenging to do thanks to Grunt, but there are some important packages you will need.
Prerequisites
Node.js
npm
Grunt Setup
Check out the example repository.
Our basic setup consists of the following packages in our package.json file:
Phantomjs (Version 1.8.2-0 is required. At time of writing, there’s a bug in version 1.9.x that will not allow us to run our jasmine tests through phantomjs.)
Example “package.json”
{
"name": "MochaJasmine",
"description": "Mocha and Jasmine Testing",
"version": "0.0.1",
"devDependencies": {
"grunt": "0.4.x",
"grunt-contrib-watch": "~0.2.0",
"grunt-contrib-jshint": "~0.4.3",
"grunt-contrib-jasmine": "~0.4.2",
"grunt-mocha-cli": "~1.0.2",
"phantomjs": "1.8.2-0",
"expect.js": "~0.2.0"
}
}
Gruntfile.js Setup
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON("package.json"),
watch: {
grunt: {
files: ["Gruntfile.js", "package.json"],
tasks: "default"
},
javascript: {
files: ["src/client/**/*.js", "src/server/*.js", "specs/**/*Spec.js"],
tasks: "test"
}
},
jasmine: {
src: "src/client/js/*.js",
options: {
specs: "specs/client/*Spec.js"
}
},
mochacli: {
options: {
reporter: "nyan",
ui: "tdd"
},
all: ["specs/server/*Spec.js"]
},
jshint: {
all: [
"Gruntfile.js",
"src/**/*.js",
"spec/**/*.js"
],
options: {
jshintrc: ".jshintrc"
}
}
});
grunt.loadNpmTasks("grunt-contrib-watch");
grunt.loadNpmTasks("grunt-contrib-jshint");
grunt.loadNpmTasks("grunt-contrib-jasmine");
grunt.loadNpmTasks("grunt-mocha-cli");
grunt.registerTask("test", ["jshint", "mochacli", "jasmine"]);
grunt.registerTask("default", ["test"]);
};
Once you have your package.json and Gruntfile.js in a directory, install the packages with the following command (in your project directory):
npm install
Directory Structure
The specs are contained within the specs directory, following the server/client model:
/specs/client
/specs/server
The source files are located in the following directories:
/src/client/js
/src/server
Example Tests
Client
var AppClient = function() {
this.name = "Panda";
};
AppClient.prototype.setName = function(name) {
this.name = name;
};
AppClient.prototype.getName = function() {
return this.name;
};
describe("The Client App...", function() {
var client;
beforeEach(function(){
client = new AppClient();
});
it("is a constructable object", function() {
expect(typeof client).not.toBeUndefined();
});
});
Server
var App;
function App() {
this.panda = "sad";
}
module.exports = App;
var App, app, expect;
App = require("../../src/server/server.js"); //Server side code
expect = require("expect.js");
app = new App();
describe("server testing", function() {
it("should work", function() {
expect(typeof app).to.be("object");
});
});
Running Tests
Now we have Jasmine running our client-side specs, and we have Mocha (CLI) running our server-side specs. You can use Grunt watch to track your files for changes and re-run the tasks specified in the Gruntfile.js. The results of the tests will be displayed in terminal, and you could easily add notify too.
Grunt will watch your files for changes and rerun the tests with Watch.
To have Grunt watch your files for changes and rerun tests, in the project directory run the command:
grunt watch
Or you can run tests right away with the following:
grunt test
or
grunt
Trial and Error
We tried to use only Mocha, but we ran into issues with running client-side tests. One issue for us was that Mocha expects client-side JavaScript to be in the ‘require’ format, which would cause a refactor for all client-side code just to get tests to run. We also tried a Jasmine-only approach; however, we encountered problems getting Jasmine to handle both client and server-side specs.
In the end, Mocha was good at server-side tests while Jasmine was good at client-side tests, so we thought, “why not use both?” Though using different testing frameworks felt a little strange to us at first, Grunt ran each test suite automatically (rather than running separate commands for each framework). It didn’t cause us issues.
This is where we are right now with JavaScript testing. But like anything else that’s new, it will probably change—especially with us at Sparkbox. We’re always looking for ways to improve our process, and we encourage you to do the same!