Get Started
Install using npm
To install the current release (v16.0.0
) of Sinon:
npm install sinon
Setting up access
Node and CommonJS build systems
var sinon = require("sinon");
Direct browser use
<script src="./node_modules/sinon/pkg/sinon.js"></script>
<script>
// Access the `sinon` global...
</script>
Or in an ES6 Modules environment (modern browsers only)
<script type="module">
import sinon from "./node_modules/sinon/pkg/sinon-esm.js";
</script>
Try It Out
The following function takes a function as its argument and returns a new function. You can call the resulting function as many times as you want, but the original function will only be called once:
function once(fn) {
var returnValue,
called = false;
return function () {
if (!called) {
called = true;
returnValue = fn.apply(this, arguments);
}
return returnValue;
};
}
Fakes
Testing this function can be quite elegantly achieved with a test fake:
it("calls the original function", function () {
var callback = sinon.fake();
var proxy = once(callback);
proxy();
assert(callback.called);
});
The fact that the function was only called once is important:
it("calls the original function only once", function () {
var callback = sinon.fake();
var proxy = once(callback);
proxy();
proxy();
assert(callback.calledOnce);
// ...or:
// assert.equals(callback.callCount, 1);
});
We also care about the this
value and arguments:
it("calls original function with right this and args", function () {
var callback = sinon.fake();
var proxy = once(callback);
var obj = {};
proxy.call(obj, 1, 2, 3);
assert(callback.calledOn(obj));
assert(callback.calledWith(1, 2, 3));
});
Behavior
The function returned by once
should return whatever the original function returns. To test this, we create a fake with behavior:
it("returns the return value from the original function", function () {
var callback = sinon.fake.returns(42);
var proxy = once(callback);
assert.equals(proxy(), 42);
});
Conveniently, we can query fakes for their callCount
, received args and more.
Testing Ajax
The following function triggers network activity:
function getTodos(listId, callback) {
jQuery.ajax({
url: "/todo/" + listId + "/items",
success: function (data) {
// Node-style CPS: callback(err, data)
callback(null, data);
},
});
}
A unit test should not actually trigger a function’s network activity. To test getTodos()
without triggering its network activity, use the sinon.replace()
method to replace the jQuery.ajax
method in your test. Restore the jQuery.ajax
method after your test by calling sinon.restore()
in your test runner’s after()
function.
after(function () {
sinon.restore();
});
it("makes a GET request for todo items", function () {
sinon.replace(jQuery, "ajax", sinon.fake());
getTodos(42, sinon.fake());
assert(jQuery.ajax.calledWithMatch({ url: "/todo/42/items" }));
});
Fake XMLHttpRequest
While the preceding test shows off some nifty Sinon.JS tricks, it is too tightly coupled to the implementation. When testing Ajax, it is better to use Sinon.JS’ fake XMLHttpRequest:
var xhr, requests;
before(function () {
xhr = sinon.useFakeXMLHttpRequest();
requests = [];
xhr.onCreate = function (req) {
requests.push(req);
};
});
after(function () {
// Like before we must clean up when tampering with globals.
xhr.restore();
});
it("makes a GET request for todo items", function () {
getTodos(42, sinon.fake());
assert.equals(requests.length, 1);
assert.match(requests[0].url, "/todo/42/items");
});
Learn more about fake XMLHttpRequest.
Fake server
The preceding example shows how flexible this API is. If it looks too laborious, you may like the fake server:
var server;
before(function () {
server = sinon.fakeServer.create();
});
after(function () {
server.restore();
});
it("calls callback with deserialized data", function () {
var callback = sinon.fake();
getTodos(42, callback);
// This is part of the FakeXMLHttpRequest API
server.requests[0].respond(
200,
{ "Content-Type": "application/json" },
JSON.stringify([{ id: 1, text: "Provide examples", done: true }])
);
assert(callback.calledOnce);
});
Test framework integration can typically reduce boilerplate further. Learn more about the fake server.
Faking time
“I don’t always bend time and space in unit tests, but when I do, I use Buster.JS + Sinon.JS”
Testing time-sensitive logic without the wait is a breeze with Sinon.JS. The following function debounces another function - only when it has not been called for 100 milliseconds will it call the original function with the last set of arguments it received.
function debounce(callback) {
var timer;
return function () {
clearTimeout(timer);
var args = [].slice.call(arguments);
timer = setTimeout(function () {
callback.apply(this, args);
}, 100);
};
}
Thanks to Sinon.JS’ time-bending abilities, testing it is easy:
var clock;
before(function () {
clock = sinon.useFakeTimers();
});
after(function () {
clock.restore();
});
it("calls callback after 100ms", function () {
var callback = sinon.fake();
var throttled = debounce(callback);
throttled();
clock.tick(99);
assert(callback.notCalled);
clock.tick(1);
assert(callback.calledOnce);
// Also:
// assert.equals(new Date().getTime(), 100);
});
As before, Sinon.JS provides utilities that help test frameworks reduce the boiler-plate. Learn more about fake time.
And all the rest…
You’ve seen the most common tasks people tackle with Sinon.JS, yet we’ve only scratched the surface. View more quick examples below, or dive into the API docs, which also provides useful pointers on how and when to use the various functionality.
Get help
- Stack Overflow
- IRC: #sinon.js on freenode
Sinon.JS elsewhere
Christian Johansen’s book Test-Driven JavaScript Development covers some of the design philosophy and initial sketches for Sinon.JS.