I'm using backbone.validation in order to validate my backbone Models and am employing a TDD approach to my work. Unfortunately I cannot seem to get my spy to be called when testing that fields are actually required.
I've been following the tutorial on Testing Backbone applications with Jasmine and Sinon
except when he registers his spy with "error"
I've tried registering mine with "invalid"
. The reason for this is because I think backbone.validation uses invalid/valid callbacks instead as described under the Events section of the readme.
My problem is that I'm getting errors saying that my spies are never called. I tried changing the bindings back to error/save but still have no luck.
My code is as follows:
class Event extends Backbone.Model
url: ->
'/events' + (if @isNew() then '' else '/' + @id)
validation:
title:
required: true
start_date:
required: true
end_date:
required: true
description:
required: true
I then define a test as follows:
describe "Event", ->
beforeEach ->
@title = "Foo"
@description = "Bar"
@start_date = new Date
@end_date = new Date
@event = new CPP.Models.Event {
title: @title
description: @description
start_date: @start_date
end_date: @end_date
}
describe "when saving required fields", ->
beforeEach ->
@error_spy = sinon.spy();
@event.bind('invalid', @error_spy)
it "should not save when title is empty", ->
@event.save 'title': ""
expect(@error_spy).toHaveBeenCalledOnce();
it "should not save when start_date is empty", ->
@event.save 'start_date': ""
expect(@error_spy).toHaveBeenCalledOnce();
it "should not save when end_date is empty", ->
@event.save 'end_date': ""l
expect(@error_spy).toHaveBeenCalledOnce();
it "should not save when description is empty", ->
@event.save 'description': ""
expect(@error_spy).toHaveBeenCalledOnce();
it "should not save when location is empty", ->
@event.save 'location': null
expect(@error_spy).toHaveBeenCalledOnce();
describe "when saving optional fields", ->
beforeEach ->
@success_spy = sinon.spy();
@event.bind('valid', @success_spy)
it "should save when deadline is empty", ->
@event.save 'deadline': ""
expect(@success_spy).toHaveBeenCalledOnce();
However when I run my tests I seem to get Error: Expected Function to have been called once.
for all of them and on further inspection of the @event object I find that the spy is never called.
I think it might be something to do with mixing in the validation on the Model's prototype via
_.extend(Backbone.Model.prototype, Backbone.Validation.mixin);
as defined on the backbone.validation readme, but I cannot seem to get this to work either.
I've had a look at the question Why is this sinon spy not being called when I run this test? however I've had no luck with incorporating the answer into my code either.
If anyone could tell me what I'm doing wrong I'd be very grateful!
Fixed
I managed to fix my code as follows:
(1) I added _.extend Backbone.Model::, Backbone.Validation.mixin
into my application
(2) I then followed the advice given in this question to bind my spy on initialize. The code now looks as follows: The model: class Event extends Backbone.Model url: -> '/events' + (if @isNew() then '' else '/' + @id)
validation:
title:
required: true
start_date:
required: true
end_date:
required: true
description:
required: true
The test:
describe "Event", ->
beforeEach ->
@title = "Foo"
@description = "Bar"
@start_date = new Date
@end_date = new Date
describe "when saving required fields", ->
beforeEach ->
spy = @error_spy = sinon.spy();
init = CPP.Models.Event::initialize
CPP.Models.Event::initialize = ->
spy(@, "validated:invalid")
init.call this
@event = new CPP.Models.Event {
title: @title
description: @description
location: @location
start_date: @start_date
end_date: @end_date
}
it "should not save when title is empty", ->
@event.save 'title': ""
expect(@error_spy).toHaveBeenCalledOnce();
it "should not save when start_date is empty", ->
@event.save 'start_date': ""
expect(@error_spy).toHaveBeenCalledOnce();
it "should not save when end_date is empty", ->
@event.save 'end_date': ""l
expect(@error_spy).toHaveBeenCalledOnce();
it "should not save when description is empty", ->
@event.save 'description': ""
expect(@error_spy).toHaveBeenCalledOnce();
it "should not save when location is empty", ->
@event.save 'location': null
expect(@error_spy).toHaveBeenCalledOnce();
describe "when saving optional fields", ->
beforeEach ->
spy = @success_spy = sinon.spy();
init = CPP.Models.Event::initialize
CPP.Models.Event::initialize = ->
spy(@, "validated:valid")
init.call this
@event = new CPP.Models.Event {
title: @title
description: @description
location: @location
start_date: @start_date
end_date: @end_date
}
it "should save when deadline is empty", ->
@event.save 'deadline': ""
expect(@success_spy).toHaveBeenCalledOnce();