Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing a trigger click from a Backbone.View which opens a new Backbone.View

I have two Backbone Views, MainView and PopupView.

MainView contains a help button. When the help button handler is fired it shows the Backbone.View.

My question is how should I test this behavior from the MainView module?


Here's my code about MainView:

var MainView = Backbone.View.extend({
    events: {
        'click #help' : 'showPopUp'
    },

    showPopUp: function() {
       var popupView = new PopupView();
       app.vent.trigger('showModal', popupView);
    }    
});

Here's my code about the mainView.spec:

describe("When help button handler fired", function() {
    beforeEach(function() {
        this.view.render();
        this.view.$el.find('#help').trigger('click');
    });
    it("shows the popup", function() {
        // what should I do?
    });
});

Here's my code about the app:

var app = new Marionette.Application();

app.addRegions({
    header: '#header',
    sidebar: '#sidebar',
    main: '#main',
    modal: '#modal'
});

app.vent.on('showModal', function(view) {
    var modal = app.modal;

    modal.show(view);
    modal.$el.modal({
        show: true,
        keyboard: true,
        backdrop: 'static'
    });
});
like image 227
Lorraine Bernard Avatar asked Jul 19 '12 10:07

Lorraine Bernard


3 Answers

If you are using Sinon and Chai, you can try this:

describe("When help button handler fired", function() {
  beforeEach(function() {
      this.popupSpy = sinon.spy()
      app.vent.on('showModal', this.popupSpy);
      this.view.render();
      this.view.$el.find('#help').trigger('click');
  });
  it("shows the popup", function() {
      this.popupSpy.callCount.should.equal(1);
      this.popupSpy.args[0][0].should.be.an.instanceOf(PopupView);
  });
});
like image 146
Tanzeeb Khalili Avatar answered Nov 20 '22 15:11

Tanzeeb Khalili


So your Main View shouldn't open the popup, it shouldn't not even know that something like this exist. It should just notify the other modules via the eventbus that an popup should open by firing the event.

As you use app.vent I assume you're using marionette. In my project I have a Marionette.Region to handle an overlay view. And this region should open/close the view.

Doing it this way, its much easier to test. In the main view you can spy on the app.vent function and test that it will be execute when the button is clicked. In your region you can fire the event on app.vent and spy on your view.render function.

Creating new instances in your object you wanna test, makes testing always harder as it should be. Sure its easier in JavaScript, as in Java for example, cause you can override existing function on runtime in JavaScript, but using some way of dependency injection makes it always easier to mock and spy the dependencies.

like image 3
Andreas Köberle Avatar answered Nov 20 '22 15:11

Andreas Köberle


How about this:

describe("When help button handler fired", function() {
    var popupShown;

    beforeEach(function() {
        popupShown = false;

        this.view.render();
        app.vent.on('showModal', function() {
            popupShown = true;      
        });
        this.view.$el.find('#help').trigger('click');
    });
    it("shows the popup", function() {
        expect(popupShown).toBe(true);
    });
});

That said, I would recommend a few things:

  1. As was mentioned elsewhere, don't create the modal view in MainView. This couples the two too tightly.
  2. In your tests, you may want to say something like it("triggers the help event") or something similar. This is particularly important since you're unit testing that object in isolation. For integration testing, the opposite would be true.
  3. I'm not sure that you aren't doing too much in your beforeEach function. You may want to at least trigger the button click in the it scope, although based on what you're describeing, this may be OK.
like image 1
Jon Wingfield Avatar answered Nov 20 '22 16:11

Jon Wingfield