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