如何使用Sinon fakeTimer在Jasmine中测试LoDash去抖?

时间:2014-10-30 20:09:10

标签: backbone.js underscore.js jasmine sinon lodash

我试图在搜索查询中编写用于去除用户输入的测试。该功能在骨干视图中定义:

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

    // init, render, etc.

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

最初,Backbone库(v0.9.10)使用了Underscore(v1.4.4),测试定义如下:

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();
        });
    });
});

但是,现在我想要合并LoDash而不是Underscore。在他们的网站上使用最新的Underscore兼容性构建(LoDash 2.4.1 / Underscore 1.5.6),我的所有测试都通过了,除了使用_.debounce的那个!

我做了一些研究并遇到了这些relevant issues来使用runInContext创建一个LoDash Underscore构建,但由于缺少示例,我不知道如何使用它。如何在我的规范中使用_.runInContext()来使用sinon.fakeTimer

2 个答案:

答案 0 :(得分:4)

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();
        });
    });
});

答案 1 :(得分:3)

您需要添加此行

_ = _.runInContext(window);

SearchView的创建(非初始化)或_.debounce()的任何调用之前。所以在包括Lo-Dash之后应该是正确的。

这允许您在全局窗口上下文中运行lodash,以便您可以使用SinonJS setTimeout覆盖。