Wednesday, October 16, 2013

JavaScript Unit Testing with Mocha

Okay so, an initiative at work has been to start JS-Unit Testing.  I looked into the latest and greatest and decided on Mocha.  I wanted to start by writing some simple JS classes to verify email addresses, which would return true/false values, given a string input. For the sake of this post, I'll focus on the simplest one, in my view:

  isEmpty isEmpty ( string ) return true / false

 We use the following pattern to initialize global variables at HG:
if (typeof window.Var = 'undefined') {
  window.Var = ...
}
I wanted to run mocha in a pure command line environment, so, because there is no browser object, I kept getting 'window is undefined' messages. I tried installing ZombieJS and PhantomJS, but both of these seem to want me to carry out my unit tests inside of a simulated browser environment, which would require a URL or at least an HTML file... I'm looking to run tests right from the terminal and neither of them seemed to be able to help me with that problem. After some poking around, I discovered this pattern for creating global variables, from The Little Book Of CoffeeScript

exports = this
exports.MyVariable = "foo-bar"

In Javascript that translates to :

// Generated by CoffeeScript 1.4.0
(function() {
  var exports;
  exports = this;
  exports.myVariable = "foobar";
}).call(this);

' Eureka! The "this" variable corresponds to "window" in a browser, or to whatever Node/Mocha uses, in other environments. Using this pattern, one can write JS that will work and be unit testable in both Node and Browser environments. So, my isEmpty function looks like this:

 globalObjects.js (file being tested)

(function() {
var exports;
exports = this;
if (exports.globalObjects === 'undefined') {
var globalObjects = {
    verify : {
               isEmpty : function (string) {
            if (string.length < 1) return true;
  return false;
        }
    }
}
exports.globalObjects = globalObjects;
}
}).call(this);

test-globalObjects.js (file doing the testing)


var globalObjects = require("../globalObjects.js");
var assert = require("assert");

describe('verify', function(){
  describe('#verify()', function () {
    it('should return false when the email is not an email', function () {
      assert.equal(false, globalObjects.verify.isEmpty("yoyoma"));
    })
  })
})

I'm still getting an error though!

 TypeError: Cannot call method 'isEmail' of undefined

 It looks like the Mocha is reading through the globalObjects file fine now, but it's just not assigning it to a variable that can be read in the context of the test. Adding:

module.exports = this.globalObjects;

to the end of the globalObjects.js file solved this! However it created an unwanted side-effect: Now running this file in the browser throws an error : "module is not defined" For this, I used :

if (typeof module !== 'undefined') {
 module.exports = this.globalObjects;
}

No comments:

Post a Comment