updates, time to do this

This commit is contained in:
John Bintz 2012-03-24 10:20:56 -04:00
parent c631bb6279
commit c654a753c5
13 changed files with 160 additions and 1570 deletions

3
.gitignore vendored
View File

@ -1,3 +1,4 @@
.DS_Store .DS_Store
.sass-cache/ .sass-cache/
_export/
_site/

View File

@ -11,6 +11,7 @@ PATH
pygments.rb pygments.rb
rack (~> 1.4.0) rack (~> 1.4.0)
rdiscount rdiscount
selenium-webdriver
sinatra sinatra
sprockets sprockets
sprockets-sass sprockets-sass
@ -53,6 +54,8 @@ GEM
rails (>= 3.0.0) rails (>= 3.0.0)
blankslate (2.1.2.4) blankslate (2.1.2.4)
builder (3.0.0) builder (3.0.0)
childprocess (0.3.1)
ffi (~> 1.0.6)
chunky_png (1.2.5) chunky_png (1.2.5)
coffee-script (2.2.0) coffee-script (2.2.0)
coffee-script-source coffee-script-source
@ -128,7 +131,13 @@ GEM
rubypython (0.5.3) rubypython (0.5.3)
blankslate (>= 2.1.2.3) blankslate (>= 2.1.2.3)
ffi (~> 1.0.7) ffi (~> 1.0.7)
rubyzip (0.9.6.1)
sass (3.1.15) sass (3.1.15)
selenium-webdriver (2.20.0)
childprocess (>= 0.2.5)
ffi (~> 1.0)
multi_json (~> 1.0)
rubyzip
sinatra (1.3.2) sinatra (1.3.2)
rack (~> 1.3, >= 1.3.6) rack (~> 1.3, >= 1.3.6)
rack-protection (~> 1.2) rack-protection (~> 1.2)

File diff suppressed because it is too large Load Diff

View File

@ -3,5 +3,7 @@ require 'rack-livereload'
Attentive.configure do |c| Attentive.configure do |c|
c.title = "Tea Time: A Beginner's Guide to Jasmine" c.title = "Tea Time: A Beginner's Guide to Jasmine"
c.middleware << Rack::LiveReload c.middleware << Rack::LiveReload
#c.export_size = '1280x1024'
end end

View File

