chaplinjs / chaplin

HTML5 application architecture using Backbone.js
http://chaplinjs.org
Other
2.85k stars 232 forks source link

In Controller tests: TypeError: Backbone.history is undefined #276

Closed starkovv closed 11 years ago

starkovv commented 11 years ago

Controller:

  ...
  myMethod: ->
    Backbone.history.navigate('#/login')
  ...

Test:

  ...
  it 'raises error of some reason', ->
    @controller.myMethod()

Error in console:

TypeError: Backbone.history is undefined

return Backbone.history.navigate('#/login');

WTF?

molily commented 11 years ago

If you test a controller independently (which is totally fine), the Backbone.History hasn’t been started. This is usually performed in the Chaplin Router on application startup. You have several options:

class FooController extends Chaplin.Controller
  theAction: ->
    @redirectTo '/login'

Test:

it 'should redirect to XYZ', ->
  spy = sinon.spy()
  mediator.subscribe '!router:route', spy
  controller.theAction()
  expect(spy).was.calledWith '/login'
  # Cleanup
  mediator.unsubscribe '!router:route', spy

Another way would be to spy on redirectTo directly.

spy = sinon.spy controller, 'redirectTo'
controller.theAction()
expect(spy).was.calledWith '/login'

(These examples are using Expect.js an Sinon.js syntax.)

HTH

starkovv commented 11 years ago

molily, thank you for your help. These two examples are perfect for my needs.

I think I'll choose first variant with Controller#redirectTo.

One more question: Am I right thinking that 'cleanup' is required only if I mock/stub global object (such as mediator or window) and it is not required if mock/stub instance object such as @controller (in case I create new instance of it for every spec)?

molily commented 11 years ago

Short answer: Yes! :)

starkovv commented 11 years ago

Thnx!