OmerHerera
5/25/2016 - 6:35 PM

Unit Test like a Secret Agent with Sinon.js

Unit Test like a Secret Agent with Sinon.js

describe("getTweets", function () {
    var fakeData = [
        { 
            created_at: "Fri Apr 05 19:39:30 +0000 2013", 
            text: "tweet 1", 
            retweeted: false, 
            favorited: false, 
            user: { name: "name 1" } 
        }, 
        /* ... */ 
    ];

    before(function () {
        sinon.stub($, "ajax").yieldsTo("success", fakeData);
    });

    it("should $.ajax & invoke callback", function (done) {
        twitter.getTweets("elijahmanor", function (tweets) {
            expect(tweets.length).to.be(5);
            done();
        });
    });

    after(function () { $.ajax.restore(); });
});
> missionImpossible.assignment("accept", tape);
Mission {}
> missionImpossible.numberOfAssignments
1
> missionImpossible.assignment("reject", tape);
⊗ Disintegrate
var missionImpossible = {
    numberOfAssignments: 0,
    assignment: function (answer, tape) {
        var mission = tape(answer);
        this.numberOfAssignments++;
        return mission;
    }
};
function Mission() { }
var tape = sinon.stub();
tape.withArgs("accept").returns(new Mission());
tape.withArgs("reject").throws("Disintegrate");
var stub = sinon.stub(),
    opts = { call: function (msg) { console.log(msg); } };

// We can control how the sinon.stub() will behave based on how it’s called!
stub.withArgs("Hello").returns("World");
stub.withArgs("Wuz").returns("Zup?");
stub.withArgs("Kapow").throws();
stub.withArgs(opts).yieldsTo("call", ["Howdy"]);

stub("Hello"); // "World"
stub(options); // "Howdy"

/* ... more ... */
> ethanHunt.called
true
> ethanHunt.calledOnce
true
> ethanHunt.callCount
1
var missionImpossible = {
    start: function (agent) {
        agent.apply(this);
    }
};

// By using a sinon.spy(), it allows us to track how the function is used
var ethanHunt = sinon.spy();
missionImpossible.start(ethanHunt);
var callback = sinon.spy();

callback(); // Invoke the spy callback function

callback.called;
callback.callCount;
callback.calledWith(arg1);
callback.threw();
callback.returned(obj);
callback.calledBefore(spy);
callback.calledAfter(spy);

/* ... more ... */
sinon.spy($, "ajax");

$.ajax({ / ... / }); // Call spy version of jQuery.ajax

var call = $.ajax.getCall(0);

call.args;
call.exception;
call.returnValue;

$.ajax.restore();
describe("getTweets", function () {
    var mock, fakeData = [];

    before(function () {
        mock = sinon.mock(jQuery).expects("ajax").once()
                   .yieldsTo("success", fakeData);
    });

    it("should call jQuery.ajax", function (done) {
        twitter.getTweets("elijahmanor", function (tweets) {
            mock.verify();
            done();
        });
    });

    after(function () { jQuery.ajax.restore(); });
});
var opts = { call: function (msg) { console.log(msg); } },
    mock = sinon.mock(opts);

// You state your success criteria upfront
mock.expects("call").once().withExactArgs("Hello World");
/* ... twice, atMost, never, exactly, on, etc ... */

opts.call("Hello World"); 

mock.verify();

mock.restore();
var clock = sinon.useFakeTimers();

var hidden = 
    $("<div hidden="">Peekaboo</div>")
        .appendTo(document.body).fadeIn("slow");

clock.tick(650); // slow = 600ms
hidden.css("opacity") === 1; // true

clock.restore();
var server = sinon.fakeServer.create();

server.respondWith("GET", "/twitter/api/user.json", [
    200, 
    {"Content-Type": "application/json"}, 
    '[{"id": 0, "tweet": "Hello World"}]'
]);

$.get("/twitter/api/user.json", function (data) {
    console.log(data); // [{"id":0,"tweet":"Hello World"}] 
});
server.respond();

server.restore();
describe("getTweets - Server", function () {
    var server, fakeData = [ /* ... */ ];

    before(function () {
        // Doesn’t work :( It’s JSONP!
        server = sinon.fakeServer.create();
        server.respondWith(
            "GET", 
            "https://api.twitter.com/.../elijahmanor.json?count=5",
            [200, { "Content-Type": "application/json" }, JSON.stringify(fakeData)]
        );
    });

    it("should $.ajax &amp; invoke callback", function (done) {
        twitter.getTweets("elijahmanor", function (tweets) {
            expect(tweets.length).to.be(5);
            done();
        }); server.respond();
    });

    after(function () { server.restore(); });
});