initial commit
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.DS_Store
|
||||||
|
.sass-cache/
|
||||||
|
|
8
Gemfile
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
source :rubygems
|
||||||
|
|
||||||
|
gem 'attentive', :path => '../attentive'
|
||||||
|
gem 'rack-livereload'
|
||||||
|
|
||||||
|
gem 'guard'
|
||||||
|
gem 'guard-livereload'
|
||||||
|
|
155
Gemfile.lock
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
PATH
|
||||||
|
remote: ../attentive
|
||||||
|
specs:
|
||||||
|
attentive (0.0.1)
|
||||||
|
backbone-rails
|
||||||
|
coffee-script
|
||||||
|
compass (~> 0.12.rc)
|
||||||
|
haml
|
||||||
|
nokogiri
|
||||||
|
pygments.rb
|
||||||
|
rack (~> 1.4.0)
|
||||||
|
rdiscount
|
||||||
|
sinatra
|
||||||
|
sprockets
|
||||||
|
sprockets-sass
|
||||||
|
sprockets-vendor_gems
|
||||||
|
thor
|
||||||
|
|
||||||
|
GEM
|
||||||
|
remote: http://rubygems.org/
|
||||||
|
specs:
|
||||||
|
actionmailer (3.2.1)
|
||||||
|
actionpack (= 3.2.1)
|
||||||
|
mail (~> 2.4.0)
|
||||||
|
actionpack (3.2.1)
|
||||||
|
activemodel (= 3.2.1)
|
||||||
|
activesupport (= 3.2.1)
|
||||||
|
builder (~> 3.0.0)
|
||||||
|
erubis (~> 2.7.0)
|
||||||
|
journey (~> 1.0.1)
|
||||||
|
rack (~> 1.4.0)
|
||||||
|
rack-cache (~> 1.1)
|
||||||
|
rack-test (~> 0.6.1)
|
||||||
|
sprockets (~> 2.1.2)
|
||||||
|
activemodel (3.2.1)
|
||||||
|
activesupport (= 3.2.1)
|
||||||
|
builder (~> 3.0.0)
|
||||||
|
activerecord (3.2.1)
|
||||||
|
activemodel (= 3.2.1)
|
||||||
|
activesupport (= 3.2.1)
|
||||||
|
arel (~> 3.0.0)
|
||||||
|
tzinfo (~> 0.3.29)
|
||||||
|
activeresource (3.2.1)
|
||||||
|
activemodel (= 3.2.1)
|
||||||
|
activesupport (= 3.2.1)
|
||||||
|
activesupport (3.2.1)
|
||||||
|
i18n (~> 0.6)
|
||||||
|
multi_json (~> 1.0)
|
||||||
|
addressable (2.2.6)
|
||||||
|
arel (3.0.2)
|
||||||
|
backbone-rails (0.9.0)
|
||||||
|
rails (>= 3.0.0)
|
||||||
|
blankslate (2.1.2.4)
|
||||||
|
builder (3.0.0)
|
||||||
|
chunky_png (1.2.5)
|
||||||
|
coffee-script (2.2.0)
|
||||||
|
coffee-script-source
|
||||||
|
execjs
|
||||||
|
coffee-script-source (1.2.0)
|
||||||
|
compass (0.12.rc.1)
|
||||||
|
chunky_png (~> 1.2)
|
||||||
|
fssm (>= 0.2.7)
|
||||||
|
sass (~> 3.1)
|
||||||
|
em-websocket (0.3.6)
|
||||||
|
addressable (>= 2.1.1)
|
||||||
|
eventmachine (>= 0.12.9)
|
||||||
|
erubis (2.7.0)
|
||||||
|
eventmachine (0.12.10)
|
||||||
|
execjs (1.3.0)
|
||||||
|
multi_json (~> 1.0)
|
||||||
|
ffi (1.0.11)
|
||||||
|
fssm (0.2.8.1)
|
||||||
|
guard (1.0.0)
|
||||||
|
ffi (>= 0.5.0)
|
||||||
|
thor (~> 0.14.6)
|
||||||
|
guard-livereload (0.4.0)
|
||||||
|
em-websocket (>= 0.2.0)
|
||||||
|
guard (>= 0.10.0)
|
||||||
|
multi_json (~> 1.0.3)
|
||||||
|
haml (3.1.4)
|
||||||
|
hike (1.2.1)
|
||||||
|
i18n (0.6.0)
|
||||||
|
journey (1.0.3)
|
||||||
|
json (1.6.5)
|
||||||
|
mail (2.4.1)
|
||||||
|
i18n (>= 0.4.0)
|
||||||
|
mime-types (~> 1.16)
|
||||||
|
treetop (~> 1.4.8)
|
||||||
|
mime-types (1.17.2)
|
||||||
|
multi_json (1.0.4)
|
||||||
|
nokogiri (1.5.0)
|
||||||
|
polyglot (0.3.3)
|
||||||
|
pygments.rb (0.2.4)
|
||||||
|
rubypython (~> 0.5.3)
|
||||||
|
rack (1.4.1)
|
||||||
|
rack-cache (1.1)
|
||||||
|
rack (>= 0.4)
|
||||||
|
rack-livereload (0.3.4)
|
||||||
|
rack
|
||||||
|
rack-protection (1.2.0)
|
||||||
|
rack
|
||||||
|
rack-ssl (1.3.2)
|
||||||
|
rack
|
||||||
|
rack-test (0.6.1)
|
||||||
|
rack (>= 1.0)
|
||||||
|
rails (3.2.1)
|
||||||
|
actionmailer (= 3.2.1)
|
||||||
|
actionpack (= 3.2.1)
|
||||||
|
activerecord (= 3.2.1)
|
||||||
|
activeresource (= 3.2.1)
|
||||||
|
activesupport (= 3.2.1)
|
||||||
|
bundler (~> 1.0)
|
||||||
|
railties (= 3.2.1)
|
||||||
|
railties (3.2.1)
|
||||||
|
actionpack (= 3.2.1)
|
||||||
|
activesupport (= 3.2.1)
|
||||||
|
rack-ssl (~> 1.3.2)
|
||||||
|
rake (>= 0.8.7)
|
||||||
|
rdoc (~> 3.4)
|
||||||
|
thor (~> 0.14.6)
|
||||||
|
rake (0.9.2.2)
|
||||||
|
rdiscount (1.6.8)
|
||||||
|
rdoc (3.12)
|
||||||
|
json (~> 1.4)
|
||||||
|
rubypython (0.5.3)
|
||||||
|
blankslate (>= 2.1.2.3)
|
||||||
|
ffi (~> 1.0.7)
|
||||||
|
sass (3.1.15)
|
||||||
|
sinatra (1.3.2)
|
||||||
|
rack (~> 1.3, >= 1.3.6)
|
||||||
|
rack-protection (~> 1.2)
|
||||||
|
tilt (~> 1.3, >= 1.3.3)
|
||||||
|
sprockets (2.1.2)
|
||||||
|
hike (~> 1.2)
|
||||||
|
rack (~> 1.0)
|
||||||
|
tilt (~> 1.1, != 1.3.0)
|
||||||
|
sprockets-sass (0.6.0)
|
||||||
|
sprockets (~> 2.0)
|
||||||
|
tilt (~> 1.1)
|
||||||
|
sprockets-vendor_gems (0.1.1)
|
||||||
|
thor (0.14.6)
|
||||||
|
tilt (1.3.3)
|
||||||
|
treetop (1.4.10)
|
||||||
|
polyglot
|
||||||
|
polyglot (>= 0.3.1)
|
||||||
|
tzinfo (0.3.31)
|
||||||
|
|
||||||
|
PLATFORMS
|
||||||
|
ruby
|
||||||
|
|
||||||
|
DEPENDENCIES
|
||||||
|
attentive!
|
||||||
|
guard
|
||||||
|
guard-livereload
|
||||||
|
rack-livereload
|
4
Guardfile
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
guard 'livereload' do
|
||||||
|
watch(%r{^(assets|presentation)})
|
||||||
|
end
|
||||||
|
|
BIN
assets/images/balancing-cat.jpg
Normal file
After Width: | Height: | Size: 42 KiB |
BIN
assets/images/beer-cat.jpg
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
assets/images/cat-carrier.jpg
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
assets/images/cat-meow.jpg
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
assets/images/checklist.png
Normal file
After Width: | Height: | Size: 171 KiB |
BIN
assets/images/dark-side-nyan-cat.jpg
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
assets/images/flying-cat.jpg
Normal file
After Width: | Height: | Size: 140 KiB |
BIN
assets/images/hungry-cat.jpg
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
assets/images/john-drinking-tea.png
Normal file
After Width: | Height: | Size: 138 KiB |
BIN
assets/images/relevant-cat.jpg
Normal file
After Width: | Height: | Size: 201 KiB |
BIN
assets/images/spaghetti.jpg
Normal file
After Width: | Height: | Size: 106 KiB |
BIN
assets/images/spy-cat.jpg
Normal file
After Width: | Height: | Size: 26 KiB |
BIN
assets/images/synergize.gif
Normal file
After Width: | Height: | Size: 43 B |
BIN
assets/images/synergize.jpg
Normal file
After Width: | Height: | Size: 109 KiB |
BIN
assets/images/wet-cat.jpg
Normal file
After Width: | Height: | Size: 26 KiB |
4
assets/javascripts/application.js.coffee
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#= require attentive
|
||||||
|
#
|
||||||
|
Attentive.Presentation.setup('#slides')
|
||||||
|
|
43
assets/stylesheets/application.css.scss
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
@import 'attentive';
|
||||||
|
|
||||||
|
$color: #d4d2bf;
|
||||||
|
|
||||||
|
body, html {
|
||||||
|
background-color: $color;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2, h3 {
|
||||||
|
font-family: Acme, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.highlight {
|
||||||
|
background-color: adjust-lightness($color, -10);
|
||||||
|
}
|
||||||
|
|
||||||
|
.style-image-80-percent {
|
||||||
|
img {
|
||||||
|
height: 80%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#slides {
|
||||||
|
@include transition-duration(0.3s);
|
||||||
|
}
|
||||||
|
|
||||||
|
#intro {
|
||||||
|
width: 90%;
|
||||||
|
|
||||||
|
@include clearfix;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 30%;
|
||||||
|
@include float-left;
|
||||||
|
}
|
||||||
|
|
||||||
|
div {
|
||||||
|
width: 70%;
|
||||||
|
@include float-right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
7
presentation.rb
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
require 'rack-livereload'
|
||||||
|
|
||||||
|
Attentive.configure do |c|
|
||||||
|
c.title = "Tea Time: A Beginner's Guide to Jasmine"
|
||||||
|
c.middleware << Rack::LiveReload
|
||||||
|
end
|
||||||
|
|
137
presentation/01_intro.slides
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
!SLIDE
|
||||||
|
<div id="intro">
|
||||||
|
<img src="assets/john-drinking-tea.png" />
|
||||||
|
<div>
|
||||||
|
<h1>Tea Time</h1>
|
||||||
|
<h2>A Beginner's Guide to JavaScript Testing using Jasmine</h2>
|
||||||
|
<h3>By John Bintz</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Automated testing is important
|
||||||
|
|
||||||
|
!SLIDE image-80-percent
|
||||||
|
<img src="assets/checklist.png" />
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Fortunately, we're beyond that nowadays
|
||||||
|
|
||||||
|
!SLIDE larger
|
||||||
|
``` ruby
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe MyCoolWebsite do
|
||||||
|
let(:website) { described_class.new }
|
||||||
|
|
||||||
|
describe '#cool_method' do
|
||||||
|
subject { website.cool_method }
|
||||||
|
|
||||||
|
let(:oh_yeah) { [ double_cool ] }
|
||||||
|
let(:double_cool) { 'double cool' }
|
||||||
|
|
||||||
|
before do
|
||||||
|
website.stubs(:whoa_cool).returns(oh_yeah)
|
||||||
|
end
|
||||||
|
|
||||||
|
it { should == double_cool }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# But there's more to web apps than Ruby nowadays...
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` html
|
||||||
|
<img src="normal.gif"
|
||||||
|
onmouseover="this.src='hover.gif'"
|
||||||
|
onmouseout="this.src='normal.gif'" />
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE larger
|
||||||
|
``` html
|
||||||
|
<script type="text/javascript">
|
||||||
|
function showMyCoolTitle(title, length) {
|
||||||
|
if (length == null) { length = 0; }
|
||||||
|
|
||||||
|
if (length < title.length) {
|
||||||
|
document.title = title.substr(0, length);
|
||||||
|
length++;
|
||||||
|
|
||||||
|
setTimeout(function() { showMyCoolTitle(title, length); }, 75);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.onload = function() { showMyCoolTitle("My cool website! Whoaaaaa!"); }
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# jQuery
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Backbone
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Sprockets and RequireJS
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Automated testing is important
|
||||||
|
|
||||||
|
!SLIDE larger
|
||||||
|
``` ruby
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe MyCoolWebsite do
|
||||||
|
let(:website) { described_class.new }
|
||||||
|
|
||||||
|
describe '#cool_method' do
|
||||||
|
subject { website.cool_method }
|
||||||
|
|
||||||
|
let(:oh_yeah) { [ double_cool ] }
|
||||||
|
let(:double_cool) { 'double cool' }
|
||||||
|
|
||||||
|
before do
|
||||||
|
website.stubs(:whoa_cool).returns(oh_yeah)
|
||||||
|
end
|
||||||
|
|
||||||
|
it { should == double_cool }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE larger
|
||||||
|
``` coffeescript
|
||||||
|
describe 'MyCoolWebsiteView', ->
|
||||||
|
website = null
|
||||||
|
|
||||||
|
beforeEach ->
|
||||||
|
website = new MyCoolWebsiteView()
|
||||||
|
|
||||||
|
describe '#coolMethod', ->
|
||||||
|
doubleCool = 'double cool'
|
||||||
|
ohYeah = [ doubleCool ]
|
||||||
|
|
||||||
|
beforeEach ->
|
||||||
|
website.whoaCool = -> ohYeah
|
||||||
|
|
||||||
|
it 'should be double cool', ->
|
||||||
|
expect(website.coolMethod()).toEqual(doubleCool)
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Jasmine
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# BDD unit testing framework for JavaScript
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Platform independent
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Easily extended
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Very easy to learn!
|
||||||
|
|
27
presentation/02_follow_along.slides
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
!SLIDE
|
||||||
|
# Follow along!
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# [johnbintz.github.com/tea-time](http://johnbintz.github.com/tea-time/)
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# No need to install anything right now
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# [tryjasmine.com](http://tryjasmine.com/)
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Specs on the left
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Code under test on the right
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Write code in CoffeeScript
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Ready?
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Let's go!
|
||||||
|
|
61
presentation/03_describe_and_it.slides
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
!SLIDE
|
||||||
|
# `describe`
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Describes a thing or a behavior of a thing
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Let's describe...
|
||||||
|
|
||||||
|
!SLIDE image-80-percent
|
||||||
|
<img src="assets/relevant-cat.jpg" />
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
describe 'Cat', ->
|
||||||
|
# cat behavior descriptions go here
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Something that cats do...
|
||||||
|
|
||||||
|
!SLIDE image-80-percent
|
||||||
|
<img src="assets/cat-meow.jpg" />
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
describe 'Cat', ->
|
||||||
|
describe '#meow', ->
|
||||||
|
# description of the meow behavior goes here
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# John behavior #1
|
||||||
|
## Use Ruby-style indicators for instance- and class-level methods, even in Jasmine
|
||||||
|
|
||||||
|
``` coffeescript
|
||||||
|
describe 'John', ->
|
||||||
|
describe 'spec definitions', ->
|
||||||
|
it 'should look like you did it in RSpec', ->
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Describe how we expect a cat to meow
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# `it`
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
describe 'Cat', ->
|
||||||
|
describe '#meow', ->
|
||||||
|
it 'should meow correctly', ->
|
||||||
|
# expectation of a cat meowing
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# We have the description...
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Now let's add the expectations!
|
||||||
|
|
92
presentation/04_expect.slides
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
!SLIDE
|
||||||
|
# `expect`
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# What should we get as an output?
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
describe 'Cat', ->
|
||||||
|
describe '#meow', ->
|
||||||
|
it 'should meow correctly', ->
|
||||||
|
expect(cat.meow()).toEqual('meow')
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Wait, we need a cat.
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
describe 'Cat', ->
|
||||||
|
describe '#meow', ->
|
||||||
|
it 'should meow correctly', ->
|
||||||
|
cat = new Cat()
|
||||||
|
|
||||||
|
expect(cat.meow()).toEqual('meow')
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
# code-under-test
|
||||||
|
|
||||||
|
class this.Cat
|
||||||
|
meow: ->
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` javascript
|
||||||
|
// safety wrapper to prevent global pollution
|
||||||
|
(function() {
|
||||||
|
// ...but we want to pollute the Cat class
|
||||||
|
this.Cat = (function() {
|
||||||
|
function Cat() {}
|
||||||
|
Cat.prototype.meow = function() {};
|
||||||
|
return Cat;
|
||||||
|
})();
|
||||||
|
})(this) // this is window in a browser
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Run it!
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
```
|
||||||
|
1 spec, 1 failure
|
||||||
|
|
||||||
|
Expected undefined to equal 'meow'.
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Make it meow!
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
class this.Cat
|
||||||
|
meow: -> "meow"
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
```
|
||||||
|
1 spec, 0 failures
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Here's what you should have meow...
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
# spec
|
||||||
|
|
||||||
|
describe 'Cat', ->
|
||||||
|
describe '#meow', ->
|
||||||
|
it 'should meow correctly', ->
|
||||||
|
expect(cat.meow()).toEqual('meow')
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
# code-under-test
|
||||||
|
|
||||||
|
class this.Cat
|
||||||
|
meow: -> "meow"
|
||||||
|
```
|
113
presentation/05_meow_states.slides
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
!SLIDE
|
||||||
|
# What if the cat meows differently based on certain states?
|
||||||
|
|
||||||
|
!SLIDE image-80-percent
|
||||||
|
<img src="assets/hungry-cat.jpg" />
|
||||||
|
|
||||||
|
!SLIDE image-80-percent
|
||||||
|
<img src="assets/cat-carrier.jpg" />
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Nested `describe`
|
||||||
|
|
||||||
|
!SLIDE larger
|
||||||
|
``` coffeescript
|
||||||
|
describe 'Cat', ->
|
||||||
|
describe '#meow', ->
|
||||||
|
describe 'hungry', ->
|
||||||
|
# Cat#meow expectation for when the cat is hungry
|
||||||
|
|
||||||
|
describe 'going to the vet', ->
|
||||||
|
# Cat#meow expectation for when the cat knows it's vet time
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE larger
|
||||||
|
``` coffeescript
|
||||||
|
describe 'Cat', ->
|
||||||
|
describe '#meow', ->
|
||||||
|
describe 'hungry', ->
|
||||||
|
it 'should be a mournful meow', ->
|
||||||
|
cat = new Cat()
|
||||||
|
cat.state = -> Cat.HUNGRY # ...just like cat.stubs(:state)
|
||||||
|
|
||||||
|
expect(cat.meow()).toEqual("meeeyaow")
|
||||||
|
|
||||||
|
describe 'going to the vet', ->
|
||||||
|
it 'should be an evil meow', ->
|
||||||
|
cat = new Cat()
|
||||||
|
cat.state = -> Cat.VET_PSYCHIC # ...just like the one above
|
||||||
|
|
||||||
|
expect(cat.meow()).toEqual("raowwww")
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE image-80-percent
|
||||||
|
<img src="assets/wet-cat.jpg" />
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
cat = new Cat()
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` ruby
|
||||||
|
before do
|
||||||
|
@cat = Cat.new
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should be a mournful meow' do
|
||||||
|
@cat.stubs(:state).returns(Cat::HUNGRY)
|
||||||
|
|
||||||
|
@cat.meow.should == "meeyaow"
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` ruby
|
||||||
|
before -> it -> after
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` ruby
|
||||||
|
before do
|
||||||
|
@instance_variable = "yes"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should be in the same context as the before block" do
|
||||||
|
@instance_variable.should == "yes"
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
beforeEach -> it -> afterEach
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
beforeEach ->
|
||||||
|
@instanceVariable = "yes"
|
||||||
|
|
||||||
|
it "should be in the same context", ->
|
||||||
|
expect(@instanceVariable).toEqual("yes")
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE larger
|
||||||
|
``` coffeescript
|
||||||
|
describe 'Cat', ->
|
||||||
|
describe '#meow', ->
|
||||||
|
beforeEach ->
|
||||||
|
@cat = new Cat()
|
||||||
|
|
||||||
|
describe 'hungry', ->
|
||||||
|
it 'should be a mournful meow', ->
|
||||||
|
@cat.state = -> Cat.HUNGRY
|
||||||
|
|
||||||
|
expect(@cat.meow()).toEqual("meeeyaow")
|
||||||
|
|
||||||
|
describe 'going to the vet', ->
|
||||||
|
it 'should be an evil meow', ->
|
||||||
|
@cat.state = -> Cat.VET_PSYCHIC
|
||||||
|
|
||||||
|
expect(@cat.meow()).toEqual("raowwww")
|
||||||
|
```
|
||||||
|
|
129
presentation/06_context.slides
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
!SLIDE
|
||||||
|
# A little semantics game...
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
describe 'Cat', ->
|
||||||
|
describe '#meow', ->
|
||||||
|
describe 'hungry', ->
|
||||||
|
# cat codes
|
||||||
|
|
||||||
|
describe 'going to the vet', ->
|
||||||
|
# moar cat codes
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# This works, but it can be clearer
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
``` ruby
|
||||||
|
describe Cat do
|
||||||
|
describe '#meow' do
|
||||||
|
describe 'hungry' do
|
||||||
|
# cat codes
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'going to the vet' do
|
||||||
|
# moar cat codes
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# `context`
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Description of different states for a test
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` ruby
|
||||||
|
alias :context :describe
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE larger
|
||||||
|
``` ruby
|
||||||
|
describe Cat do
|
||||||
|
let(:cat) { described_class.new }
|
||||||
|
|
||||||
|
# save describe for things or behaviors...
|
||||||
|
describe '#meow' do
|
||||||
|
subject { cat.meow }
|
||||||
|
|
||||||
|
# use context to describe states
|
||||||
|
context 'hungry' do
|
||||||
|
# cat codes
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'going to the vet' do
|
||||||
|
# moar cat codes
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Jasmine doesn't have `context`
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# However...
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
this.context = this.describe
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
this.context = this.describe
|
||||||
|
|
||||||
|
describe 'Cat', ->
|
||||||
|
describe '#meow', ->
|
||||||
|
context 'hungry', ->
|
||||||
|
# cat codes
|
||||||
|
|
||||||
|
context 'going to the vet', ->
|
||||||
|
# moar cat codes
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE larger
|
||||||
|
``` coffeescript
|
||||||
|
this.context = this.describe
|
||||||
|
|
||||||
|
describe 'Cat', ->
|
||||||
|
describe '#meow', ->
|
||||||
|
beforeEach ->
|
||||||
|
@cat = new Cat()
|
||||||
|
|
||||||
|
context 'hungry', ->
|
||||||
|
it 'should be a mournful meow', ->
|
||||||
|
@cat.state = -> Cat.HUNGRY
|
||||||
|
|
||||||
|
expect(@cat.meow()).toEqual("meeeyaow")
|
||||||
|
|
||||||
|
context 'going to the vet', ->
|
||||||
|
it 'should be an evil meow', ->
|
||||||
|
@cat.state = -> Cat.VET_PSYCHIC
|
||||||
|
|
||||||
|
expect(@cat.meow()).toEqual("raowwww")
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
class this.Cat
|
||||||
|
@HUNGRY = 'hungry'
|
||||||
|
@VET_PSYCHIC = 'vet psychic'
|
||||||
|
|
||||||
|
meow: ->
|
||||||
|
switch this.state()
|
||||||
|
when Cat.HUNGRY
|
||||||
|
"meeeyaow"
|
||||||
|
when Cat.VET_PSYCHIC
|
||||||
|
"raowwww"
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
```
|
||||||
|
2 spec, 0 failures
|
||||||
|
```
|
||||||
|
|
56
presentation/07_matchers.slides
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
!SLIDE
|
||||||
|
# Matchers
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` ruby
|
||||||
|
cat.meow.should == "meow"
|
||||||
|
cat.should be_a_kind_of(Cat)
|
||||||
|
cat.should_not be_hungry #=> cat.hungry?.should == false
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
expect(cat.meow()).toEqual("meow")
|
||||||
|
expect(cat.prototype).toEqual(Cat.prototype)
|
||||||
|
expect(cat.isHungry()).not.toBeTruthy()
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
# Lots of built in matchers
|
||||||
|
|
||||||
|
``` coffeescript
|
||||||
|
toEqual(object)
|
||||||
|
toBeTruthy()
|
||||||
|
toBeFalsy()
|
||||||
|
toBeGreaterThan()
|
||||||
|
toBeLessThan()
|
||||||
|
toBeUndefined()
|
||||||
|
toContain()
|
||||||
|
toMatch()
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
expect(cat.isHungry()).not.toBeTruthy()
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Create your own matchers!
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
MyMatchers =
|
||||||
|
toBeHungry: ->
|
||||||
|
return @actual.isHungry() == true
|
||||||
|
|
||||||
|
beforeEach ->
|
||||||
|
this.addMatchers(MyMatchers)
|
||||||
|
|
||||||
|
describe 'Cat', ->
|
||||||
|
beforeEach ->
|
||||||
|
@cat = new Cat()
|
||||||
|
|
||||||
|
it 'should not be hungry', ->
|
||||||
|
expect(@cat).not.toBeHungry()
|
||||||
|
```
|
||||||
|
|
368
presentation/08_mocks_and_stubs.slides
Normal file
@ -0,0 +1,368 @@
|
|||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
describe
|
||||||
|
it
|
||||||
|
expect
|
||||||
|
toSomething()
|
||||||
|
beforeEach
|
||||||
|
afterEach
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Jasmine == unit testing
|
||||||
|
|
||||||
|
!SLIDE image-80-percent
|
||||||
|
<img src="assets/synergize.jpg" />
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# No, this isn't a talk about integration testing
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Testing the *right* things in your JavaScript unit tests
|
||||||
|
|
||||||
|
!SLIDE image-80-percent
|
||||||
|
<img src="assets/spaghetti.jpg" />
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# John behavior #2
|
||||||
|
## Mock, stub, and spy on anything that should be handled in an integration test
|
||||||
|
|
||||||
|
``` coffeescript
|
||||||
|
describe 'John', ->
|
||||||
|
describe 'spec definitions', ->
|
||||||
|
it 'should keep unit tests as focused as possible', ->
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE image-80-percent
|
||||||
|
<img src="assets/beer-cat.jpg" />
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` gherkin
|
||||||
|
Feature: Cat Behaviors
|
||||||
|
Scenario: Hungry cats meow a particular way
|
||||||
|
Given I have a cat
|
||||||
|
And the cat is hungry
|
||||||
|
When the cat meows
|
||||||
|
Then the meow should sound like "meeyaow"
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
class this.Cat
|
||||||
|
@FOOD_THRESHOLD = 20
|
||||||
|
@HUNGRY = 'hungry'
|
||||||
|
|
||||||
|
constructor: (@foodLevel = 30) ->
|
||||||
|
|
||||||
|
meow: ->
|
||||||
|
switch this.state()
|
||||||
|
when Cat.HUNGRY
|
||||||
|
"meeyaow"
|
||||||
|
|
||||||
|
state: ->
|
||||||
|
if @foodLevel < Cat.FOOD_THRESHOLD
|
||||||
|
Cat.HUNGRY
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
describe 'Cat', ->
|
||||||
|
describe '#meow', ->
|
||||||
|
context 'hungry', ->
|
||||||
|
it 'should be a mournful meow', ->
|
||||||
|
cat = new Cat()
|
||||||
|
cat.foodLevel = 15
|
||||||
|
|
||||||
|
expect(cat.meow()).toEqual("meeeyaow")
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# A perfectly cromulent test
|
||||||
|
|
||||||
|
!SLIDE larger
|
||||||
|
``` coffeescript
|
||||||
|
class this.Cat
|
||||||
|
meow: ->
|
||||||
|
switch this.state() # <= dependent code executed
|
||||||
|
when Cat.HUNGRY
|
||||||
|
"meeyaow"
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Why make your unit tests fragile?
|
||||||
|
|
||||||
|
!SLIDE larger
|
||||||
|
``` coffeescript
|
||||||
|
cat.foodLevel = 15 # do we care about food level in this test?
|
||||||
|
# all we care about is that the cat is hungry
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE larger
|
||||||
|
``` coffeescript
|
||||||
|
describe 'Cat', ->
|
||||||
|
describe '#meow', ->
|
||||||
|
describe 'hungry', ->
|
||||||
|
it 'should be a mournful meow', ->
|
||||||
|
cat = new Cat()
|
||||||
|
cat.state = -> Cat.HUNGRY # <= we don't care how state works,
|
||||||
|
# we just want a hungry cat
|
||||||
|
|
||||||
|
expect(cat.meow()).toEqual("meeeyaow")
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Instance Stubs in JavaScript
|
||||||
|
## Just replace the method on the instance
|
||||||
|
|
||||||
|
``` coffeescript
|
||||||
|
class this.Cat
|
||||||
|
state: ->
|
||||||
|
# cat codes
|
||||||
|
|
||||||
|
cat = new Cat()
|
||||||
|
cat.state = -> "whatever"
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Stubs just return something when called
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Mocks expect to be called
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Test fails if all mocks are not called
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Jasmine blurs the line a little
|
||||||
|
|
||||||
|
!SLIDE image-80-percent
|
||||||
|
<img src="assets/spy-cat.jpg" />
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Spies work like mocks, but with additional abilities
|
||||||
|
|
||||||
|
!SLIDE image-80-percent
|
||||||
|
<img src="assets/flying-cat.jpg" />
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
class this.Cat
|
||||||
|
vocalProcessor: (speech) =>
|
||||||
|
if this.isAirborne()
|
||||||
|
this.modifyForAirborne(speech)
|
||||||
|
else
|
||||||
|
this.modifyForGround(speech)
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE larger
|
||||||
|
``` coffeescript
|
||||||
|
describe 'Cat#vocalProcessor', ->
|
||||||
|
speech = "speech"
|
||||||
|
|
||||||
|
beforeEach ->
|
||||||
|
@cat = new Cat()
|
||||||
|
|
||||||
|
context 'airborne', ->
|
||||||
|
beforeEach ->
|
||||||
|
spyOn(@cat, 'modifyForAirborne')
|
||||||
|
@cat.isAirborne = -> true
|
||||||
|
|
||||||
|
it 'should be modified for flight', ->
|
||||||
|
@cat.vocalProcessor(speech)
|
||||||
|
expect(@cat.modifyForAirborne).toHaveBeenCalledWith(speech)
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
# `spyOn` replaces a method on an instance with a spy method
|
||||||
|
|
||||||
|
``` coffeescript
|
||||||
|
spyOn(@cat, 'modifyForAirborne')
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Can return a value, run code, run the original code, or just wait to be called
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Two basic ways to make sure a spy is called
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
# `toHaveBeenCalledWith()`
|
||||||
|
## Called least once with the given parameters
|
||||||
|
|
||||||
|
``` coffeescript
|
||||||
|
expect(@cat.modifyForAirborne).toHaveBeenCalledWith(speech)
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
# `toHaveBeenCalled()`
|
||||||
|
# Just called, no parameter check
|
||||||
|
|
||||||
|
``` coffeescript
|
||||||
|
expect(@cat.modifyForAirborne).toHaveBeenCalled()
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
# Instance Mocks/Spies in JavaScript
|
||||||
|
## Use `spyOn`/`toHaveBeenCalled` matchers
|
||||||
|
|
||||||
|
``` coffeescript
|
||||||
|
class this.Cat
|
||||||
|
state: ->
|
||||||
|
# cat codes
|
||||||
|
|
||||||
|
cat = new Cat()
|
||||||
|
spyOn(cat, 'state')
|
||||||
|
expect(cat.state).toHaveBeenCalled()
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# `spyOn` works great with class-level stubs and mocks, too
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
class this.Cat
|
||||||
|
@generateFurColor: (base) ->
|
||||||
|
# magicks to make a fur color given a base
|
||||||
|
|
||||||
|
regrowFur: (damagedHairs) ->
|
||||||
|
for follicle in damagedHairs
|
||||||
|
follicle.regrow(Cat.generateFurColor(this.baseColor))
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
Cat.generateFurColor = ->
|
||||||
|
"whoops i nuked this method for every other test"
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE larger
|
||||||
|
``` coffeescript
|
||||||
|
describe 'Cat#regrowFur', ->
|
||||||
|
color = 'color'
|
||||||
|
|
||||||
|
beforeEach ->
|
||||||
|
@cat = new Cat()
|
||||||
|
@follicle =
|
||||||
|
regrow: ->
|
||||||
|
|
||||||
|
@follicles = [ follicle ]
|
||||||
|
|
||||||
|
spyOn(Cat, 'generateFurColor').andReturn(color)
|
||||||
|
# ^^^ original is replaced when done
|
||||||
|
spyOn(@follicle, 'regrow')
|
||||||
|
|
||||||
|
it 'should regrow', ->
|
||||||
|
@cat.regrowFur(@follicles)
|
||||||
|
|
||||||
|
expect(@follicle.regrow).toHaveBeenCalledWith(color)
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
# Class Stubs in JavaScript
|
||||||
|
## Use `spyOn` to generate stubs so that the original code is replaced after the test
|
||||||
|
|
||||||
|
``` coffeescript
|
||||||
|
class this.Cat
|
||||||
|
@injectPsychicPowers: (cat) ->
|
||||||
|
# cat codes
|
||||||
|
|
||||||
|
spyOn(Cat, 'injectPsychicPowers').andReturn(psychicCat)
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# John behavior #3
|
||||||
|
## If you have too many mocks/stubs/contexts, your code is too complex
|
||||||
|
|
||||||
|
``` coffeescript
|
||||||
|
describe 'John', ->
|
||||||
|
describe 'spec definitions', ->
|
||||||
|
it 'should obey the Law of Demeter as much as possible', ->
|
||||||
|
it 'should not smell too funny', ->
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE smaller
|
||||||
|
``` coffeescript
|
||||||
|
describe 'Cat#fetch', ->
|
||||||
|
object = null
|
||||||
|
|
||||||
|
context 'a mouse', ->
|
||||||
|
beforeEach ->
|
||||||
|
object = new Mouse()
|
||||||
|
|
||||||
|
context 'fast mouse', ->
|
||||||
|
it 'should wear down the mouse', ->
|
||||||
|
# who
|
||||||
|
|
||||||
|
context 'slow mouse', ->
|
||||||
|
it 'should deliver a present to you', ->
|
||||||
|
# cares
|
||||||
|
|
||||||
|
context 'a ball', ->
|
||||||
|
beforeEach ->
|
||||||
|
object = new Ball()
|
||||||
|
|
||||||
|
context 'ball is bouncing', ->
|
||||||
|
it 'should cause the cat to leap', ->
|
||||||
|
# this
|
||||||
|
|
||||||
|
context 'ball is rolling', ->
|
||||||
|
it 'should cause the cat to slide on the floor', ->
|
||||||
|
# test
|
||||||
|
|
||||||
|
context 'a red dot', ->
|
||||||
|
laser = null
|
||||||
|
|
||||||
|
beforeEach ->
|
||||||
|
laser = new Laser()
|
||||||
|
|
||||||
|
context 'laser out of batteries', ->
|
||||||
|
it 'should not activate', ->
|
||||||
|
# is
|
||||||
|
|
||||||
|
context 'laser functioning', ->
|
||||||
|
it 'should activate, driving the cat insane', ->
|
||||||
|
# huge and unmaintainable and silly
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Sometimes you just need a big blob of unit tests
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
# fast and focused!
|
||||||
|
|
||||||
|
describe 'Cat#respondsTo', ->
|
||||||
|
beforeEach ->
|
||||||
|
@cat = new Cat()
|
||||||
|
|
||||||
|
context 'successes', ->
|
||||||
|
it 'should respond', ->
|
||||||
|
for request in [ 'kitty kitty', 'pookums', 'hisshead' ]
|
||||||
|
expect(@cat.respondsTo(request)).toBeTruthy()
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` gherkin
|
||||||
|
# slow and synergistic!
|
||||||
|
|
||||||
|
Scenario Outline: Successful responsiveness
|
||||||
|
Given I have a cat
|
||||||
|
When I call it with "<request>"
|
||||||
|
Then the cat should respond
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
| request |
|
||||||
|
| kitty kitty |
|
||||||
|
| pookums |
|
||||||
|
| hisshead |
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE image-80-percent
|
||||||
|
<img src="assets/balancing-cat.jpg" />
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Find what works best for you and stick with it
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
## ...until you get sick of it, of course...
|
||||||
|
|
33
presentation/09_using_in_your_project.slides
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
!SLIDE
|
||||||
|
# Using it in your project
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# [github.com/pivotal/jasmine-gem](http://github.com/pivotal/jasmine-gem)
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Starts a Rack server for running Jasmine against your code
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Really easy to plug into an existing Rails project
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Want to make that run fast?
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Use PhantomJS or `jasmine-headless-webkit`
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Fast code running in a real browser
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Evergreen
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Jasminerice
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Node.js
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Pick your favorite!
|
||||||
|
|
205
presentation/10_misc_hints.slides
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
!SLIDE
|
||||||
|
# Some miscellaneous hints and tips
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Testing jQuery
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Mocking and stubbing `$.fn` calls
|
||||||
|
|
||||||
|
!SLIDE larger
|
||||||
|
``` coffeescript
|
||||||
|
this.containerWaiter = ->
|
||||||
|
$('#container').addClass('wait').append('<div class="waiting" />')
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
$.fn.makeWait = ->
|
||||||
|
$(this).addClass('wait').append('<div class="waiting" />')
|
||||||
|
this
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
this.containerWaiter = ->
|
||||||
|
$('#container').makeWait()
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# `jquery-jasmine`
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
describe 'container', ->
|
||||||
|
beforeEach ->
|
||||||
|
setFixtures('<div id="container" />')
|
||||||
|
|
||||||
|
it 'should make it wait', ->
|
||||||
|
containerWaiter()
|
||||||
|
expect($('#container')).toHaveClass('wait')
|
||||||
|
expect($('#container')).toContain('div.waiting')
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE image-80-percent
|
||||||
|
<img src="assets/wet-cat.jpg" />
|
||||||
|
|
||||||
|
!SLIDE image-80-percent
|
||||||
|
<img src="assets/spaghetti.jpg" />
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
describe '$.fn.makeWait', ->
|
||||||
|
it 'should make wait', ->
|
||||||
|
$div = $('<div />')
|
||||||
|
$div.makeWait()
|
||||||
|
|
||||||
|
expect($div).toHaveClass('wait')
|
||||||
|
expect($div).toContain('div.waiting')
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
describe 'container', ->
|
||||||
|
beforeEach ->
|
||||||
|
setFixtures('<div id="container" />')
|
||||||
|
spyOn($.fn, 'makeWait')
|
||||||
|
|
||||||
|
it 'should make it wait', ->
|
||||||
|
containerWaiter()
|
||||||
|
expect($.fn.makeWait).toHaveBeenCalled()
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# No longer testing jQuery, just testing for our code
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Animations and other time-dependent things
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
class Cat
|
||||||
|
constructor: ->
|
||||||
|
@mood = "happy"
|
||||||
|
|
||||||
|
pet: ->
|
||||||
|
setTimeout(
|
||||||
|
-> @mood = "angry"
|
||||||
|
, 500
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Do you really need to test the `setTimeout`?
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
class Cat
|
||||||
|
constructor: ->
|
||||||
|
@mood = "happy"
|
||||||
|
|
||||||
|
pet: -> setTimeout(@makeAngry, 500)
|
||||||
|
|
||||||
|
makeAngry: => @mood = "angry"
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Use Jasmine's `waitsFor` and `runs`
|
||||||
|
|
||||||
|
!SLIDE larger
|
||||||
|
``` coffeescript
|
||||||
|
describe 'cat moods', ->
|
||||||
|
it 'should change moods', ->
|
||||||
|
cat = new Cat()
|
||||||
|
|
||||||
|
# we want to know the cat's current mood
|
||||||
|
currentMood = cat.mood
|
||||||
|
|
||||||
|
# start petting the cat
|
||||||
|
runs -> cat.pet()
|
||||||
|
|
||||||
|
# wait one second for the cat's mood to change
|
||||||
|
waitsFor(
|
||||||
|
->
|
||||||
|
cat.mood != currentMood
|
||||||
|
, "Cat changed its mood",
|
||||||
|
1000
|
||||||
|
)
|
||||||
|
|
||||||
|
# expect the inevitable
|
||||||
|
runs ->
|
||||||
|
expect(cat.mood).toEqual('angry')
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Underscore.js mixins
|
||||||
|
## and other prototype mixin-style extensions
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
CatLike =
|
||||||
|
catify: (name) ->
|
||||||
|
"meow meow #{name}"
|
||||||
|
|
||||||
|
# mix in to the Underscore object
|
||||||
|
_.mixin(CatLike)
|
||||||
|
|
||||||
|
# use it
|
||||||
|
_.catify("john") # => "meow meow john"
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
CatLike =
|
||||||
|
catify: (name) -> "meow meow #{name}"
|
||||||
|
|
||||||
|
class Cat
|
||||||
|
hiss: -> "hiss"
|
||||||
|
|
||||||
|
# like Ruby include, add code to instances
|
||||||
|
for method, code of CatLike
|
||||||
|
Cat.prototype[method] = code
|
||||||
|
|
||||||
|
cat = new Cat()
|
||||||
|
cat.catify("john") # => "meow meow #{name}"
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
CatLike =
|
||||||
|
catify: (name) -> "meow meow #{name}"
|
||||||
|
|
||||||
|
class Cat
|
||||||
|
hiss: -> "hiss"
|
||||||
|
|
||||||
|
# like Ruby extend, add code to class
|
||||||
|
for method, code of CatLike
|
||||||
|
Cat[method] = code
|
||||||
|
|
||||||
|
Cat.catify("john") # => "meow meow john"
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
describe '_.catify', ->
|
||||||
|
it 'should catify', ->
|
||||||
|
expect(_.catify("hiss")).toEqual("meow meow hiss")
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Eliminate the Underscore.js dependency
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
``` coffeescript
|
||||||
|
describe 'CatLike', ->
|
||||||
|
beforeEach ->
|
||||||
|
@helper = {}
|
||||||
|
|
||||||
|
for method, code of CatLike
|
||||||
|
@helper[method] = code
|
||||||
|
|
||||||
|
describe '#catify', ->
|
||||||
|
it 'should catify', ->
|
||||||
|
expect(@helper.catify("hiss")).toEqual("meow meow hiss")
|
||||||
|
```
|
||||||
|
|
50
presentation/11_conclusion.slides
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
!SLIDE
|
||||||
|
# So that's pretty much it.
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
# Basic parts of Jasmine unit tests
|
||||||
|
|
||||||
|
``` coffeescript
|
||||||
|
describe
|
||||||
|
it
|
||||||
|
expect
|
||||||
|
toSomething()
|
||||||
|
beforeEach
|
||||||
|
afterEach
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
# Mocking and stubbing
|
||||||
|
|
||||||
|
``` coffeescript
|
||||||
|
direct method replacement
|
||||||
|
spyOn()
|
||||||
|
toHaveBeenCalled()
|
||||||
|
toHaveBeenCalledWith()
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Running Jasmine in your project
|
||||||
|
|
||||||
|
!SLIDE even-larger
|
||||||
|
# Hints and tips for JavaScript testing
|
||||||
|
|
||||||
|
``` coffeescript
|
||||||
|
waitsFor()
|
||||||
|
runs()
|
||||||
|
```
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# [Jasmine documentation](http://pivotal.github.com/jasmine/)
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# [johnbintz.github.com/tea-time](http://johnbintz.github.com/tea-time/)
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Any questions?
|
||||||
|
|
||||||
|
!SLIDE
|
||||||
|
# Thank you!
|
||||||
|
## [@johnbintz](http://twitter.com/johnbintz/)
|
||||||
|
## [GitHub](http://github.com/johnbintz/)
|
||||||
|
|
2
views/_header.haml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
%link{:href => 'http://fonts.googleapis.com/css?family=Acme', :rel => 'stylesheet', :type => 'text/css'}/
|
||||||
|
|