Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test LoDash debounce in Jasmine with Sinon fakeTimer?

I'm trying to write a test for debouncing user input in a search query. The function is defined on a Backbone View:

SearchView = Backbone.View.extend({
    events: {
        "input .search-input": "search"
    },

    // init, render, etc.

    search: _.debounce(function() {
        this.collection.fetch();   
    }, 200)
});

Originally, the Backbone library (v0.9.10) used Underscore (v1.4.4), and the test was defined as follows:

describe("SearchView", function() {
    var view, $viewContainer;

    beforeEach(function() {
        appendSetFixtures('<div class="jasmine-container"></div>');
        $viewContainer = $(".jasmine-container");

        view = new SearchView({
            el: $viewContainer
        });
    });

    afterEach(function() {
        view.remove();
        view.cleanup();
    });

    //...

    describe("wires the search input", function() {
        var collectionStub,
            fakeTimer;

        beforeEach(function() {
            collectionStub = sinon.stub(
                SearchResultsCollection.prototype,
                "fetch"
            );     

            fakeTimer = sinon.useFakeTimers();
        });

        afterEach(function() { 
            collectionStub.restore();
            fakeTimer.restore();
        });

        it("should not trigger a search before 200ms", function() {
            fakeTimer.tick(199);
            expect(collectionStub).not.toHaveBeenCalled();
        });

        it("should trigger a search after 200ms", function() {
            fakeTimer.tick(200);
            expect(collectionStub).toHaveBeenCalled();
        });
    });
});

However, now I want to incorporate LoDash instead of Underscore. Using the latest Underscore compatibility build on their site (LoDash 2.4.1 / Underscore 1.5.6), all my tests pass except for the one using _.debounce!

I did some research and came across these relevant issues to create a LoDash Underscore build with runInContext, but I have no idea how to use it due to lack of examples. How can I use _.runInContext() in my spec(s) to work with sinon.fakeTimer?

like image 458
SirTophamHatt Avatar asked Oct 30 '14 20:10

SirTophamHatt


2 Answers

SearchView = Backbone.View.extend({
    events: {
        "input .search-input": function() {
            this.search();
        }
    },

    initialize: function() {
        this.search = _.debounce(this.search, 200);
    }

    // init, render, etc.

    search: function() {
        this.collection.fetch();   
    }
});    

describe("SearchView", function() {
    var view; 
    var $viewContainer;
    var clock;
    var lodash = window._;

    beforeEach(function() {
        appendSetFixtures('<div class="jasmine-container"></div>');
        $viewContainer = $(".jasmine-container");

        clock = sinon.useFakeTimers();
        window._ = _.runInContext(window);

        view = new SearchView({
            el: $viewContainer
        });
    });

    afterEach(function() {
        view.remove();
        view.cleanup();

        clock.restore();
        window._ = lodash;
    });

    //...

    describe("wires the search input", function() {
        var collectionStub;

        beforeEach(function() {
            collectionStub = sinon.stub(
                SearchResultsCollection.prototype,
                "fetch"
            );     
        });

        afterEach(function() { 
            collectionStub.restore();
        });

        it("should not trigger a search before 200ms", function() {
            fakeTimer.tick(199);
            expect(collectionStub).not.toHaveBeenCalled();
        });

        it("should trigger a search after 200ms", function() {
            fakeTimer.tick(200);
            expect(collectionStub).toHaveBeenCalled();
        });
    });
});
like image 139
SirTophamHatt Avatar answered Nov 03 '22 10:11

SirTophamHatt


You need add this line

_ = _.runInContext(window);

before creation (not initialization) of SearchView or any call of _.debounce(). So it should be right after including Lo-Dash.

This allows you to run lodash in global window context so you can use overridden by SinonJS setTimeout.

like image 3
Eugene Glova Avatar answered Nov 03 '22 08:11

Eugene Glova