Sinon.js documentation

This documentation below is an adaptation of the official Sinon.js documentation.

Sinon.js is included in Unit.JS, you can use Sinon.js with Unit.js.

Load Unit.js :

var test = require('unit.js'); 

Utils for the examples of this documentation :

// some functions function once(fn) { var returnValue; var called = false; return function() { if (!called) { called = true; returnValue = fn.apply(this, arguments); } return returnValue; }; }; var jQuery = { ajax: function() {} }; function getTodos(listId, callback) { jQuery.ajax({ url: '/todo/' + listId + '/items', success: function(data) { // Node-style CPS: callback(err, data) callback(null, data); } }); } 

Spy

var spy = test.spy(); spy(42); test.assert(spy.withArgs(42).calledOnce); 

Calls the original function :

var callback = test.spy(); var proxy = once(callback); proxy(); test.assert(callback.called); 

Calls the original function only once :

var callback = test.spy(); var proxy = once(callback); proxy(); proxy(); test.assert(callback.calledOnce); // ...or: test.assert.strictEqual(callback.callCount, 1); 

Calls original function with right this and args :

var callback = test.spy(); var proxy = once(callback); var obj = {}; proxy.call(obj, 1, 2, 3); test.assert(callback.calledOn(obj)); test.assert(callback.calledWith(1, 2, 3)); 

Stubs

Returns the return value from the original function :

var callback = test.stub().returns(42); var proxy = once(callback); test.assert.strictEqual(proxy(), 42); 

Mocks

Returns the return value from the original function :

var myAPI = { method: function() {} }; var mock = test.mock(myAPI); mock.expects('method').once().returns(42); var proxy = once(myAPI.method); test.assert.equal(proxy(), 42); mock.verify(); 

Test should call a method with exceptions :

var myAPI = { method: function() {} }; var mock = test.mock(myAPI); mock.expects('method').once().throws(); test.exception(function() { myAPI.method(); }) .isInstanceOf(Error); mock.verify(); 

Matchers

Test should assert fuzzy :

var book = { pages: 42, author: 'cjno' }; var spy = test.spy(); spy(book); test.sinon.assert.calledWith(spy, test.sinon.match({ author: 'cjno' })); test.sinon.assert.calledWith(spy, test.sinon.match.has('pages', 42)); 

Test should stub method differently based on argument types :

var callback = test.stub(); callback.withArgs(test.sinon.match.string).returns(true); callback.withArgs(test.sinon.match.number).throws('TypeError'); test.bool(callback('abc')).isTrue(); // Returns true test.exception(function() { callback(123); // Throws TypeError }) .isValid(function(err) { if (err.name === 'TypeError') { return true; } }); 

Combining matchers :

var stringOrNumber = test.sinon.match.string .or(test.sinon.match.number); var bookWithPages = test.sinon.match.object .and(test.sinon.match.has('pages')); var book = { pages: 42, author: 'cjno' }; var spy = test.spy(); var otherSpy = test.spy(); spy(book); otherSpy(10); test.sinon.assert.calledWith(spy, bookWithPages); test.sinon.assert.calledWith(otherSpy, stringOrNumber); 

Custom matchers :

 var equal10 = test.sinon.match(function(value) { return value === 10; }, 'value is not equal to 10'); var spy = test.spy(); var otherSpy = test.spy(); spy(10); otherSpy(42); // ok because the argument value 10 is identical to 10 expected test.sinon.assert.calledWith(spy, equal10); test.exception(function() { // throws an exception because the argument value 42 // is not identical to 10 expected test.sinon.assert.calledWith(otherSpy, equal10); }) .hasMessage(/value is not equal to 10/); 

Sandbox

it('test using test.sinon.test sandbox', test.sinon.test(function() { var myAPI = { method: function() {} }; var mockMyApi = this.mock(myAPI).expects('method').once().returns(42); var proxy = once(myAPI.method); test.number(proxy()).isIdenticalTo(42); mockMyApi.verify(); })); 

Testing Ajax

after(function() { // When the test either fails or passes, restore the original // jQuery ajax function (Sinon.JS also provides tools to help // test frameworks automate clean-up like this) jQuery.ajax.restore(); }); it('makes a GET request for todo items', function() { test.stub(jQuery, 'ajax'); getTodos(42, test.spy()); test.assert(jQuery.ajax.calledWithMatch({ url: '/todo/42/items' })); }); 

Faking time

 // original function function throttle(callback) { var timer; return function() { clearTimeout(timer); var args = [].slice.call(arguments); timer = setTimeout(function() { callback.apply(this, args); }, 100); }; } var clock; // before load the fake timers before(function() { clock = test.useFakeTimers(); }); // after the test, restore the timers after(function() { clock.restore(); }); it('calls callback after 100ms', function() { var callback = test.spy(); var throttled = throttle(callback); throttled(); // faking 99ms clock.tick(99); test.assert(callback.notCalled); // faking 1ms clock.tick(1); test.assert(callback.calledOnce); // Also: test.assert.strictEqual(new Date().getTime(), 100); });