Compare commits
No commits in common. "master" and "gh-pages" have entirely different histories.
4
.gitignore
vendored
@ -1,4 +0,0 @@
|
|||||||
.DS_Store
|
|
||||||
.sass-cache/
|
|
||||||
_export/
|
|
||||||
_site/
|
|
9
Gemfile
@ -1,9 +0,0 @@
|
|||||||
source :rubygems
|
|
||||||
|
|
||||||
gem 'attentive', :path => '../attentive'
|
|
||||||
gem 'rack-livereload'
|
|
||||||
|
|
||||||
gem 'guard'
|
|
||||||
gem 'guard-livereload'
|
|
||||||
|
|
||||||
gem 'thin'
|
|
172
Gemfile.lock
@ -1,172 +0,0 @@
|
|||||||
PATH
|
|
||||||
remote: ../attentive
|
|
||||||
specs:
|
|
||||||
attentive (0.0.1)
|
|
||||||
backbone-rails
|
|
||||||
coffee-script
|
|
||||||
compass (~> 0.12.rc)
|
|
||||||
haml
|
|
||||||
naturalsort (~> 1.1.1)
|
|
||||||
nokogiri
|
|
||||||
pygments.rb
|
|
||||||
rack (~> 1.4.0)
|
|
||||||
rdiscount
|
|
||||||
selenium-webdriver
|
|
||||||
sinatra
|
|
||||||
sprockets
|
|
||||||
sprockets-sass
|
|
||||||
sprockets-vendor_gems
|
|
||||||
thor
|
|
||||||
|
|
||||||
GEM
|
|
||||||
remote: http://rubygems.org/
|
|
||||||
specs:
|
|
||||||
actionmailer (3.2.2)
|
|
||||||
actionpack (= 3.2.2)
|
|
||||||
mail (~> 2.4.0)
|
|
||||||
actionpack (3.2.2)
|
|
||||||
activemodel (= 3.2.2)
|
|
||||||
activesupport (= 3.2.2)
|
|
||||||
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.2)
|
|
||||||
activesupport (= 3.2.2)
|
|
||||||
builder (~> 3.0.0)
|
|
||||||
activerecord (3.2.2)
|
|
||||||
activemodel (= 3.2.2)
|
|
||||||
activesupport (= 3.2.2)
|
|
||||||
arel (~> 3.0.2)
|
|
||||||
tzinfo (~> 0.3.29)
|
|
||||||
activeresource (3.2.2)
|
|
||||||
activemodel (= 3.2.2)
|
|
||||||
activesupport (= 3.2.2)
|
|
||||||
activesupport (3.2.2)
|
|
||||||
i18n (~> 0.6)
|
|
||||||
multi_json (~> 1.0)
|
|
||||||
addressable (2.2.6)
|
|
||||||
arel (3.0.2)
|
|
||||||
backbone-rails (0.9.1)
|
|
||||||
rails (>= 3.0.0)
|
|
||||||
blankslate (2.1.2.4)
|
|
||||||
builder (3.0.0)
|
|
||||||
childprocess (0.3.1)
|
|
||||||
ffi (~> 1.0.6)
|
|
||||||
chunky_png (1.2.5)
|
|
||||||
coffee-script (2.2.0)
|
|
||||||
coffee-script-source
|
|
||||||
execjs
|
|
||||||
coffee-script-source (1.2.0)
|
|
||||||
compass (0.12.1)
|
|
||||||
chunky_png (~> 1.2)
|
|
||||||
fssm (>= 0.2.7)
|
|
||||||
sass (~> 3.1)
|
|
||||||
daemons (1.1.8)
|
|
||||||
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.4)
|
|
||||||
i18n (>= 0.4.0)
|
|
||||||
mime-types (~> 1.16)
|
|
||||||
treetop (~> 1.4.8)
|
|
||||||
mime-types (1.18)
|
|
||||||
multi_json (1.0.4)
|
|
||||||
naturalsort (1.1.1)
|
|
||||||
nokogiri (1.5.2)
|
|
||||||
polyglot (0.3.3)
|
|
||||||
pygments.rb (0.2.7)
|
|
||||||
rubypython (~> 0.5.3)
|
|
||||||
rack (1.4.1)
|
|
||||||
rack-cache (1.2)
|
|
||||||
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.2)
|
|
||||||
actionmailer (= 3.2.2)
|
|
||||||
actionpack (= 3.2.2)
|
|
||||||
activerecord (= 3.2.2)
|
|
||||||
activeresource (= 3.2.2)
|
|
||||||
activesupport (= 3.2.2)
|
|
||||||
bundler (~> 1.0)
|
|
||||||
railties (= 3.2.2)
|
|
||||||
railties (3.2.2)
|
|
||||||
actionpack (= 3.2.2)
|
|
||||||
activesupport (= 3.2.2)
|
|
||||||
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)
|
|
||||||
rubyzip (0.9.6.1)
|
|
||||||
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)
|
|
||||||
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.7.0)
|
|
||||||
sprockets (~> 2.0)
|
|
||||||
tilt (~> 1.1)
|
|
||||||
sprockets-vendor_gems (0.1.1)
|
|
||||||
thin (1.3.1)
|
|
||||||
daemons (>= 1.0.9)
|
|
||||||
eventmachine (>= 0.12.6)
|
|
||||||
rack (>= 1.0.0)
|
|
||||||
thor (0.14.6)
|
|
||||||
tilt (1.3.3)
|
|
||||||
treetop (1.4.10)
|
|
||||||
polyglot
|
|
||||||
polyglot (>= 0.3.1)
|
|
||||||
tzinfo (0.3.32)
|
|
||||||
|
|
||||||
PLATFORMS
|
|
||||||
ruby
|
|
||||||
|
|
||||||
DEPENDENCIES
|
|
||||||
attentive!
|
|
||||||
guard
|
|
||||||
guard-livereload
|
|
||||||
rack-livereload
|
|
||||||
thin
|
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 171 KiB After Width: | Height: | Size: 171 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 140 KiB After Width: | Height: | Size: 140 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 171 KiB |
Before Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 140 KiB |
Before Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 138 KiB |
Before Width: | Height: | Size: 201 KiB |
Before Width: | Height: | Size: 106 KiB |
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 43 B |
Before Width: | Height: | Size: 109 KiB |
Before Width: | Height: | Size: 26 KiB |
@ -1,4 +0,0 @@
|
|||||||
#= require attentive
|
|
||||||
#
|
|
||||||
Attentive.Presentation.setup('#slides')
|
|
||||||
|
|
Before Width: | Height: | Size: 138 KiB After Width: | Height: | Size: 138 KiB |
Before Width: | Height: | Size: 201 KiB After Width: | Height: | Size: 201 KiB |
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 106 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
@ -1,43 +0,0 @@
|
|||||||
@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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Before Width: | Height: | Size: 43 B After Width: | Height: | Size: 43 B |
Before Width: | Height: | Size: 109 KiB After Width: | Height: | Size: 109 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
1492
index.html
Normal file
@ -1,9 +0,0 @@
|
|||||||
require 'rack-livereload'
|
|
||||||
|
|
||||||
Attentive.configure do |c|
|
|
||||||
c.title = "Tea Time: A Beginner's Guide to Jasmine"
|
|
||||||
c.middleware << Rack::LiveReload
|
|
||||||
|
|
||||||
#c.export_size = '1280x1024'
|
|
||||||
end
|
|
||||||
|
|
@ -1,146 +0,0 @@
|
|||||||
!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
|
|
||||||
# Why is it important?
|
|
||||||
|
|
||||||
!SLIDE image-80-percent
|
|
||||||
<img src="assets/checklist.png" />
|
|
||||||
|
|
||||||
!SLIDE
|
|
||||||
# Fortunately, we're beyond that nowadays
|
|
||||||
|
|
||||||
!SLIDE even-larger
|
|
||||||
``` ruby
|
|
||||||
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 even-larger
|
|
||||||
``` 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
!SLIDE even-larger
|
|
||||||
``` javascript
|
|
||||||
window.onload = function() {
|
|
||||||
showMyCoolTitle(
|
|
||||||
"My cool website! Whoaaaaa!"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
!SLIDE
|
|
||||||
# jQuery
|
|
||||||
|
|
||||||
!SLIDE
|
|
||||||
# Backbone.js
|
|
||||||
|
|
||||||
!SLIDE
|
|
||||||
# Sprockets and RequireJS
|
|
||||||
|
|
||||||
!SLIDE
|
|
||||||
# Automated testing is important
|
|
||||||
|
|
||||||
!SLIDE even-larger
|
|
||||||
``` ruby
|
|
||||||
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 even-larger
|
|
||||||
``` coffeescript
|
|
||||||
describe 'MyCoolWebsiteView', ->
|
|
||||||
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!
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
|||||||
!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!
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
|||||||
!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 larger
|
|
||||||
# John behavior #1
|
|
||||||
## Use Ruby-style indicators for instance- and class-level methods
|
|
||||||
|
|
||||||
``` 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!
|
|
||||||
|
|
@ -1,91 +0,0 @@
|
|||||||
!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 @Cat
|
|
||||||
meow: ->
|
|
||||||
```
|
|
||||||
|
|
||||||
!SLIDE larger
|
|
||||||
``` javascript
|
|
||||||
// safety wrapper to prevent global pollution
|
|
||||||
(function() {
|
|
||||||
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 @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 @Cat
|
|
||||||
meow: -> "meow"
|
|
||||||
```
|
|
@ -1,124 +0,0 @@
|
|||||||
!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 even-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 even-larger
|
|
||||||
``` coffeescript
|
|
||||||
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")
|
|
||||||
```
|
|
||||||
|
|
||||||
!SLIDE even-larger
|
|
||||||
``` coffeescript
|
|
||||||
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 "is in same context as 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 even-larger
|
|
||||||
``` coffeescript
|
|
||||||
describe 'Cat', ->
|
|
||||||
describe '#meow', ->
|
|
||||||
beforeEach ->
|
|
||||||
@cat = new Cat()
|
|
||||||
```
|
|
||||||
|
|
||||||
!SLIDE even-larger
|
|
||||||
``` coffeescript
|
|
||||||
describe 'hungry', ->
|
|
||||||
it 'should be a mournful meow', ->
|
|
||||||
@cat.state = -> Cat.HUNGRY
|
|
||||||
|
|
||||||
expect(@cat.meow()).toEqual("meeeyaow")
|
|
||||||
```
|
|
||||||
|
|
||||||
!SLIDE even-larger
|
|
||||||
``` coffeescript
|
|
||||||
describe 'going to the vet', ->
|
|
||||||
it 'should be an evil meow', ->
|
|
||||||
@cat.state = -> Cat.VET_PSYCHIC
|
|
||||||
|
|
||||||
expect(@cat.meow()).toEqual("raowwww")
|
|
||||||
```
|
|
||||||
|
|
@ -1,130 +0,0 @@
|
|||||||
!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 even-larger
|
|
||||||
``` 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 even-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 @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
|
|
||||||
```
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
|||||||
!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.constructor).toEqual(Cat)
|
|
||||||
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)
|
|
||||||
```
|
|
||||||
|
|
||||||
!SLIDE even-larger
|
|
||||||
``` coffeescript
|
|
||||||
describe 'Cat', ->
|
|
||||||
beforeEach ->
|
|
||||||
@cat = new Cat()
|
|
||||||
|
|
||||||
it 'should not be hungry', ->
|
|
||||||
expect(@cat).not.toBeHungry()
|
|
||||||
```
|
|
||||||
|
|
@ -1,380 +0,0 @@
|
|||||||
!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 certain way
|
|
||||||
Given I have a cat
|
|
||||||
And the cat is hungry
|
|
||||||
When the cat meows
|
|
||||||
Then the meow should be a "meeyaow"
|
|
||||||
```
|
|
||||||
|
|
||||||
!SLIDE even-larger
|
|
||||||
``` coffeescript
|
|
||||||
class @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 even-larger
|
|
||||||
``` coffeescript
|
|
||||||
class @Cat
|
|
||||||
meow: ->
|
|
||||||
switch this.state()
|
|
||||||
# ^^^ dependent code executed
|
|
||||||
when Cat.HUNGRY
|
|
||||||
"meeyaow"
|
|
||||||
```
|
|
||||||
|
|
||||||
!SLIDE
|
|
||||||
# Why make your unit tests fragile?
|
|
||||||
|
|
||||||
!SLIDE even-larger
|
|
||||||
``` coffeescript
|
|
||||||
cat.foodLevel = 15
|
|
||||||
# do we care about food level?
|
|
||||||
```
|
|
||||||
|
|
||||||
!SLIDE even-larger
|
|
||||||
``` coffeescript
|
|
||||||
describe 'Cat', ->
|
|
||||||
describe '#meow', ->
|
|
||||||
context 'hungry', ->
|
|
||||||
it 'should be a mournful meow', ->
|
|
||||||
cat = new Cat()
|
|
||||||
cat.state = -> Cat.HUNGRY
|
|
||||||
# ^^^ 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 @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 @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(args...)`
|
|
||||||
### 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 @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 larger
|
|
||||||
``` coffeescript
|
|
||||||
class @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 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: -> null }
|
|
||||||
@follicles = [ follicle ]
|
|
||||||
|
|
||||||
spyOn(Cat, 'generateFurColor').
|
|
||||||
# ^^^ original replaced when done
|
|
||||||
andReturn(color)
|
|
||||||
spyOn(@follicle, 'regrow')
|
|
||||||
|
|
||||||
it 'should regrow', ->
|
|
||||||
@cat.regrowFur(@follicles)
|
|
||||||
|
|
||||||
expect(@follicle.regrow).
|
|
||||||
toHaveBeenCalledWith(color)
|
|
||||||
```
|
|
||||||
|
|
||||||
!SLIDE 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 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 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...
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
|||||||
!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!
|
|
||||||
|
|
@ -1,141 +0,0 @@
|
|||||||
!SLIDE
|
|
||||||
# Some miscellaneous hints and tips
|
|
||||||
|
|
||||||
!SLIDE
|
|
||||||
# Testing jQuery
|
|
||||||
|
|
||||||
!SLIDE
|
|
||||||
# Mocking and stubbing `$.fn` calls
|
|
||||||
|
|
||||||
!SLIDE even-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')
|
|
||||||
```
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
|||||||
!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!
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
|||||||
%link{:href => 'http://fonts.googleapis.com/css?family=Acme', :rel => 'stylesheet', :type => 'text/css'}/
|
|
||||||
|
|