@ -20,10 +20,8 @@
!SLIDE !SLIDE
# Fortunately, we're beyond that nowadays # Fortunately, we're beyond that nowadays
!SLIDE larger !SLIDE even-larger
``` ruby ``` ruby
require 'spec_helper'
describe MyCoolWebsite do describe MyCoolWebsite do
let(:website) { described_class.new } let(:website) { described_class.new }
@ -34,7 +32,8 @@ describe MyCoolWebsite do
let(:double_cool) { 'double cool' } let(:double_cool) { 'double cool' }
before do before do
website.stubs(:whoa_cool).returns(oh_yeah) website.stubs(:whoa_cool).
returns(oh_yeah)
end end
it { should == double_cool } it { should == double_cool }
@ -52,31 +51,38 @@ end
onmouseout="this.src='normal.gif'" /> onmouseout="this.src='normal.gif'" />
``` ```
!SLIDE !SLIDE even-larger
``` html ``` javascript
<script type="text/javascript">
function showMyCoolTitle(title, length) { function showMyCoolTitle(title, length) {
if (length == null) { length = 0; } if (length == null) { length = 0; }
if (length <= title.length) { if (length <= title.length) {
document.title = title.substr(0, length); document.title =
title.substr(0, length);
length++; length++;
setTimeout(function() { showMyCoolTitle(title, length); }, 75); setTimeout(function() {
showMyCoolTitle(title, length);
}, 75);
} }
} }
```
!SLIDE even-larger
``` javascript
window.onload = function() { window.onload = function() {
showMyCoolTitle("My cool website! Whoaaaaa!"); showMyCoolTitle(
"My cool website! Whoaaaaa!"
);
} }
</script>
``` ```
!SLIDE !SLIDE
# jQuery # jQuery
!SLIDE !SLIDE
# Backbone # Backbone.js
!SLIDE !SLIDE
# Sprockets and RequireJS # Sprockets and RequireJS
@ -84,10 +90,8 @@ window.onload = function() {
!SLIDE !SLIDE
# Automated testing is important # Automated testing is important
!SLIDE larger !SLIDE even-larger
``` ruby ``` ruby
require 'spec_helper'
describe MyCoolWebsite do describe MyCoolWebsite do
let(:website) { described_class.new } let(:website) { described_class.new }
@ -98,7 +102,8 @@ describe MyCoolWebsite do
let(:double_cool) { 'double cool' } let(:double_cool) { 'double cool' }
before do before do
website.stubs(:whoa_cool).returns(oh_yeah) website.stubs(:whoa_cool).
returns(oh_yeah)
end end
it { should == double_cool } it { should == double_cool }
@ -106,23 +111,22 @@ describe MyCoolWebsite do
end end
``` ```
!SLIDE larger !SLIDE even-larger
``` coffeescript ``` coffeescript
describe 'MyCoolWebsiteView', -> describe 'MyCoolWebsiteView', ->
website = null
beforeEach -> beforeEach ->
website = new MyCoolWebsiteView() @website = new MyCoolWebsiteView()
describe '#coolMethod', -> describe '#coolMethod', ->
doubleCool = 'double cool' doubleCool = 'double cool'
ohYeah = [ doubleCool ] ohYeah = [ doubleCool ]
beforeEach -> beforeEach ->
website.whoaCool = -> ohYeah @website.whoaCool = -> ohYeah
it 'should be double cool', -> it 'should be double cool', ->
expect(website.coolMethod()).toEqual(doubleCool) expect(@website.coolMethod()).
toEqual(doubleCool)
``` ```
!SLIDE !SLIDE

View File

@ -22,16 +22,17 @@ describe 'Cat', ->
!SLIDE image-80-percent !SLIDE image-80-percent
<img src="assets/cat-meow.jpg" /> <img src="assets/cat-meow.jpg" />
!SLIDE larger !SLIDE even-larger
``` coffeescript ``` coffeescript
describe 'Cat', -> describe 'Cat', ->
describe '#meow', -> describe '#meow', ->
# description of the meow behavior goes here # description of the
# meow behavior goes here
``` ```
!SLIDE !SLIDE larger
# John behavior #1 # John behavior #1
## Use Ruby-style indicators for instance- and class-level methods, even in Jasmine ## Use Ruby-style indicators for instance- and class-level methods
``` coffeescript ``` coffeescript
describe 'John', -> describe 'John', ->

View File

@ -29,7 +29,7 @@ describe 'Cat', ->
``` coffeescript ``` coffeescript
# code-under-test # code-under-test
class this.Cat class @Cat
meow: -> meow: ->
``` ```
@ -37,7 +37,6 @@ class this.Cat
``` javascript ``` javascript
// safety wrapper to prevent global pollution // safety wrapper to prevent global pollution
(function() { (function() {
// ...but we want to pollute the Cat class
this.Cat = (function() { this.Cat = (function() {
function Cat() {} function Cat() {}
Cat.prototype.meow = function() {}; Cat.prototype.meow = function() {};
@ -61,7 +60,7 @@ Expected undefined to equal 'meow'.
!SLIDE even-larger !SLIDE even-larger
``` coffeescript ``` coffeescript
class this.Cat class @Cat
meow: -> "meow" meow: -> "meow"
``` ```
@ -87,6 +86,6 @@ describe 'Cat', ->
``` coffeescript ``` coffeescript
# code-under-test # code-under-test
class this.Cat class @Cat
meow: -> "meow" meow: -> "meow"
``` ```

View File

@ -10,7 +10,7 @@
!SLIDE !SLIDE
# Nested `describe` # Nested `describe`
!SLIDE larger !SLIDE even-larger
``` coffeescript ``` coffeescript
describe 'Cat', -> describe 'Cat', ->
describe '#meow', -> describe '#meow', ->
@ -23,10 +23,8 @@ describe 'Cat', ->
# the cat knows it's vet time # the cat knows it's vet time
``` ```
!SLIDE larger !SLIDE even-larger
``` coffeescript ``` coffeescript
describe 'Cat', ->
describe '#meow', ->
describe 'hungry', -> describe 'hungry', ->
it 'should be a mournful meow', -> it 'should be a mournful meow', ->
cat = new Cat() cat = new Cat()
@ -34,7 +32,10 @@ describe 'Cat', ->
# ...just like cat.stubs(:state) # ...just like cat.stubs(:state)
expect(cat.meow()).toEqual("meeeyaow") expect(cat.meow()).toEqual("meeeyaow")
```
!SLIDE even-larger
``` coffeescript
describe 'going to the vet', -> describe 'going to the vet', ->
it 'should be an evil meow', -> it 'should be an evil meow', ->
cat = new Cat() cat = new Cat()
@ -95,19 +96,25 @@ it "should be in the same context", ->
expect(@instanceVariable).toEqual("yes") expect(@instanceVariable).toEqual("yes")
``` ```
!SLIDE larger !SLIDE even-larger
``` coffeescript ``` coffeescript
describe 'Cat', -> describe 'Cat', ->
describe '#meow', -> describe '#meow', ->
beforeEach -> beforeEach ->
@cat = new Cat() @cat = new Cat()
```
!SLIDE even-larger
``` coffeescript
describe 'hungry', -> describe 'hungry', ->
it 'should be a mournful meow', -> it 'should be a mournful meow', ->
@cat.state = -> Cat.HUNGRY @cat.state = -> Cat.HUNGRY
expect(@cat.meow()).toEqual("meeeyaow") expect(@cat.meow()).toEqual("meeeyaow")
```
!SLIDE even-larger
``` coffeescript
describe 'going to the vet', -> describe 'going to the vet', ->
it 'should be an evil meow', -> it 'should be an evil meow', ->
@cat.state = -> Cat.VET_PSYCHIC @cat.state = -> Cat.VET_PSYCHIC

View File

@ -15,7 +15,7 @@ describe 'Cat', ->
!SLIDE !SLIDE
# This works, but it can be clearer # This works, but it can be clearer
!SLIDE !SLIDE even-larger
``` ruby ``` ruby
describe Cat do describe Cat do
describe '#meow' do describe '#meow' do
@ -41,12 +41,13 @@ end
alias :context :describe alias :context :describe
``` ```
!SLIDE larger !SLIDE even-larger
``` ruby ``` ruby
describe Cat do describe Cat do
let(:cat) { described_class.new } let(:cat) { described_class.new }
# save describe for things or behaviors... # save describe for
# things or behaviors...
describe '#meow' do describe '#meow' do
subject { cat.meow } subject { cat.meow }
@ -110,7 +111,7 @@ describe 'Cat', ->
!SLIDE even-larger !SLIDE even-larger
``` coffeescript ``` coffeescript
class this.Cat class @Cat
@HUNGRY = 'hungry' @HUNGRY = 'hungry'
@VET_PSYCHIC = 'vet psychic' @VET_PSYCHIC = 'vet psychic'

View File

@ -12,7 +12,7 @@ cat.should_not be_hungry
!SLIDE even-larger !SLIDE even-larger
``` coffeescript ``` coffeescript
expect(cat.meow()).toEqual("meow") expect(cat.meow()).toEqual("meow")
expect(cat.prototype).toEqual(Cat.prototype) expect(cat.constructor).toEqual(Cat)
expect(cat.isHungry()).not.toBeTruthy() expect(cat.isHungry()).not.toBeTruthy()
``` ```
@ -46,7 +46,10 @@ MyMatchers =
beforeEach -> beforeEach ->
this.addMatchers(MyMatchers) this.addMatchers(MyMatchers)
```
!SLIDE even-larger
``` coffeescript
describe 'Cat', -> describe 'Cat', ->
beforeEach -> beforeEach ->
@cat = new Cat() @cat = new Cat()

View File

@ -36,19 +36,19 @@ describe 'John', ->
!SLIDE image-80-percent !SLIDE image-80-percent
<img src="assets/beer-cat.jpg" /> <img src="assets/beer-cat.jpg" />
!SLIDE larger !SLIDE even-larger
``` gherkin ``` gherkin
Feature: Cat Behaviors Feature: Cat Behaviors
Scenario: Hungry cats meow a particular way Scenario: Hungry cats meow a certain way
Given I have a cat Given I have a cat
And the cat is hungry And the cat is hungry
When the cat meows When the cat meows
Then the meow should sound like "meeyaow" Then the meow should be a "meeyaow"
``` ```
!SLIDE even-larger !SLIDE even-larger
``` coffeescript ``` coffeescript
class this.Cat class @Cat
@FOOD_THRESHOLD = 20 @FOOD_THRESHOLD = 20
@HUNGRY = 'hungry' @HUNGRY = 'hungry'
@ -64,7 +64,7 @@ class this.Cat
Cat.HUNGRY Cat.HUNGRY
``` ```
!SLIDE larger !SLIDE even-larger
``` coffeescript ``` coffeescript
describe 'Cat', -> describe 'Cat', ->
describe '#meow', -> describe '#meow', ->
@ -73,17 +73,19 @@ describe 'Cat', ->
cat = new Cat() cat = new Cat()
cat.foodLevel = 15 cat.foodLevel = 15
expect(cat.meow()).toEqual("meeeyaow") expect(cat.meow()).
toEqual("meeeyaow")
``` ```
!SLIDE !SLIDE
# A perfectly cromulent test # A perfectly cromulent test
!SLIDE larger !SLIDE even-larger
``` coffeescript ``` coffeescript
class this.Cat class @Cat
meow: -> meow: ->
switch this.state() # <= dependent code executed switch this.state()
# ^^^ dependent code executed
when Cat.HUNGRY when Cat.HUNGRY
"meeyaow" "meeyaow"
``` ```
@ -91,25 +93,24 @@ class this.Cat
!SLIDE !SLIDE
# Why make your unit tests fragile? # Why make your unit tests fragile?
!SLIDE larger !SLIDE even-larger
``` coffeescript ``` coffeescript
cat.foodLevel = 15 cat.foodLevel = 15
# do we care about food level in this test? # do we care about food level?
# all we care about is that the cat is hungry
``` ```
!SLIDE larger !SLIDE even-larger
``` coffeescript ``` coffeescript
describe 'Cat', -> describe 'Cat', ->
describe '#meow', -> describe '#meow', ->
describe 'hungry', -> context 'hungry', ->
it 'should be a mournful meow', -> it 'should be a mournful meow', ->
cat = new Cat() cat = new Cat()
cat.state = -> Cat.HUNGRY cat.state = -> Cat.HUNGRY
# ^^^ we don't care how state works, # ^^^ we just want a hungry cat
# we just want a hungry cat
expect(cat.meow()).toEqual("meeeyaow") expect(cat.meow()).
toEqual("meeeyaow")
``` ```
!SLIDE !SLIDE
@ -117,7 +118,7 @@ describe 'Cat', ->
## Just replace the method on the instance ## Just replace the method on the instance
``` coffeescript ``` coffeescript
class this.Cat class @Cat
state: -> state: ->
# cat codes # cat codes
@ -148,7 +149,7 @@ cat.state = -> "whatever"
!SLIDE even-larger !SLIDE even-larger
``` coffeescript ``` coffeescript
class this.Cat class @Cat
vocalProcessor: (speech) => vocalProcessor: (speech) =>
if this.isAirborne() if this.isAirborne()
this.modifyForAirborne(speech) this.modifyForAirborne(speech)
@ -156,7 +157,7 @@ class this.Cat
this.modifyForGround(speech) this.modifyForGround(speech)
``` ```
!SLIDE !SLIDE larger
``` coffeescript ``` coffeescript
describe 'Cat#vocalProcessor', -> describe 'Cat#vocalProcessor', ->
speech = "speech" speech = "speech"
@ -171,7 +172,8 @@ describe 'Cat#vocalProcessor', ->
it 'should be modified for flight', -> it 'should be modified for flight', ->
@cat.vocalProcessor(speech) @cat.vocalProcessor(speech)
expect(@cat.modifyForAirborne).toHaveBeenCalledWith(speech) expect(@cat.modifyForAirborne).
toHaveBeenCalledWith(speech)
``` ```
!SLIDE even-larger !SLIDE even-larger
@ -187,48 +189,53 @@ spyOn(@cat, 'modifyForAirborne')
!SLIDE !SLIDE
# Two basic ways to make sure a spy is called # Two basic ways to make sure a spy is called
!SLIDE !SLIDE even-larger
## `toHaveBeenCalledWith(args...)` ## `toHaveBeenCalledWith(args...)`
### Called least once with the given parameters ### Called least once with the given parameters
``` coffeescript ``` coffeescript
expect(@cat.modifyForAirborne).toHaveBeenCalledWith(speech) expect(@cat.modifyForAirborne).
toHaveBeenCalledWith(speech)
``` ```
!SLIDE !SLIDE even-larger
## `toHaveBeenCalled()` ## `toHaveBeenCalled()`
### Just called, no parameter check ### Just called, no parameter check
``` coffeescript ``` coffeescript
expect(@cat.modifyForAirborne).toHaveBeenCalled() expect(@cat.modifyForAirborne).
toHaveBeenCalled()
``` ```
!SLIDE larger !SLIDE even-larger
# Instance Mocks/Spies in JavaScript # Instance Mocks/Spies in JavaScript
## Use `spyOn`/`toHaveBeenCalled` matchers ## Use `spyOn`/`toHaveBeenCalled` matchers
``` coffeescript ``` coffeescript
class this.Cat class @Cat
state: -> state: ->
# cat codes # cat codes
cat = new Cat() cat = new Cat()
spyOn(cat, 'state') spyOn(cat, 'state')
expect(cat.state).toHaveBeenCalled() expect(cat.state).
toHaveBeenCalled()
``` ```
!SLIDE !SLIDE
# `spyOn` works great with class-level stubs and mocks, too # `spyOn` works great with class-level stubs and mocks, too
!SLIDE !SLIDE larger
``` coffeescript ``` coffeescript
class this.Cat class @Cat
@generateFurColor: (base) -> @generateFurColor: (base) ->
# magicks to make a fur color given a base # magicks to make a fur color given a base
regrowFur: (damagedHairs) -> regrowFur: (damagedHairs) ->
for follicle in damagedHairs for follicle in damagedHairs
follicle.regrow(Cat.generateFurColor(this.baseColor)) follicle.regrow(
Cat.generateFurColor(this.baseColor)
)
``` ```
!SLIDE larger !SLIDE larger
@ -237,26 +244,26 @@ Cat.generateFurColor = ->
"whoops i nuked this method for every other test" "whoops i nuked this method for every other test"
``` ```
!SLIDE !SLIDE larger
``` coffeescript ``` coffeescript
describe 'Cat#regrowFur', -> describe 'Cat#regrowFur', ->
color = 'color' color = 'color'
beforeEach -> beforeEach ->
@cat = new Cat() @cat = new Cat()
@follicle = @follicle = { regrow: -> null }
regrow: ->
@follicles = [ follicle ] @follicles = [ follicle ]
spyOn(Cat, 'generateFurColor').andReturn(color) spyOn(Cat, 'generateFurColor').
# ^^^ original is replaced when done # ^^^ original replaced when done
andReturn(color)
spyOn(@follicle, 'regrow') spyOn(@follicle, 'regrow')
it 'should regrow', -> it 'should regrow', ->
@cat.regrowFur(@follicles) @cat.regrowFur(@follicles)
expect(@follicle.regrow).toHaveBeenCalledWith(color) expect(@follicle.regrow).
toHaveBeenCalledWith(color)
``` ```
!SLIDE larger !SLIDE larger
@ -329,7 +336,7 @@ describe 'Cat#fetch', ->
!SLIDE !SLIDE
# Sometimes you just need a big blob of unit tests # Sometimes you just need a big blob of unit tests
!SLIDE !SLIDE larger
``` coffeescript ``` coffeescript
# fast and focused! # fast and focused!
@ -339,8 +346,11 @@ describe 'Cat#respondsTo', ->
context 'successes', -> context 'successes', ->
it 'should respond', -> it 'should respond', ->
for request in [ 'kitty kitty', 'pookums', 'hisshead' ] for request in [ 'kitty kitty',
expect(@cat.respondsTo(request)).toBeTruthy() 'pookums',
'hisshead' ]
expect(@cat.respondsTo(request)).
toBeTruthy()
``` ```
!SLIDE larger !SLIDE larger

View File

@ -7,16 +7,20 @@
!SLIDE !SLIDE
# Mocking and stubbing `$.fn` calls # Mocking and stubbing `$.fn` calls
!SLIDE !SLIDE even-larger
``` coffeescript ``` coffeescript
this.containerWaiter = -> this.containerWaiter = ->
$('#container').addClass('wait').append('<div class="waiting" />') $('#container').
addClass('wait').
append('<div class="waiting" />')
``` ```
!SLIDE !SLIDE even-larger
``` coffeescript ``` coffeescript
$.fn.makeWait = -> $.fn.makeWait = ->
$(this).addClass('wait').append('<div class="waiting" />') $(this).
addClass('wait').
append('<div class="waiting" />')
this this
``` ```
@ -29,7 +33,7 @@ this.containerWaiter = ->
!SLIDE !SLIDE
# `jquery-jasmine` # `jquery-jasmine`
!SLIDE larger !SLIDE even-larger
``` coffeescript ``` coffeescript
describe 'container', -> describe 'container', ->
beforeEach -> beforeEach ->
@ -37,8 +41,11 @@ describe 'container', ->
it 'should make it wait', -> it 'should make it wait', ->
containerWaiter() containerWaiter()
expect($('#container')).toHaveClass('wait')
expect($('#container')).toContain('div.waiting') expect($('#container')).
toHaveClass('wait')
expect($('#container')).
toContain('div.waiting')
``` ```
!SLIDE image-80-percent !SLIDE image-80-percent
@ -67,7 +74,8 @@ describe 'container', ->
it 'should make it wait', -> it 'should make it wait', ->
containerWaiter() containerWaiter()
expect($.fn.makeWait).toHaveBeenCalled() expect($.fn.makeWait).
toHaveBeenCalled()
``` ```
!SLIDE !SLIDE
@ -78,7 +86,7 @@ describe 'container', ->
!SLIDE even-larger !SLIDE even-larger
``` coffeescript ``` coffeescript
class Cat class @Cat
constructor: -> constructor: ->
@mood = "happy" @mood = "happy"

View File

@ -45,6 +45,4 @@ runs()
!SLIDE !SLIDE
# Thank you! # Thank you!
## [@johnbintz](http://twitter.com/johnbintz/)
## [GitHub](http://github.com/johnbintz/)