uris77
10/5/2013 - 8:01 AM

Testing Backbone Views

Testing Backbone Views

describe 'View', ->
  Given -> @model = {}
  Given -> @subject = new View
  
  Then -> expect(@subject.events).toEqual
    'click button': 'createAccount'
    'change input[name="login"]': 'checkAvailability'
    
  describe 'render', ->
    Given -> spyOn(JST, ['app/templates/sign-up-form.us'].andReturn(-> '<div id="woot" />')
    When -> @subject.render()
    Then -> @subject.$('#woot').length == 1
    
  describe 'createAccount', ->
    Given -> @subject.$el.affix['input[name="login"]').val('joe')
    Given -> @subject.$el.affix['input[name="email"]').val('joe@joe.com')
    Given -> @subject.$el.affix['input[name="password"]').val('notreallyjoe')
    Given -> @model.save = jasmine.createSpy('save')
    Given -> @event = fakeEvent()
    When -> @subject.createAccount(@event)
    Then -> expect(@event.preventDefault).toHaveBeenCalled()
    Then -> expect(@model.save).toHaveBeenCalled()
    Then -> expect(@model.save).toHaveBeenCalledWith
      login: 'joe'
      email: 'joe@joe.com'
      password: 'notreallyjoe'
      
    Given -> spyOn(app.PopOverWrapper, 'display')
    describe 'checkAvailability', ->
      Given -> @login = @subject.$el.affix('input[name="login"][value="fun!"]')
      Given -> @event = fakeEvent('change', @$login[0])
      Given -> spyOn($, 'get')
      Given -> @ajaxCallback = jasmine.captor()
      When -> @subject.checkAvailability(@event)
      And -> expect($.get).toHaveBeenCalledWith('/account_availability/fun', @ajaxCallback.capture)
      And -> @ajaxCallback.value(available: @available)
      
      context "the name is available", ->
        Given -> @available = true
        Then -> expect(app.Popover.display).toHaveBeenCalledWith(@$login[0], 'Available')
        
      context "the name is not available", ->
        Given -> @available = false
        Then -> expect(app.Popover.display).toHaveBeenCalledWith(@$login[0], "That name is not Available!")
        
    describe 'confirmPassword', ->
      Given -> @$password = @subject.$el.affix('input[name="password"][value="password"]')
      Given -> @$paswordConfirmation = @subject.$el.affix('input[name="passwordConfirmation"][value="password"]')
      Given -> @event = fakeEvent('change', @$passwordCnfirmation[0])
      When -> @subject.confirmPassword(@event)
      
        context 'matching password', ->
          Given -> spyOn(app.PopoverWrapper, 'clear')
          Then -> expect(app.PopoverWrapper.clear).toHaveBeenCalledWith(@$passwordConfirmation[0])
          
        context 'mismatching password', ->
          Given -> @passwordConfirmation.val("bar")
          Then -> expect(app.PopOverWrapper.display).toHaveBeenCalledWith(@$passwordConfirmation[0], "Passwords don't match")
      

### Routers ###
class app.Router extends Backbone.Router
  routes:
    'accounts/new': 'newAccount'
    '*path': 'defaultRoute'
    
  initialize: ->
    @$container = $('.container')
    
  defaultRoute: ->
    @navigate 'accounts/new', trigger: true
    
  newAccount: ->
    new app.SignupView
      el: @$container[0]
      model: new app.SignUp()
    .render()
    

### Spec ###
describe 'Router', ->
  Given -> @$container = affix('.container')
  Given -> @subject = new Router
  
  Then -> expect(@subject.routes).toEqual
    "accounts/new": "newAccount"
    "*path": "defaultRoute"
    
  describe "defaultRoute", ->
    When -> @subject.defaultRoute()
    Then -> window.location.hash == "#accounts/new"
    
  describe "newAccount", ->
    Given -> @signUpView = spyOnConstructor(app, 'SignUpView', ['render'])
    When -> @subject.newAccount()
    Then -> expect(@signUpView.constructor).toHaveBeenCalledWith
      el: @$container[0]
      model: any(app.SignUp)
    Then -> expect(@signUpView.render).toHaveBeenCalled()
      
      
### Look into argThat for testing constructor arguments. eg. new app.Signup({foo: 'berry'})