Reputation: 511
I'm trying to test my Backbone.view using grunt, karma, jasmine 2 and chrome as output browser. My view is responding to a click event:
el: $('#wrap'),
events: {
(...)
'click #sender' : 'observeSender',
(...)
},
Where sender is a div (rendered by the view) in a menu bar, and the observeSender() method brings up a UI window. My test for this:
it('should show error dialog', function() {
var model = new fooModel({ 'config' : config });
var view = new barview({ model: model });
expect($('#errors-dialog').is(':visible')).toBe(false);
sender = $('#wrap').find('div#sender').eq(0);
sender.trigger('click');
expect($('#errors-dialog').is(':visible')).toBe(true);
});
This test fails. I've tried a ton of stuff and finally, if I change my view to this:
events: {
(...)
//'click #sender' : 'observeSender',
(...)
},
initialize: function(options) {
(...)
$('#sender').on('click', function(){ self.observeSender.call(self); });
}
Now the test passes. The first example works fine when trying the app live but it is not testable, second option works once but not after the #sender is re-rendered (due to other events). I would still like to have it organised the first way, so what am I doing wrong?
Update 1
As suggested I switched all my queries in the test to view.$, but the test is still failing on
expect(view.$('#errors-dialog').is(':visible')).toBe(true);
Update 2
I need to clarify that the observeSender() method is responsible for bringing up a UI dialog. It is never called. My question is not about elements in the DOM, it's all there, I use the Karma Debug Runner and Chrome console to check it.
If I replace the entire contents of the observeSender method with a console.log('hello');
statement, I will never see the output of it using the first approach where I define the click event "the backbone way". As I see it, something is going on with the events during the test.
Update 3
I've gone through the tests for the backbone library and copied over a test from their view tests
it('should delegateEvents', function() {
var counter1 = 0, counter2 = 0;
var view = new Backbone.View({el: '#testElement'});
view.increment = function(){ counter1++; };
view.$el.on('click', function(){ counter2++; });
var events = {'click h1': 'increment'};
view.delegateEvents(events);
view.$('h1').trigger('click');
expect(counter1).toBe(1);
expect(counter2).toBe(1);
view.$('h1').trigger('click');
expect(counter1).toBe(2);
expect(counter2).toBe(2);
view.delegateEvents(events);
view.$('h1').trigger('click');
expect(counter1).toBe(3);
expect(counter2).toBe(3);
});
The output is:
Expected 0 to be 1.
Error: Expected 0 to be 1.
at /.../Spec.js:20572
Expected 0 to be 1.
Error: Expected 0 to be 1.
at /.../Spec.js:20573
Expected 0 to be 2.
Error: Expected 0 to be 2.
at /.../Spec.js:20576
Expected 0 to be 2.
Error: Expected 0 to be 2.
at /.../Spec.js:20577
Expected 0 to be 3.
Error: Expected 0 to be 3.
at /../Spec.js:20581
Expected 0 to be 3.
Error: Expected 0 to be 3.
Ran it in both Chrome and PhantomJS, same result, I'm going to go dig into Jasmine now...
Upvotes: 2
Views: 1671
Reputation: 511
I'm now using the jasmine-jquery library. Since I am using browserify to build everything, together with jQuery, it does not work to put the jasmine-jquery library in my karma.conf. Instead it must be included after jQuery, so it goes in the Spec.js:
var jasminejquery = require('jasmine-jquery');
Then add fixtures and trigger the click:
describe('Example', function() {
beforeEach(function(){
setFixtures('<body><div id="wrap"></div></body>');
});
it('should init application and draw stuff', function() {
var application = new App({container: 'body'});
// (...)
$('#sender').click();
});
});
and everything is working as expected.
Upvotes: 1