Skip to content

Instantly share code, notes, and snippets.

@danascheider
Last active February 13, 2017 21:03
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danascheider/64934f610eef19397406 to your computer and use it in GitHub Desktop.
Save danascheider/64934f610eef19397406 to your computer and use it in GitHub Desktop.
Testing Backbone View Events with Mocha, Chai, Sinon, and Require.js

This gist shows how to test events on Backbone views using Mocha, Chai, Sinon, and Require.js. The directory structure of the project being referenced, based on that of the Canto front end, can be found in my earlier gist about a related testing topic.

define([
'jquery',
'underscore',
'backbone',
'text!templates/partials/login-form.html',
], function($, _, Backbone, LoginFormTemplate) {
var LoginFormView = Backbone.View.extend({
template : _.template(LoginFormTemplate),
tagName : 'form',
id : 'login-form',
events : {
'submit' : 'loginUser',
'click .pull-right a' : 'loginHelp'
},
loginHelp : function() {
console.log('Haha you\'re boned!');
},
loginUser : function(e) {
// The content of this isn't the point
},
render : function() {
this.$el.html(this.template());
return this;
},
});
return LoginFormView;
});
define(['backbone', 'views/app/loginForm'], function(Backbone, LoginForm) {
describe('LoginForm', function() {
// Instantiate login form variable so it is available outside the beforeEach blocks
var loginForm;
describe('event handling', function() {
beforeEach(function() {
// Stub the event callback on the view's prototype BEFORE
// instantiating the view. This way, the stub will be in place before
// the events are bound when you call the constructor.
sinon.stub(LoginForm.prototype, 'loginHelp');
loginForm = new LoginForm();
loginForm.render();
});
afterEach(function() {
// Return everything to the way it was before
LoginForm.prototype.loginHelp.restore();
loginForm.remove();
});
it('listens for the click on the login help link', function() {
loginForm.$('.login-help-link').click();
LoginForm.prototype.loginHelp.calledOnce.should.be.true;
});
});
});
});
require.config([
paths: {
'jquery' : './lib/jquery-2.1.1',
'underscore' : './lib/underscore',
'backbone' : './lib/backbone',
'mocha' : './lib/mocha/mocha',
'chai' : './lib/chai/chai',
'chai-jquery' : './lib/chai/jquery',
'sinon' : './lib/sinon-1.12.1',
'sinon-chai' : './lib/sinon-chai',
'templates' : '../templates',
},
shim : {
'backbone' : {
deps : ['jquery', 'underscore'],
exports : 'Backbone'
},
'chai-jquery' : ['jquery', 'chai'],
'sinon-chai' : ['chai', 'sinon']
}
]);
require(['backbone', 'router'], function(Backbone, Router) {
this.router = new Router();
Backbone.history.start({root: '.'});
});
// This is only the relevant part of the router code. In my actual project,
// this is the very same router that handles the whole rest of my app. Nothing
// different or special about the spec runner - it's just another view.
define([
'backbone',
'views/spec/spec'
], function(Backbone, SpecRunner) {
var Router = Backbone.Router.extend({
routes : {
'spec(/)' : 'runSpec'
},
runSpec : function() {
this.specRunner = new SpecRunner({el: 'body'});
}
});
return Router;
});
define([
'jquery',
'underscore',
'backbone',
'css!lib/mocha/mocha.css',
], function($, _, Backbone) {
var SpecRunner = Backbone.View.extend({
template : _.template("<div id='mocha'></div>"),
initialize: function() {
this.render();
},
render: function() {
this.runSpecs();
this.$el.html(this.template());
},
runSpecs: function() {
require(['require', 'chai', 'sinon-chai', 'api', 'mocha', 'jquery', 'chai-jquery'], function(require, Chai, sinonChai, API) {
if (API.base.match(/localhost/)) { throw 'Connect to test API' }
var should = Chai.should();
Chai.use(sinonChai);
mocha.setup('bdd');
require(['spec/specHelper'], function(require) {
mocha.run();
});
});
}
});
return SpecRunner;
});
// This allows me to comment out a category of specs to only run certain ones,
// for example if I only want to run model specs.
define([
'spec/modelSpecs',
'spec/collectionSpecs',
'spec/viewSpecs'
]);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment