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?
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();
});
});
});
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With