Skip to content

Instantly share code, notes, and snippets.

@alexbeletsky
Created December 18, 2012 19:07
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alexbeletsky/4330928 to your computer and use it in GitHub Desktop.
Save alexbeletsky/4330928 to your computer and use it in GitHub Desktop.
Backbone.View done with TDD
var Feedback = Backbone.Model.extend({
url: '/feedback',
validate: function (attrs) {
var errors = [];
if (!attrs.email || attrs.email === '') {
errors.push({name: 'email', message: 'Please fill email field.'});
}
if (!attrs.feedback || attrs.feedback === '') {
errors.push({name: 'feedback', message: 'Please fill feedback field.'});
}
return errors.length > 0 ? errors : false;
}
});
var FeedbackFormView = Backbone.View.extend({
className: 'row',
template: '\
<form>\
<legend>Share the feedback</legend>\
<div class="control-group email">\
<label>Email</label>\
<input type="text" id="email" placeholder="Your email address...">\
<span class="help-inline"></span>\
</div>\
<div class="control-group website">\
<label>Web site</label>\
<input type="text" id="website" placeholder="Your website...">\
<span class="help-inline"></span>\
</div>\
<div class="control-group feedback">\
<label>Feedback</label>\
<textarea id="feedback" class="input-xxlarge" placeholder="Feedback text..." rows="6"><%= feedback %></textarea>\
<span class="help-inline"></span>\
</div>\
<button type="submit" id="submit" class="btn">Submit</button>\
</form>\
',
events: {
'click #submit': 'submitClicked'
},
initialize: function (options) {
if (!this.model) {
throw new Error('model is required');
}
if (!(options && options.feedback)) {
throw new Error('feedback is required');
}
this.feedback = options.feedback;
},
render: function () {
this.$el.html(_.template(this.template, {feedback: this.feedback}));
return this;
},
submitClicked: function (e) {
e.preventDefault();
var me = this;
var options = {
success: function () {
me.hideErrors();
},
error: function (model, errors) {
me.showErrors(errors);
}
};
var feedback = {
email: this.$('#email').val(),
website: this.$('#website').val(),
feedback: this.$('#feedback').val()
};
this.model.save(feedback, options);
},
showErrors: function(errors) {
_.each(errors, function (error) {
var controlGroup = this.$('.' + error.name);
controlGroup.addClass('error');
controlGroup.find('.help-inline').text(error.message);
}, this);
},
hideErrors: function () {
this.$('.control-group').removeClass('error');
this.$('.help-inline').text('');
}
});
describe('FeedbackFormView.js spec', function () {
var view, model;
beforeEach(function () {
view = new FeedbackFormView({model: new Feedback(), feedback: 'TDD is awesome..' });
});
describe('when view is constructing', function () {
it ('should exist', function () {
expect(view).toBeDefined();
});
});
describe('when view is initialized', function () {
describe('without model', function () {
it('should throw exception', function () {
expect(function () {
new FeedbackFormView();
}).toThrow(new Error('model is required'));
});
});
describe('without default feedback', function () {
it('should throw exception', function () {
expect(function () {
new FeedbackFormView({model: new Backbone.Model() });
}).toThrow(new Error('feedback is required'));
});
});
});
describe('when view is rendered', function () {
beforeEach(function () {
view.render();
});
it ('should email field be empty', function () {
expect(view.$el.find('input#email')).toHaveValue('');
});
it ('should website field be empty', function () {
expect(view.$el.find('input#website')).toHaveValue('');
});
it ('should feedback field with default feedback', function () {
expect(view.$el.find('textarea#feedback')).toHaveValue('TDD is awesome..');
});
});
describe('when view is changing', function () {
beforeEach(function () {
view.render();
});
describe('when form is submitted', function () {
describe('no inputs are filled', function () {
beforeEach(function () {
view.$el.find('#email').val('').trigger('change');
view.$el.find('#feedback').val('').trigger('change');
});
beforeEach(function () {
view.$el.find('#submit').trigger('click');
});
it('email field should be invalidated', function () {
expect(view.$el.find('.control-group.email')).toHaveClass('error');
});
it('feedback field should be invalidated', function () {
expect(view.$el.find('.control-group.feedback')).toHaveClass('error');
});
it('website field should be valid', function () {
expect(view.$el.find('.control-group.website')).not.toHaveClass('error');
});
});
describe('only email field filled', function () {
beforeEach(function () {
view.$el.find('#email').val('a@a.com').trigger('change');
view.$el.find('#feedback').val('').trigger('change');
});
beforeEach(function () {
view.$el.find('#submit').trigger('click');
});
it('email field should be valid', function () {
expect(view.$el.find('.control-group.email')).not.toHaveClass('error');
});
it('feedback field should be invalidated', function () {
expect(view.$el.find('.control-group.feedback')).toHaveClass('error');
});
it('website field should be valid', function () {
expect(view.$el.find('.control-group.website')).not.toHaveClass('error');
});
});
describe('email and feedback filled', function () {
beforeEach(function () {
spyOn(view.model, 'save').andCallThrough();
});
beforeEach(function () {
view.$el.find('#email').val('a@a.com').trigger('change');
view.$el.find('#feedback').val('some feedback').trigger('change');
});
beforeEach(function () {
view.$el.find('#submit').trigger('click');
});
it('should show no errors', function () {
expect(view.$el.find('.error').length).toBe(0);
});
it('should save model', function () {
expect(view.model.save).toHaveBeenCalled();
});
});
});
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment