An introduction
var MODULE = (function () {
var privateVariable = 1;
function privateMethod() {
// ...
}
function publicMain () {
// ...
};
return {
main : publicMain
};
}());
(function($){
var prototype = {
init : function(){ ... }
};
$.fn.myPlugin = function(params){
var obj = Object.create(prototype);
return this.each(function(){
obj.init();
});
};
}(jQuery));
there are no bugs, just unwritten specifications
// the assertion
function assert(value, message){
return !!value ? 'PASS!' : 'Fail: ' + message;
}
//the method under test
function add(a,b){
return a+b;
}
//the test
var result = (add(38,4) === 42);
assert(result, "should return Mr Adams favorite number");
(function($){
module('moduleUnderTest', {
setup: function(){
// handle setup logic
}
});
test('returns sum of values passed in', 1, function(){
deepEqual(add(38,4), 42, 'should return 42');
});
}(jQuery));
"test should call subscribers on publish": function () {
var callback = sinon.spy();
PubSub.subscribe("message", callback);
PubSub.publishSync("message");
assertTrue(callback.called);
}
"test should call ajax twice": function () {
sinon.spy(jQuery, "ajax");
jQuery.getJSON('/some/resource');
jQuery.getJson('/some/other/resource');
sinon.assert.calledTwice(jQuery.ajax);
}
"test stub differently based on arguments": function () {
var callback = sinon.stub();
callback.withArgs(42).returns(1);
callback.withArgs(1).throws("TypeError");
callback(42); // Returns 1
callback(1); // Throws TypeError
}
"test useful for stubbing externals": function(){
var deferred = $.Deferred();
sinon.stub(jQuery, "ajax").returns(deferred.promise);
someMethodThatUsesAjax();
deferred.resolve();
}
{
setUp: function(){
this.clock = sinon.useFakeTimers();
},
tearDown: function(){
this.clock.restore();
},
"test should animate el over 500ms": function () {
var el = jQuery('<div>');
el.appendTo(document.body);
el.animate({height: '200px'});
this.clock.tick(510);
assertEquals('200px', el.css('height'));
}
}
// fake servers
var server = sinon.fakeServer.create(),
headers = { "Content-Type": "application/json" },
response = '[{ "value" : "heeeey!" }]';
server.respondWith("GET", "/some/resource",
[200, headers, response]);
// call method that makes call to resource
getComments();
// tell server to respond
server.respond();
// Assertions...
// first install node from nodejs.org
> npm install -g grunt
Initialize grunt-file
> grunt init:jquery
Please answer the following:
[?] Project name (replaceTag)
[?] Project title (ReplaceTag)
[?] Description (The best jQuery plugin ever.)
[?] Version (0.1.0)
... etc ...
Note: PhantomJS needs to be in path to run qunit
module.exports = function(grunt){
grunt.initConfig({
concat: { dist: { src: [''], dest: [''] } }, //min
qunit: {
files: ['test/**/*.html']
},
lint: {
files: ['src/**/*.js', 'test/**/*.js']
},
watch: {
files: '<config:lint.files>',
tasks: 'lint qunit'
},
jshint: {
options: { ... },
globals: { ... }
}
});
grunt.registerTask('default', 'lint qunit concat min');
}
// On Windows you need to run grunt.cmd
> grunt
// automatically runs default task ('lint qunit concat min')
// Now lets try the watch command
> grunt watch