Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Cincinnati JS on 12/14/2011

Cincinnati JS on 12/14/2011

This talk is a mash-up talk of "I'm afraid of JavaScript" and "Jasmine Enhancers".
Want JavaScript help or training? Contact us at http://test-double.com

Justin Searls

December 14, 2011
Tweet

More Decks by Justin Searls

Other Decks in Programming

Transcript

  1. I'm afraid!
    of JavaScript

    View full-size slide

  2. Ahoy!
    new friend

    View full-size slide

  3. http://test-double.com

    View full-size slide

  4. every developer
    FEAR
    shares a secret

    View full-size slide

  5. ...my code sucks?
    WHAT IF

    View full-size slide

  6. AND WE COPE
    POORLY

    View full-size slide

  7. stupid things we do:
    we pair less often
    we share less often
    we change less often

    View full-size slide

  8. say it with me:
    “My Code Sucks”

    View full-size slide

  9. say it with me:
    “My Code Sucks”
    sometimes

    View full-size slide

  10. say it with me:
    “My Code Sucks”
    maybe

    View full-size slide

  11. say it with me:
    “My Code Sucks”
    if you say so

    View full-size slide

  12. SO FIGHT
    THE FEAR

    View full-size slide

  13. and
    fail
    PROUDLY

    View full-size slide

  14. as we talk!
    about JavaScript

    View full-size slide

  15. model
    STAGE 2

    View full-size slide

  16. model view
    STAGE 2

    View full-size slide

  17. model view dumping
    ground
    STAGE 2

    View full-size slide

  18. YOUR
    PAIR
    GRABS
    A CARD

    View full-size slide

  19. so you say,
    “let’s use JavaScript!”

    View full-size slide

  20. but your pair’s all like

    View full-size slide

  21. she says,
    “Start with the simplest
    thing that could possibly work!”

    View full-size slide

  22. !==
    simplest easiest

    View full-size slide

  23. !==
    simplest most
    familiar

    View full-size slide

  24. !==
    simplest
    calling a server
    to sort an
    array &
    render HTML
    for you

    View full-size slide

  25. so simple!‚

    View full-size slide

  26. WHAT
    GOOD
    ARE YOUR
    SERVERS?

    View full-size slide

  27. security
    persisting data
    analytics model behavior
    HTML templating
    routing users
    proxying UI events
    things servers are great at

    View full-size slide

  28. security
    persisting data
    analytics
    proxying
    things servers are great at

    View full-size slide

  29. model behavior
    HTML templating
    routing users
    UI events
    but it’s simpler when the client handles

    View full-size slide

  30. DON’T
    PANIC

    View full-size slide

  31. YOU’VE
    GOT
    THIS

    View full-size slide

  32. model behavior
    HTML templating
    routing users
    UI events

    View full-size slide

  33. model behavior
    HTML templating
    routing users
    UI events

    View full-size slide

  34. expect().toBe()

    View full-size slide

  35. expect().not.toBe()

    View full-size slide

  36. beforeEach()

    View full-size slide

  37. run it yourself!
    http://is.gd/logic1
    describe('CallList', function() {
    });

    View full-size slide

  38. run it yourself!
    http://is.gd/logic1
    describe('CallList', function() {
    describe("#moveUp", function() {
    });
    });

    View full-size slide

  39. run it yourself!
    http://is.gd/logic1
    describe('CallList', function() {
    describe("#moveUp", function() {
    context("moving up C", function() {
    });
    });
    });

    View full-size slide

  40. run it yourself!
    http://is.gd/logic1
    describe('CallList', function() {
    describe("#moveUp", function() {
    context("moving up C", function() {
    it("places it above B", function() {
    });
    });
    });
    });

    View full-size slide

  41. run it yourself!
    http://is.gd/logic1
    describe('CallList', function() {
    var subject;
    beforeEach(function() {
    subject = new CallList({items: ['A','B','C']});
    });
    describe("#moveUp", function() {
    context("moving up C", function() {
    it("places it above B", function() {
    });
    });
    });
    });

    View full-size slide

  42. run it yourself!
    http://is.gd/logic1
    describe('CallList', function() {
    var subject;
    beforeEach(function() {
    subject = new CallList({items: ['A','B','C']});
    });
    describe("#moveUp", function() {
    context("moving up C", function() {
    beforeEach(function() {
    subject.moveUp('C');
    });
    it("places it above B", function() {
    });
    });
    });
    });

    View full-size slide

  43. run it yourself!
    http://is.gd/logic1
    describe('CallList', function() {
    var subject;
    beforeEach(function() {
    subject = new CallList({items: ['A','B','C']});
    });
    describe("#moveUp", function() {
    context("moving up C", function() {
    beforeEach(function() {
    subject.moveUp('C');
    });
    it("places it above B", function() {
    expect(subject.get('items')).toEqual(['A','C','B']);
    });
    });
    });
    });

    View full-size slide

  44. run it yourself!
    http://is.gd/logic1

    View full-size slide

  45. run it yourself!
    http://is.gd/logic1
    window.CallList = Backbone.Model.extend({
    });

    View full-size slide

  46. run it yourself!
    http://is.gd/logic1
    window.CallList = Backbone.Model.extend({
    moveUp: function(item) {
    }
    });

    View full-size slide

  47. run it yourself!
    http://is.gd/logic1
    window.CallList = Backbone.Model.extend({
    moveUp: function(item) {
    this.set({items: ['A','C','B']});
    }
    });

    View full-size slide

  48. run it yourself!
    http://is.gd/logic1

    View full-size slide

  49. run it yourself!
    http://is.gd/logic2
    describe('CallList', function() {
    var subject;
    beforeEach(function() {
    subject = new CallList({items: ['A','B','C']});
    });
    describe("#moveUp", function() {
    context("moving up C", function() {...});
    context("moving up B", function() {
    });
    });
    });

    View full-size slide

  50. run it yourself!
    http://is.gd/logic2
    describe('CallList', function() {
    var subject;
    beforeEach(function() {
    subject = new CallList({items: ['A','B','C']});
    });
    describe("#moveUp", function() {
    context("moving up C", function() {...});
    context("moving up B", function() {
    it("places B above A", function() {
    });
    });
    });
    });

    View full-size slide

  51. run it yourself!
    http://is.gd/logic2
    describe('CallList', function() {
    var subject;
    beforeEach(function() {
    subject = new CallList({items: ['A','B','C']});
    });
    describe("#moveUp", function() {
    context("moving up C", function() {...});
    context("moving up B", function() {
    beforeEach(function() {
    subject.moveUp('B');
    });
    it("places B above A", function() {
    });
    });
    });
    });

    View full-size slide

  52. run it yourself!
    http://is.gd/logic2
    describe('CallList', function() {
    var subject;
    beforeEach(function() {
    subject = new CallList({items: ['A','B','C']});
    });
    describe("#moveUp", function() {
    context("moving up C", function() {...});
    context("moving up B", function() {
    beforeEach(function() {
    subject.moveUp('B');
    });
    it("places B above A", function() {
    expect(subject.get('items')).toEqual(['B','A','C']);
    });
    });
    });
    });

    View full-size slide

  53. run it yourself!
    http://is.gd/logic2

    View full-size slide

  54. run it yourself!
    http://is.gd/logic2
    window.CallList = Backbone.Model.extend({
    moveUp: function(item) {
    var items = this.get('items');
    }
    });

    View full-size slide

  55. run it yourself!
    http://is.gd/logic2
    window.CallList = Backbone.Model.extend({
    moveUp: function(item) {
    var items = this.get('items');
    var index = _(items).indexOf(item) - 1;
    }
    });

    View full-size slide

  56. run it yourself!
    http://is.gd/logic2
    window.CallList = Backbone.Model.extend({
    moveUp: function(item) {
    var items = this.get('items');
    var index = _(items).indexOf(item) - 1;
    items.splice(index,2,item,items[index]);
    }
    });

    View full-size slide

  57. run it yourself!
    http://is.gd/logic2

    View full-size slide

  58. run it yourself!
    http://is.gd/logic3
    describe('CallList', function() {
    var subject;
    beforeEach(function() {
    subject = new CallList({items: ['A','B','C']});
    });
    describe("#moveUp", function() {
    context("moving up C", function() {...});
    context("moving up B", function() {...});
    context("moving up A", function() {
    });
    });
    });

    View full-size slide

  59. run it yourself!
    http://is.gd/logic3
    describe('CallList', function() {
    var subject;
    beforeEach(function() {
    subject = new CallList({items: ['A','B','C']});
    });
    describe("#moveUp", function() {
    context("moving up C", function() {...});
    context("moving up B", function() {...});
    context("moving up A", function() {
    it("leaves the items as they were", function() {
    });
    });
    });
    });

    View full-size slide

  60. run it yourself!
    http://is.gd/logic3
    describe('CallList', function() {
    var subject;
    beforeEach(function() {
    subject = new CallList({items: ['A','B','C']});
    });
    describe("#moveUp", function() {
    context("moving up C", function() {...});
    context("moving up B", function() {...});
    context("moving up A", function() {
    beforeEach(function() {
    subject.moveUp('A');
    });
    it("leaves the items as they were", function() {
    });
    });
    });
    });

    View full-size slide

  61. run it yourself!
    http://is.gd/logic3
    describe('CallList', function() {
    var subject;
    beforeEach(function() {
    subject = new CallList({items: ['A','B','C']});
    });
    describe("#moveUp", function() {
    context("moving up C", function() {...});
    context("moving up B", function() {...});
    context("moving up A", function() {
    beforeEach(function() {
    subject.moveUp('A');
    });
    it("leaves the items as they were", function() {
    expect(subject.get('items')).toEqual(['A','B','C']);
    });
    });
    });
    });

    View full-size slide

  62. run it yourself!
    http://is.gd/logic3

    View full-size slide

  63. run it yourself!
    http://is.gd/logic3

    View full-size slide

  64. run it yourself!
    http://is.gd/logic3
    window.CallList = Backbone.Model.extend({
    moveUp: function(item) {
    var items = this.get('items');
    var index = _(items).indexOf(item) - 1;
    items.splice(index,2,item,items[index]);
    }
    });

    View full-size slide

  65. run it yourself!
    http://is.gd/logic3
    window.CallList = Backbone.Model.extend({
    moveUp: function(item) {
    var items = this.get('items');
    var index = _(items).indexOf(item) - 1;
    if(index >= 0) {
    items.splice(index,2,item,items[index]);
    }
    }
    });

    View full-size slide

  66. run it yourself!
    http://is.gd/logic3

    View full-size slide

  67. model behavior
    HTML templating
    routing users
    UI events

    View full-size slide

  68. model behavior
    HTML templating
    routing users
    UI events

    View full-size slide

  69. view
    model
    00 00

    View full-size slide

  70. view
    model
    00 00
    UI Event Occurs!
    “click .move-up”

    View full-size slide

  71. view
    model
    00 00
    this.model.moveUp(‘C’)

    View full-size slide

  72. view
    model
    00 00
    this.set({
    items:[‘A’,’C’,’B’]
    });

    View full-size slide

  73. view
    model
    00 00
    Model Event Fired!
    “change:items”

    View full-size slide

  74. view
    model
    00 00
    change:items bound!
    this.render()

    View full-size slide

  75. view
    model
    00 00

    View full-size slide

  76. view
    model
    00 00
    01

    View full-size slide

  77. and now
    you know
    backbone!

    View full-size slide

  78. run it yourself!
    http://is.gd/view1
    describe "CallListView", ->

    View full-size slide

  79. CoffeeScript

    View full-size slide

  80. function(){}

    View full-size slide

  81. employee.group.department.company.yuck

    View full-size slide

  82. employee.group.department.company.yuck
    TypeError: 'undefined' is not an object

    View full-size slide

  83. employee.group.department.company.yuck

    View full-size slide

  84. ?.
    enter the existential operator

    View full-size slide

  85. employee?.group?.department?.company?.yuck

    View full-size slide

  86. employee?.group?.department?.company?.yuck
    now, merely “undefined”

    View full-size slide

  87. employee?.group?.department?.company?.yuck
    now, merely “undefined”
    It’s Demeter-tastic!

    View full-size slide

  88. run it yourself!
    http://is.gd/view1
    describe "CallListView", ->
    describe "events", ->

    View full-size slide

  89. run it yourself!
    http://is.gd/view1
    describe "CallListView", ->
    describe "events", ->
    it "binds to up-arrow clicks", ->

    View full-size slide

  90. run it yourself!
    http://is.gd/view1
    describe "CallListView", ->
    beforeEach ->
    @subject = new CallListView
    describe "events", ->
    it "binds to up-arrow clicks", ->
    expect(@subject.events).toEqual "click .up-arrow": 'moveUp'

    View full-size slide

  91. run it yourself!
    http://is.gd/view1

    View full-size slide

  92. run it yourself!
    http://is.gd/view1
    class CallListView extends Backbone.View

    View full-size slide

  93. run it yourself!
    http://is.gd/view1
    class CallListView extends Backbone.View
    events:
    "click .up-arrow": "moveUp"

    View full-size slide

  94. run it yourself!
    http://is.gd/view1

    View full-size slide

  95. run it yourself!
    http://is.gd/view1

    View full-size slide

  96. run it yourself!
    http://is.gd/view1
    class CallListView extends Backbone.View
    events:
    "click .up-arrow": "moveUp"
    moveUp: ->

    View full-size slide

  97. run it yourself!
    http://is.gd/view1

    View full-size slide

  98. jasmine
    spies

    View full-size slide

  99. spyOn(object,‘method’)

    View full-size slide

  100. spyOn(object,‘method’)
    jasmine.createSpy(‘method’)

    View full-size slide

  101. spyOn(object,‘method’)
    jasmine.createSpy(‘method’)
    jasmine.createSpyObj(‘Name’,[‘method1’,‘method2’])

    View full-size slide

  102. spyOn(panda,‘isHappy’)

    View full-size slide

  103. spyOn(panda,‘isHappy’)
    panda.isHappy.andReturn(true)

    View full-size slide

  104. spyOn(panda,‘isHappy’)
    panda.isHappy.andReturn(true)
    panda.isHappy()

    View full-size slide

  105. spyOn(panda,‘isHappy’)
    panda.isHappy.andReturn(true)
    panda.isHappy()
    returns true

    View full-size slide

  106. spyOn(panda,‘feed’)

    View full-size slide

  107. spyOn(panda,‘feed’)
    panda.feed()

    View full-size slide

  108. spyOn(panda,‘feed’)
    expect(panda.feed).toHaveBeenCalled()
    panda.feed()

    View full-size slide

  109. run it yourself!
    http://is.gd/view2
    describe "CallListView", ->
    beforeEach ->
    @subject = new CallListView
    describe "events", ->
    it "binds to up-arrow clicks", ->
    expect(@subject.events).toEqual "click .up-arrow": 'moveUp'
    describe "#moveUp", ->
    it "tells the model to move up the arrow's text", ->

    View full-size slide

  110. run it yourself!
    http://is.gd/view2
    describe "CallListView", ->
    beforeEach ->
    @model = jasmine.createSpyObj('CallList',['bind','moveUp'])
    @subject = new CallListView model: @model
    describe "events", ->
    it "binds to up-arrow clicks", ->
    expect(@subject.events).toEqual "click .up-arrow": 'moveUp'
    describe "#moveUp", ->
    it "tells the model to move up the arrow's text", ->

    View full-size slide

  111. run it yourself!
    http://is.gd/view2
    describe "CallListView", ->
    beforeEach ->
    @model = jasmine.createSpyObj('CallList',['bind','moveUp'])
    @subject = new CallListView model: @model
    describe "events", ->
    it "binds to up-arrow clicks", ->
    expect(@subject.events).toEqual "click .up-arrow": 'moveUp'
    describe "#moveUp", ->
    beforeEach ->
    $upArrow = $(@subject.el).inject('up-arrow').text('C')
    it "tells the model to move up the arrow's text", ->

    View full-size slide

  112. run it yourself!
    http://is.gd/view2
    describe "CallListView", ->
    beforeEach ->
    @model = jasmine.createSpyObj('CallList',['bind','moveUp'])
    @subject = new CallListView model: @model
    describe "events", ->
    it "binds to up-arrow clicks", ->
    expect(@subject.events).toEqual "click .up-arrow": 'moveUp'
    describe "#moveUp", ->
    beforeEach ->
    $upArrow = $(@subject.el).inject('up-arrow').text('C')
    it "tells the model to move up the arrow's text", ->
    jasmine-fixture
    https://github.com/searls/jasmine-fixture

    View full-size slide

  113. run it yourself!
    http://is.gd/view2
    describe "CallListView", ->
    beforeEach ->
    @model = jasmine.createSpyObj('CallList',['bind','moveUp'])
    @subject = new CallListView model: @model
    describe "events", ->
    it "binds to up-arrow clicks", ->
    expect(@subject.events).toEqual "click .up-arrow": 'moveUp'
    describe "#moveUp", ->
    beforeEach ->
    $upArrow = $(@subject.el).inject('up-arrow').text('C')
    @subject.moveUp target: $upArrow[0]
    it "tells the model to move up the arrow's text", ->

    View full-size slide

  114. run it yourself!
    http://is.gd/view2
    describe "CallListView", ->
    beforeEach ->
    @model = jasmine.createSpyObj('CallList',['bind','moveUp'])
    @subject = new CallListView model: @model
    describe "events", ->
    it "binds to up-arrow clicks", ->
    expect(@subject.events).toEqual "click .up-arrow": 'moveUp'
    describe "#moveUp", ->
    beforeEach ->
    $upArrow = $(@subject.el).inject('up-arrow').text('C')
    @subject.moveUp target: $upArrow[0]
    it "tells the model to move up the arrow's text", ->
    expect(@model.moveUp).toHaveBeenCalledWith 'C'

    View full-size slide

  115. run it yourself!
    http://is.gd/view2

    View full-size slide

  116. run it yourself!
    http://is.gd/view2
    class CallListView extends Backbone.View
    events:
    "click .up-arrow": "moveUp"
    moveUp: (e) ->
    @model.moveUp $(e.target).text()

    View full-size slide

  117. run it yourself!
    http://is.gd/view2

    View full-size slide

  118. HTML templating
    model behavior routing users
    UI events

    View full-size slide

  119. HTML templating
    model behavior routing users
    UI events

    View full-size slide

  120. run it yourself!
    http://is.gd/template1
    describe "CallListView", ->
    beforeEach ->
    @model = jasmine.createSpyObj('CallList',['bind','moveUp'])
    @subject = new CallListView model: @model
    describe "events", -> ...
    describe "#moveUp", -> ...
    describe "#render", ->
    it "renders the template with the model's JSON", ->

    View full-size slide

  121. run it yourself!
    http://is.gd/template1
    describe "CallListView", ->
    beforeEach ->
    @model = jasmine.createSpyObj('CallList',['bind','moveUp'])
    @subject = new CallListView model: @model
    describe "events", -> ...
    describe "#moveUp", -> ...
    describe "#render", ->
    it "renders the template with the model's JSON", ->
    expect($(@subject.el)).toHaveHtml('HTML for bar')

    View full-size slide

  122. run it yourself!
    http://is.gd/template1
    describe "CallListView", ->
    beforeEach ->
    @model = jasmine.createSpyObj('CallList',['bind','moveUp'])
    @subject = new CallListView model: @model
    describe "events", -> ...
    describe "#moveUp", -> ...
    describe "#render", ->
    it "renders the template with the model's JSON", ->
    expect($(@subject.el)).toHaveHtml('HTML for bar')
    jasmine-jquery
    https://github.com/velesin/jasmine-jquery

    View full-size slide

  123. run it yourself!
    http://is.gd/template1
    describe "CallListView", ->
    beforeEach ->
    @model = jasmine.createSpyObj('CallList',['bind','moveUp'])
    @subject = new CallListView model: @model
    describe "events", -> ...
    describe "#moveUp", -> ...
    describe "#render", ->
    beforeEach ->
    @subject.render()
    it "renders the template with the model's JSON", ->
    expect($(@subject.el)).toHaveHtml('HTML for bar')

    View full-size slide

  124. run it yourself!
    http://is.gd/template1
    describe "CallListView", ->
    beforeEach ->
    @model = jasmine.createSpyObj('CallList',['bind','moveUp','toJSON'])
    @subject = new CallListView model: @model
    describe "events", -> ...
    describe "#moveUp", -> ...
    describe "#render", ->
    beforeEach ->
    @model.toJSON.andReturn foo: "bar"
    @subject.render()
    it "renders the template with the model's JSON", ->
    expect($(@subject.el)).toHaveHtml('HTML for bar')

    View full-size slide

  125. run it yourself!
    http://is.gd/template1
    describe "CallListView", ->
    beforeEach ->
    $template = inject('')
    $template.html('HTML for <%= foo %>')
    @model = jasmine.createSpyObj('CallList',['bind','moveUp','toJSON'])
    @subject = new CallListView model: @model
    describe "events", -> ...
    describe "#moveUp", -> ...
    describe "#render", ->
    beforeEach ->
    @model.toJSON.andReturn foo: "bar"
    @subject.render()
    it "renders the template with the model's JSON", ->
    expect($(@subject.el)).toHaveHtml('HTML for bar')

    View full-size slide

  126. run it yourself!
    http://is.gd/template1

    View full-size slide

  127. run it yourself!
    http://is.gd/template1
    class CallListView extends Backbone.View
    events:
    "click .up-arrow": "moveUp"
    initialize: ->
    @template = _.template($('#call-list-template').html())
    moveUp: (e) ->
    @model.moveUp $(e.target).text()

    View full-size slide

  128. run it yourself!
    http://is.gd/template1
    class CallListView extends Backbone.View
    events:
    "click .up-arrow": "moveUp"
    initialize: ->
    @template = _.template($('#call-list-template').html())
    moveUp: (e) ->
    @model.moveUp $(e.target).text()
    render: ->
    $(@el).html(@template(@model.toJSON()))

    View full-size slide

  129. run it yourself!
    http://is.gd/template1

    View full-size slide

  130. routing users
    HTML templating
    model behavior
    UI events

    View full-size slide

  131. routing users
    HTML templating
    model behavior
    UI events

    View full-size slide

  132. class AppRouter extends Backbone.Router
    routes:
    “call-list”: “callList”
    callList: ->
    new CallListView(model: new CallList).render()

    View full-size slide

  133. $ ->
    window.router = new AppRouter();
    Backbone.history.start();

    View full-size slide

  134. $ ->
    window.router = new AppRouter();
    Backbone.history.start();
    http://yourapp.dev/#call-list

    View full-size slide

  135. $ ->
    window.router = new AppRouter();
    Backbone.history.start();
    http://yourapp.dev/#call-list
    router.navigate('call-list',true)

    View full-size slide

  136. jasmine
    enhancers

    View full-size slide

  137. jasmine-given
    https://github.com/searls/jasmine-given

    View full-size slide

  138. beforeEach ->
    @subject = new Button()
    @result = @subject.press()
    it “goes ‘ohhh yeah’”
    expect(@result).toBe(‘ohhh yeah’)

    View full-size slide

  139. beforeEach ->
    @subject = new Button()
    @result = @subject.press()
    it “goes ‘ohhh yeah’”
    expect(@result).toBe(‘ohhh yeah’)
    Given

    View full-size slide

  140. beforeEach ->
    @subject = new Button()
    @result = @subject.press()
    it “goes ‘ohhh yeah’”
    expect(@result).toBe(‘ohhh yeah’)
    Given
    When

    View full-size slide

  141. beforeEach ->
    @subject = new Button()
    @result = @subject.press()
    it “goes ‘ohhh yeah’”
    expect(@result).toBe(‘ohhh yeah’)
    Given
    When
    Then

    View full-size slide

  142. beforeEach ->
    @subject = new Button()
    @result = @subject.press()
    it “goes ‘ohhh yeah’”
    expect(@result).toBe(‘ohhh yeah’)
    Given -> @subject = new Button()
    Given
    When
    Then

    View full-size slide

  143. beforeEach ->
    @subject = new Button()
    @result = @subject.press()
    it “goes ‘ohhh yeah’”
    expect(@result).toBe(‘ohhh yeah’)
    Given -> @subject = new Button()
    When -> @result = @subject.press()
    Given
    When
    Then

    View full-size slide

  144. beforeEach ->
    @subject = new Button()
    @result = @subject.press()
    it “goes ‘ohhh yeah’”
    expect(@result).toBe(‘ohhh yeah’)
    Given -> @subject = new Button()
    When -> @result = @subject.press()
    Then -> @result == “ohhh yeah”
    Given
    When
    Then

    View full-size slide

  145. When -> @config = createConfig()

    View full-size slide

  146. When -> @config = createConfig()
    Then -> @config.url == "http://moore.chris"

    View full-size slide

  147. When -> @config = createConfig()
    Then -> @config.url == "http://moore.chris"
    Then -> @config.name == "Peter Kananen"

    View full-size slide

  148. When -> @config = createConfig()
    Then -> @config.url == "http://moore.chris"
    Then -> @config.name == "Peter Kananen"
    Then -> @config.bestMochaFriend == "Josh Owens"

    View full-size slide

  149. When -> @config = createConfig()
    Then -> @config.url == "http://moore.chris"
    Then -> @config.name == "Peter Kananen"
    Then -> @config.bestMochaFriend == "Josh Owens"
    Then -> @config.bestDnDFriend == "James Smith"

    View full-size slide

  150. When -> @config = createConfig()
    Then -> @config.url == "http://moore.chris"
    Then -> @config.name == "Peter Kananen"
    Then -> @config.bestMochaFriend == "Josh Owens"
    Then -> @config.bestDnDFriend == "James Smith"

    View full-size slide

  151. When -> @config = createConfig()
    Then( -> @config.url == "http://moore.chris")
    .Then( -> @config.name == "Peter Kananen")
    .Then( -> @config.bestMochaFriend == "Josh Owens")
    .Then( -> @ config.bestDnDFriend == "James Smith")

    View full-size slide

  152. When -> @config = createConfig()
    Then( -> @config.url == "http://moore.chris")
    .Then( -> @config.name == "Peter Kananen")
    .Then( -> @config.bestMochaFriend == "Josh Owens")
    .Then( -> @ config.bestDnDFriend == "James Smith")

    View full-size slide

  153. jasmine-jquery
    https://github.com/velesin/jasmine-jquery

    View full-size slide

  154. $button = $(‘.win’);

    View full-size slide

  155. $button = $(‘.win’);
    Winning

    View full-size slide

  156. $button = $(‘.win’);
    Winning
    expect($button).toExist()

    View full-size slide

  157. $button = $(‘.win’);
    Winning
    expect($button).toExist()
    expect($button).toHaveAttr("id","yay")

    View full-size slide

  158. $button = $(‘.win’);
    Winning
    expect($button).toExist()
    expect($button).toHaveAttr("id","yay")
    expect($button).toHaveId("yay")

    View full-size slide

  159. $button = $(‘.win’);
    Winning
    expect($button).toBe('span.hidden')
    expect($button).toExist()
    expect($button).toHaveAttr("id","yay")
    expect($button).toHaveId("yay")

    View full-size slide

  160. $button = $(‘.win’);
    Winning
    expect($button).toBe('span.hidden')
    expect($button).toExist()
    expect($button).toHaveAttr("id","yay")
    expect($button).toHaveText("Winning")
    expect($button).toHaveId("yay")

    View full-size slide

  161. $button = $(‘.win’);
    Winning
    expect($button).toBe('span.hidden')
    expect($button).toExist()
    expect($button).toHaveAttr("id","yay")
    expect($button).toHaveText("Winning")
    expect($button).toHaveId("yay")
    expect($button).toHaveClass("hidden")

    View full-size slide

  162. jasmine-fixture
    https://github.com/searls/jasmine-fixture

    View full-size slide

  163. $foo = inject('foo')

    View full-size slide

  164. $foo = inject('foo')

    View full-size slide

  165. $foo = inject('foo')

    $bar = $foo.inject('bar')

    View full-size slide

  166. $foo = inject('foo')

    $bar = $foo.inject('bar')

    View full-size slide

  167. $foo = inject('foo')

    $bar = $foo.inject('bar')

    $input = $bar.inject(el: 'input', id: 'woot').val(42)

    View full-size slide

  168. $foo = inject('foo')

    $bar = $foo.inject('bar')

    $input = $bar.inject(el: 'input', id: 'woot').val(42)

    View full-size slide

  169. jasmine-stealth
    https://github.com/searls/jasmine-stealth

    View full-size slide

  170. spyOn(model,'get')

    View full-size slide

  171. spyOn(model,'get')
    model.get.andReturn('123-456-7890')

    View full-size slide

  172. spyOn(model,'get')
    model.get.andReturn('123-456-7890')
    model.get.andReturn('[email protected]')

    View full-size slide

  173. spyOn(model,'get')
    model.get.andReturn('123-456-7890')
    model.get.andReturn('[email protected]')
    model.get('email') #=> [email protected]

    View full-size slide

  174. spyOn(model,'get')
    model.get.andReturn('123-456-7890')
    model.get.andReturn('[email protected]')
    model.get('phone') #=> [email protected]
    model.get('email') #=> [email protected]

    View full-size slide

  175. spyOn(model,'get')

    View full-size slide

  176. spyOn(model,'get')
    model.get.when('phone').thenReturn('123-456-7890')

    View full-size slide

  177. spyOn(model,'get')
    model.get.when('phone').thenReturn('123-456-7890')
    model.get.when('email').thenReturn('[email protected]')

    View full-size slide

  178. spyOn(model,'get')
    model.get.when('phone').thenReturn('123-456-7890')
    model.get.when('email').thenReturn('[email protected]')
    model.get('phone') #=> 123-456-7890

    View full-size slide

  179. spyOn(model,'get')
    model.get.when('phone').thenReturn('123-456-7890')
    model.get.when('email').thenReturn('[email protected]')
    model.get('phone') #=> 123-456-7890
    model.get('email') #=> [email protected]

    View full-size slide

  180. jasmine-headless-webkit
    http://johnbintz.github.com/jasmine-headless-webkit/

    View full-size slide

  181. command-line runner

    View full-size slide

  182. github.com/searls
    +I’ll help!

    View full-size slide

  183. @searls
    +I’ll help!

    View full-size slide

  184. •g l e e * for the color scheme
    •clafouti for the despair statue
    •SteveFE for the pouting girl
    •ifollowtherabbit for another color scheme
    •mokra for the jaw-dropped baby
    •Epicality for the third color scheme
    credits

    View full-size slide