Lately I’ve been playing with nodejs and vows, doing some TDD on a side project at home. I love the very readable syntax of should.js, which lets you frame your assertions as almost natural english. However, pretty early on I realized I wanted to add my own custom assertions to the should object to abstract away some of the messy details of my testing and keep the code readable. In the past I’ve used custom asserts with .NET for testing, and I find it allows you to quickly express domain specific concepts even inside your tests, for better readability and clarity.
One particular example was a test where I wanted to make sure the elements in a <ul> where the same as those in a javascript array. Rather than trying to parse out the list into another array and do a comparison in the test body, I wanted to have an assertion that was something like $(“#list”).children().should.consistOfTheElementsIn(array), where consistOfTheElementsIn will handle the parsing and comparison.
After a little bit a playing around, I worked out a pretty simple way to do this. Basically I create a new node module called customShould.js. customShould.js require’s should, and then exports the should object. Additionally, customShould adds a new method to the “Assertion” object created by should.js. Here’s the code
var should = require('should.js'); exports = module.exports = should; should.Assertion.prototype.aHtmlListThatConsistOf = function(list){ var compareArrays = function(first,second){ if (first.length != second.length) { return false; } var a = first.sort(), b = second.sort(); for (var i = 0; second[i]; i++) { if (a[i] !== b[i]) { return false; } } return true; } var matches = this.match(/<li>.?*<//li>/gi); for(matchIndex in matches){ matches[matchIndex] = matches.replace("<li>","").replace("</li>",""); } this.assert(compareArray(matches, list), "lists do not match"); }
It’s all pretty straight forward. Then to use your custom asserts, you just require your customShould.js module instead of the normal should module.