I have a Backbone Model:
class DateTimeSelector extends Backbone.Model initialize: -> @bind 'change:date', @updateDatetime @bind 'change:time', @updateDatetime updateDatetime: => # do some stuff with the sate and time
And I have some tests for that code using jasmin and sinon.js
describe "DateTimeSelector", -> beforeEach -> @datetime = new DateTimeSelector() describe "updateDatetime", -> beforeEach -> @updateSpy = sinon.spy(@datetime, 'updateDatetime') afterEach -> @datetime.updateDatetime.restore() # passes it "should be called when we call it", -> @datetime.updateDatetime() expect(@updateSpy).toHaveBeenCalledOnce() # fails it "should be called when we trigger it", -> @datetime.trigger 'change:date' expect(@updateSpy).toHaveBeenCalled() # fails it "should be called when we set the date", -> @datetime.set { date: new Date() } expect(@updateSpy).toHaveBeenCalled()
It seems to work when I use it in the browser but I can't seem to get the tests to pass. Can anyone enlighten me?
The function sinon. spy returns a Spy object, which can be called like a function, but also contains properties with information on any calls made to it. In the example above, the firstCall property has information about the first call, such as firstCall. args which is the list of arguments passed.
spy. Returns true if spy was called at least once with the provided arguments. Can be used for partial matching, Sinon only checks the provided arguments against actual arguments, so a call that received the provided arguments (in the same spots) and possibly others as well will return true .
Mocks allow you to create a fake function that passes or fails depending on your needs. You can ensure it was called with certain arguments, or check how many times it was called. You must call mock() on an object.
The sinon. stub() substitutes the real function and returns a stub object that you can configure using methods like callsFake() . Stubs also have a callCount property that tells you how many times the stub was called. For example, the below code stubs out axios.
duckyfuzz, you are experiencing this problem because when you are creating the spy (which actually wraps the original function and creates a level of indirection to insert its services of tracking method invocation) the binding of the events has already taken place. Which means that even though the spy wrapped the original function the event binding references the original function and not the wrapped spy. Hence, when you test, the original function gets executed on the event trigger but the spy tracking is one level above and is not executed.
To make sure that the event binding is actually pointing to the wrapped spy function you have to create the spy before create the model object (same goes if you are testing views). To do that create the spy on the prototype."method" of the class:
in the beforeEach -> section before @datetime = new DateTimeSelector() create the spy: @updateSpy = sinon.spy(DateTimeSelector.prototype, 'updateDatetime')
be sure to change your afterEach -> section where you return the prototype back to normal, like so: @updateSpy.restore()
this should be your code:
describe "DateTimeSelector", -> beforeEach -> @updateSpy = sinon.spy(DateTimeSelector.prototype, 'updateDatetime') @datetime = new DateTimeSelector() afterEach -> @updateSpy.restore() # passes it "should be called when we call it", -> @datetime.updateDatetime() expect(@updateSpy).toHaveBeenCalledOnce() # should pass now it "should be called when we trigger it", -> @datetime.trigger 'change:date' expect(@updateSpy).toHaveBeenCalled() # should pass now it "should be called when we set the date", -> @datetime.set { date: new Date() } expect(@updateSpy).toHaveBeenCalled()
BTW, if you are using jasmin-sinon.js plugin then your syntax is fine
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With