Question

When I am not throttling/debouncing the function the test passes.

However when I debounce the event to prevent flooding the server the test no longer passes. Mocha outputs AssertionError: expected execute to have been called at least once, but it was never called

It should be noted that the debounced call works without errors in the live code. Which is why I'm thoroughly confused why the test fails.

The Test:

describe('When information is entered into the search fields', function () {
    it('vents up the search:for:churches command', function () {
        var executeStub = sinon.stub(App, 'execute');

        view = new SearchForm()
        view.render();

        view.$el.find('input[name=church_name]').val('baptist')
        view.$el.find('input[name=zip]').val('61615')

        view.$el.find('input[name=zip]').trigger($.Event('keypress'))

        expect(executeStub).to.have.been.called

        view.close();
        PEP.execute.restore()
    });
});

Un-throttled:

var SearchForm = Backbone.Marionette.ItemView.extend({

    template: 'search_form',
    events: {
        'keypress [data-search-field]' : 'searchForChurches'
    },

    searchForChurches: function() {
        console.log('not debounced')
        var searchData = Backbone.Syphon.serialize(this);
        App.execute("search:for:churches", searchData);
    }

});

Throttled:

var SearchForm = Backbone.Marionette.ItemView.extend({

    template: 'search_form',
    events: {
        'keypress [data-search-field]' : 'searchForChurches'
    },

    searchForChurches: _.debounce(function() {
        console.log('debounced')
        var searchData = Backbone.Syphon.serialize(this);
        App.execute("search:for:churches", searchData);
    }, 200)

});

Edit: I have also posted a related follow-up question: https://stackoverflow.com/questions/21167488/how-to-test-a-debounced-throttled-backbone-view-event-with-mocha-to-ensure-its-a

Était-ce utile?

La solution 2

Simon's approach worked great for most cases but I kept bumping into different situations that were causing more errors. After spending more time with it and looking at sinon's documentation I think I have a better approach.

Sinon's Fake Timers to the rescue.

describe('When information is entered into the search fields', function () {
    it('vents up the search:for:churches command', function () {
        var clock = sinon.useFakeTimers();
        var executeStub = sinon.stub(App, 'execute');

        view = new SearchForm()
        view.render();

        view.$el.find('input[name=church_name]').val('baptist')
        view.$el.find('input[name=zip]').val('61615')

        view.$el.find('input[name=zip]').trigger($.Event('keypress'))
        clock.tick(200)

        expect(executeStub).to.have.been.called

        view.close();
        PEP.execute.restore()
        clock.restore()    
    });
});

Autres conseils

There is a problem, when using UnderscoreJS with SinonJS.

  • The debounce function in UnderscoreJS uses _.now.
  • SinonJS covers the Date object, but doesn't cover _.now.

For testing purposes, i replace _.now in the test's bootstrap file:

_.now = function() {
  return new Date().getTime();
};

Throttling anything means the execution will be asynchronous. This is why it fails in your tests, because the App.execute method is not call right away, so when you assert it have been called, it haven't yet.

In this case, don't use Sinon. Just manually stub your method:

describe('When information is entered into the search fields', function () {
    it('vents up the search:for:churches command', function (done) {
        var originalMethod = App.prototype.execute;

        App.prototype.execute = function () {
            App.prototype.execute = originalMethod;
            done(); // calling done will pass the test, otherwise it'll fail with a timeout
        };

        view = new SearchForm()
        view.render();

        view.$el.find('input[name=church_name]').val('baptist')
        view.$el.find('input[name=zip]').val('61615')

        view.$el.find('input[name=zip]').trigger($.Event('keypress'))

        view.close();
    });
});
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top