CINXE.COM
Sinon.JS - Standalone test fakes, spies, stubs and mocks for JavaScript. Works with any unit testing framework.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Sinon.JS - Standalone test fakes, spies, stubs and mocks for JavaScript. Works with any unit testing framework.</title> <meta name="description" content="Standalone test spies, stubs and mocks for JavaScript. Works with any unit testing framework." /> <link rel="stylesheet" href="/assets/css/main.css"> <link rel="shortcut icon" href="/assets/images/favicon.png"> <script> var site = {}; // site settings </script> <link rel="canonical" href="https://sinonjs.org/" /> <link href="https://fonts.googleapis.com/css?family=Karla:400,700" rel="stylesheet"> </head> <body> <div class="navigation"> <div class="container"> <nav class="navbar header"> <div class="navbar-header"> <a class="navbar-brand" href="/"> Sinon.JS </a> </div> <ul class="nav navbar-nav navbar-right"> <li><a href="/releases/v19">Documentation</a></li> <li><a href="/releases/">Releases</a></li> <li><a href="/how-to/">How To</a></li> <li><a href="https://github.com/sinonjs/" target="blank" class="github-nav"><img src="/assets/images/github.png" alt="Github"></a></li> </ul> </nav> </div> </div> <div class="top"> <div class="container home-header"> <img class="logo grow img-responsive" src="/assets/images/logo.png" alt=""> <h1> Standalone test spies, stubs and mocks for JavaScript. <br /> Works with any unit testing framework. </h1> <p class="btn-top text-center"> <a class="btn btn-primary" href="#get-started">Get Started</a> <a class="btn btn-default" target="blank" href="https://github.com/sinonjs/sinon" ><img src="/assets/images/github.png" alt="">Star Sinon.JS on Github</a > </p> </div> <div class="container"> <div class="backed"> <div class="wrap"> <p class="centre-line"> <span>Proudly Sponsored By</span> </p> <div class="people"> <object data="https://opencollective.com/sinon/tiers/sponsors.svg?button=false&margin=1" title="Sponsors"></object> </div> <div class="backer"> <a target="blank" href="https://opencollective.com/sinon/"> Become a sponsor and get your logo on our README on GitHub with a link to your site </a> </div> </div> </div> <div class="backed"> <div class="wrap"> <p class="centre-line"> <span>Proudly Backed By</span> </p> <div class="people"> <object data="https://opencollective.com/sinon/backers.svg?width=720&limit=200&button=false" data-md="https://opencollective.com/sinon/backers.svg?width=680&limit=108&button=false" data-sm="https://opencollective.com/sinon/backers.svg?width=300&limit=45&button=false" title="Backers" class=""></object> </div> </div> <div class="backer"> <a target="blank" href="https://opencollective.com/sinon/"> Become a backer and support Sinon.JS with a monthly donation. </a> </div> </div> </div> </div> <div class="content"> <div class="container container-2"> <h2 id="get-started">Get Started</h2> <h3 id="install-using-npm">Install using <code>npm</code></h3> <p>To install the current release (<code>v19.0.2</code>) of Sinon:</p> <pre><code class="language-shell">npm install sinon </code></pre> <h3 id="setting-up-access">Setting up access</h3> <h4 id="node-and-commonjs-build-systems">Node and CommonJS build systems</h4> <pre><code class="language-javascript">var sinon = require("sinon"); </code></pre> <h4 id="direct-browser-use">Direct browser use</h4> <pre><code class="language-html"><script src="./node_modules/sinon/pkg/sinon.js"></script> <script> // Access the `sinon` global... </script> </code></pre> <p>Or in an ES6 Modules environment (modern browsers only)</p> <pre><code class="language-html"><script type="module"> import sinon from "./node_modules/sinon/pkg/sinon-esm.js"; </script> </code></pre> <h2 id="try-it-out">Try It Out</h2> <p>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:</p> <pre><code class="language-javascript">function once(fn) { var returnValue, called = false; return function () { if (!called) { called = true; returnValue = fn.apply(this, arguments); } return returnValue; }; } </code></pre> <h3 id="fakes">Fakes</h3> <p>Testing this function can be quite elegantly achieved with a <a href="/releases/v19/fakes">test fake</a>:</p> <pre><code class="language-javascript">it("calls the original function", function () { var callback = sinon.fake(); var proxy = once(callback); proxy(); assert(callback.called); }); </code></pre> <p>The fact that the function was only called once is important:</p> <pre><code class="language-javascript">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); }); </code></pre> <p>We also care about the <code>this</code> value and arguments:</p> <pre><code class="language-javascript">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)); }); </code></pre> <p><a href="/releases/v19/fakes">Learn more about fakes</a>.</p> <h3 id="behavior">Behavior</h3> <p>The function returned by <code>once</code> should return whatever the original function returns. To test this, we create a fake with behavior:</p> <pre><code class="language-javascript">it("returns the return value from the original function", function () { var callback = sinon.fake.returns(42); var proxy = once(callback); assert.equals(proxy(), 42); }); </code></pre> <p>Conveniently, we can query fakes for their <code>callCount</code>, received args and more.</p> <p><a href="/releases/v19/fakes">Learn more about fakes</a>.</p> <h3 id="testing-ajax">Testing Ajax</h3> <p>The following function triggers network activity:</p> <pre><code class="language-javascript">function getTodos(listId, callback) { jQuery.ajax({ url: "/todo/" + listId + "/items", success: function (data) { // Node-style CPS: callback(err, data) callback(null, data); }, }); } </code></pre> <p>A unit test should not actually trigger a function’s network activity. To test <code>getTodos()</code> without triggering its network activity, use the <code>sinon.replace()</code> method to replace the <code>jQuery.ajax</code> method in your test. Restore the <code>jQuery.ajax</code> method after your test by calling <code>sinon.restore()</code> in your test runner’s <code>after()</code> function.</p> <pre><code class="language-javascript">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" })); }); </code></pre> <h3 id="fake-xmlhttprequest">Fake XMLHttpRequest</h3> <p>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’ <a href="/releases/v19/fake-xhr-and-server">fake XMLHttpRequest</a>:</p> <pre><code class="language-javascript">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"); }); </code></pre> <p>Learn more about <a href="/releases/v19/fake-xhr-and-server">fake XMLHttpRequest</a>.</p> <h3 id="fake-server">Fake server</h3> <p>The preceding example shows how flexible this API is. If it looks too laborious, you may like the fake server:</p> <pre><code class="language-javascript">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); }); </code></pre> <p>Test framework integration can typically reduce boilerplate further. <a href="/releases/v19/fake-xhr-and-server#fake-server">Learn more about the fake server</a>.</p> <h3 id="faking-time">Faking time</h3> <blockquote> <p>“I don’t always bend time and space in unit tests, but when I do, I use Buster.JS + Sinon.JS”</p> </blockquote> <p><em><a href="https://twitter.com/briancavalier/status/225617077346635776">Brian Cavalier, Cujo.JS</a></em></p> <p>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.</p> <pre><code class="language-javascript">function debounce(callback) { var timer; return function () { clearTimeout(timer); var args = [].slice.call(arguments); timer = setTimeout(function () { callback.apply(this, args); }, 100); }; } </code></pre> <p>Thanks to Sinon.JS’ time-bending abilities, testing it is easy:</p> <pre><code class="language-javascript">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); }); </code></pre> <p>As before, Sinon.JS provides utilities that help test frameworks reduce the boiler-plate. <a href="/releases/v19/fake-timers">Learn more about fake time</a>.</p> <h3 id="and-all-the-rest">And all the rest…</h3> <p>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 <a href="/releases/v19">API docs</a>, which also provides useful pointers on how and when to use the various functionality.</p> <h3 id="get-help">Get help</h3> <ul> <li><a href="https://stackoverflow.com/questions/tagged/sinon">Stack Overflow</a></li> <li>IRC: #sinon.js on freenode</li> </ul> <h3 id="sinonjs-elsewhere">Sinon.JS elsewhere</h3> <ul> <li><a href="http://tinnedfruit.com/2011/03/03/testing-backbone-apps-with-jasmine-sinon.html">Testing Backbone applications with Jasmine and Sinon</a></li> <li><a href="https://github.com/ducin/sinon-backend-less-demo">Sinon.JS fake server live demo</a></li> </ul> <p>Christian Johansen’s book <a href="http://tddjs.com/">Test-Driven JavaScript Development</a> covers some of the design philosophy and initial sketches for Sinon.JS.</p> </div> </div> <script src="/assets/js/prism.js"></script> <script src="https://embed.runkit.com"></script> <script> function htmlDecode(input) { var doc = new DOMParser().parseFromString(input, "text/html"); return doc.documentElement.textContent; } </script> <div class="footer"> <div class="container text-center"> <a href="http://sinonjs.org/" target="blank"><img class="grow" src="/assets/images/logo.png" alt="Sinon.JS"></a> <p><a target="blank" class="join-btn" href="https://stackoverflow.com/questions/tagged/sinon">Join the discussion on Stack Overflow!</a></p> <p>All copyright is reserved the Sinon committers.</p> <p>Released under the <a href="https://opensource.org/licenses/BSD-3-Clause">BSD license</a>.</p> </div> </div> <script src="/assets/js/sinon.js"></script> </body> </html>