initial commit

This commit is contained in:
John Bintz 2011-12-12 09:46:21 -05:00
commit 3a067b518e
17 changed files with 899 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.sass-cache/

21
Gemfile Normal file
View File

@ -0,0 +1,21 @@
source :rubygems
group :rack do
gem 'rack-livereload'
gem 'showoff'
end
gem 'rmagick'
gem 'thin'
gem 'guard'
gem 'guard-livereload'
gem 'compass', '~> 0.12.alpha'
gem 'sprockets-sass'
gem 'sass'
gem 'coffee-script'
gem 'therubyracer'
gem 'sprockets'

87
Gemfile.lock Normal file
View File

@ -0,0 +1,87 @@
GEM
remote: http://rubygems.org/
specs:
addressable (2.2.6)
blankslate (2.1.2.4)
bluecloth (2.2.0)
chunky_png (1.2.5)
coffee-script (2.2.0)
coffee-script-source
execjs
coffee-script-source (1.1.3)
compass (0.12.alpha.2)
chunky_png (~> 1.2)
fssm (>= 0.2.7)
sass (~> 3.1)
daemons (1.1.4)
em-websocket (0.3.5)
addressable (>= 2.1.1)
eventmachine (>= 0.12.9)
eventmachine (0.12.10)
execjs (1.2.11)
multi_json (~> 1.0)
fssm (0.2.7)
gli (1.4.0)
guard (0.8.8)
thor (~> 0.14.6)
guard-livereload (0.3.1)
em-websocket (>= 0.2.0)
guard (>= 0.4.0)
multi_json (~> 1.0.3)
hike (1.2.1)
json (1.6.3)
libv8 (3.3.10.4)
multi_json (1.0.4)
nokogiri (1.5.0)
parslet (1.2.3)
blankslate (~> 2.0)
rack (1.3.5)
rack-livereload (0.3.3)
rack
rack-protection (1.1.4)
rack
rmagick (2.13.1)
sass (3.1.11)
showoff (0.7.0)
bluecloth
gli (>= 1.3.2)
json
nokogiri
parslet
sinatra
sinatra (1.3.1)
rack (~> 1.3, >= 1.3.4)
rack-protection (~> 1.1, >= 1.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.5.1)
sprockets (~> 2.0)
tilt (~> 1.1)
therubyracer (0.9.9)
libv8 (~> 3.3.10)
thin (1.3.1)
daemons (>= 1.0.9)
eventmachine (>= 0.12.6)
rack (>= 1.0.0)
thor (0.14.6)
tilt (1.3.3)
PLATFORMS
ruby
DEPENDENCIES
coffee-script
compass (~> 0.12.alpha)
guard
guard-livereload
rack-livereload
rmagick
sass
showoff
sprockets
sprockets-sass
therubyracer
thin

48
Guardfile Normal file
View File

@ -0,0 +1,48 @@
# A sample Guardfile
# More info at https://github.com/guard/guard#readme
guard 'livereload' do
watch(%r{.*\.(json|md|scss)$})
end
require 'guard/guard'
require 'sprockets'
require 'sprockets-sass'
require 'sass'
require 'compass'
module ::Guard
class Sprockets < ::Guard::Guard
def initialize(watchers = [], options = {})
@env = ::Sprockets::Environment.new
@env.append_path 'app/assets/stylesheets'
@env.append_path 'app/assets/javascripts'
super
end
def start
::Guard::UI.info "Guard::Sprockets is running..."
end
def run_all
%w{presentation.css presentation.js}.each do |file|
::Guard::UI.info "Rebuilding #{file}..."
begin
File.open(file, 'wb') { |fh| fh.print @env[file].to_s }
rescue StandardError => e
puts e.message
end
end
end
def run_on_change(paths)
run_all
end
end
end
guard 'sprockets' do
watch(%r{^app/assets})
end

View File

@ -0,0 +1,30 @@
$(->
isTiming = false
time = 0
delay = 1000
timer = null
timer = ->
$('#footer span#timeInfo').remove()
$('#footer').append('<span id="timeInfo" />')
minute = "00#{Math.floor(time / 60)}".substr(-2)
second = "00#{time % 60}".substr(-2)
output = "#{minute}:#{second}"
output += " (running)" if isTiming
$('#footer #timeInfo').text(output)
time += 1 if isTiming
setTimeout(timer, delay)
timer()
$(document).keyup (event) ->
if event.keyCode == 77
isTiming = !isTiming
time = 0 if isTiming
true
)

View File

@ -0,0 +1,85 @@
// solarized
$base03: #002b36;
$base02: #073642;
$base01: #586e75;
$base00: #657b83;
$base0: #839496;
$base1: #93a1a1;
$base2: #eee8d5;
$base3: #fdf6e3;
$yellow: #b58900;
$orange: #cb4b16;
$red: #dc322f;
$magenta: #d33682;
$violet: #6c71c4;
$blue: #268bd2;
$cyan: #2aa198;
$green: #859900;
$width: 1280px;
#preso, .slide {
width: $width;
height: 800px;
background-color: $base3;
}
@import 'compass';
#timeInfo {
@include float-right;
}
pre.sh_sourceCode, .sh_yaml, .sh_haml {
background-color: $base03;
@include single-box-shadow($base02, 0, 0, 5px);
code {
color: $base3;
}
.sh_string {
color: $red;
}
.sh_symbol {
color: $orange;
}
.sh_comment {
color: $base01;
}
.sh_keyword {
color: $yellow;
}
.sh_number {
color: $cyan;
}
.sh_function {
color: $green;
}
}
#footer {
width: $width - 20px;
}
body {
color: $base03;
background-color: $base1;
}
h1 {
color: $base03;
}
h2 {
color: $base02;
}

7
config.ru Normal file
View File

@ -0,0 +1,7 @@
require 'bundler'
Bundler.require(:rack)
use Rack::LiveReload
run ShowOff

73
intro/01_intro.md Normal file
View File

@ -0,0 +1,73 @@
!SLIDE
# `jasmine-headless-webkit`
## The fastest way to test your browser-targeted JavaScript!
!SLIDE
# JavaScript Testing
!SLIDE bullets incremental
# Ajax-y apps are complex nowadays!
* jQuery
* Backbone
* Tons of other JavaScripty things
* Client/server communication
!SLIDE
# A lot can break!
!SLIDE
# Lots of different ways to test
!SLIDE bullets incremental
# Standalone JavaScript Engines
* Node.JS
* EnvJS
* Rhino
* ...and others!
!SLIDE
# Great for testing JS Libraries
!SLIDE
# Not so great in testing in "real" browsers
!SLIDE
# Fake DOMs aren't quite the same
!SLIDE bullets incremental
# Integration testing tools
* Capybara
* Cucumber
* Selenium
!SLIDE
# Very thorough
!SLIDE
# Sloooooow
!SLIDE
# Server-side dependency management
!SLIDE
# Sprockets
!SLIDE bullets incremental
# Continuous testing
* Guard
!SLIDE bullets incremental
# A JS testing tool that...
* Runs fast
* In a real browser
* That supports modern Ruby webapp conventions
* Is built for continuous testing
!SLIDE
# Enter `jasmine-headless-webkit`

103
intro/02_install.md Normal file
View File

@ -0,0 +1,103 @@
!SLIDE
# Installing
!SLIDE
# Qt 4.7 or above
!SLIDE
# `gem install jasmine-headless-webkit`
!SLIDE
# Gemfile
@@@ ruby
gem 'jasmine-headless-webkit', '~> 0.8.0'
!SLIDE
# Gemfile
@@@ ruby
gem 'jasmine-headless-webkit', '~> 0.8.0'
gem 'guard'
gem 'guard-jasmine-headless-webkit'
!SLIDE
# Rails 3.1 Application
!SLIDE
# spec/javascripts/support/jasmine.yml
@@@ yaml
src_dir: app/assets/javascripts
asset_paths:
- lib/assets/javascripts
- vendor/assets/javascripts
src_files: [ '**/*' ]
spec_dir: spec/javascripts
spec_files: [ '**/*[Ss]pec.*' ]
helpers: [ 'helpers/**/*' ]
!SLIDE
# Load Paths
!SLIDE
# Sprockets and Jasmine load files differently
!SLIDE
@@@ ruby
# ...somewhere in JHW...
env = Sprockets::Environment.new
env['application.js'].to_s #=> compiled JS
!SLIDE
# spec/javascripts/support/jasmine.yml
@@@ yaml
src_dir: app/assets/javascripts
asset_paths:
- lib/assets/javascripts
- vendor/assets/javascripts
spec_dir: spec/javascripts
!SLIDE
@@@ ruby
# ...somewhere in JHW...
env.append_path "app/assets/javascripts"
env.append_path "lib/assets/javascripts"
env.append_path "vendor/assets/javascripts"
env.append_path "spec/javascripts"
!SLIDE
@@@ javascript
//= require backbone/models/cat
//= require backbone/collections/cats
//= require backbone/views/global_view
class window.CatsView extends GlobalView
!SLIDE
# Sprockets loading
!SLIDE
# Jasmine loading?
!SLIDE
@@@ yaml
src_dir: app/assets/javascripts
src_files: [ '**/*' ]
spec_dir: spec/javascripts
spec_files: [ '**/*[Ss]pec.*' ]
helpers: [ 'helpers/**/*' ]
!SLIDE
@@@ ruby
Dir["app/assets/javascripts/**/*"]
Dir["spec/javascripts/**/*[Ss]pec.*"]
Dir["spec/javascripts/helpers/**/*"]
!SLIDE
# JHW ensures that no file is loaded twice
!SLIDE
# Ensures Sprockets dependencies are loaded in the right order

72
intro/03_jasmine.md Normal file
View File

@ -0,0 +1,72 @@
!SLIDE
# Writing Jasmine Tests
!SLIDE
# RSpec?
!SLIDE
@@@ ruby
(2 + 2).should == 4
!SLIDE
# Jasmine!
!SLIDE
@@@ javascript
expect(2 + 2).toEqual(4)
!SLIDE
# RSpec?
@@@ ruby
describe "CatsView" do
before do
@cats = [ stub ]
end
it 'should show cats' do
render
rendered.should have_css('#cats li')
end
end
!SLIDE
# JavaScript?
@@@ javascript
describe("CatsView", function() {
var view;
beforeEach(function() {
view = new CatsView({collection: [ {} ]})
}):
it('should show cats', function() {
view.render()
expect($(view.el)).toContain('#cats li')
});
});
!SLIDE
# CoffeeScript?
@@@ coffeescript
describe "CatsView", ->
view = null
beforeEach ->
view = new CatsView(collection: [ {} ])
it 'should show cats', ->
view.render()
expect($(view.el)).toContain('#cats li')
!SLIDE
# Plenty of resources to learn Jasmine itself
!SLIDE
# tryjasmine.com
!SLIDE
# But once you know Jasmine...

166
intro/04_sprockets.md Normal file
View File

@ -0,0 +1,166 @@
!SLIDE
# Sprockets fun!
!SLIDE
# JST templates
!SLIDE
# templates/cats_view.jst.ejs
@@@ html
<h1>All the cats</h1>
<h2>Owned by <%= owner %></h2>
<ul id="#cats"></ul>
<h3>List generated: <%= date %></h3>
!SLIDE
# templates/cats_view.jst.hamljs
@@@ haml
%h1 All the cats
%h2 Owned by #{owner}
%ul#cats
%h3 List generated: #{date}
!SLIDE
## (no highlighting for haml :( )
!SLIDE
# backbone/views/cats_view.js.coffee
@@@ coffeescript
#= require templates/cats_view.jst.hamljs
class window.CatsView extends Backbone.View
template: JST['templates/cats_view']
render: =>
$(@el).html(this.template(this.templateData()))
this
!SLIDE
# EJS and Eco come as part of Sprockets
!SLIDE
# JHW supports `haml-sprockets` for `.hamljs`
!SLIDE
@@@ ruby
gem 'jasmine-headless-webkit', '~> 0.8.0'
gem 'haml-sprockets'
!SLIDE bullets incremental
# ERB files
* app/assets/javascripts/application.js.coffee.erb
!SLIDE
# ERB integrates with the host application
!SLIDE
# Since it integrates...
!SLIDE
# Integration testing...
!SLIDE
# Not our domain!
!SLIDE
# `.erb` files are actively ignored
!SLIDE
# application.js.coffee.erb
@@@ coffeescript
window.Routes = <%= Routes.to_json %>
window.CatTypes = <%= CatType.all.to_json %>
window.DefaultCatName = <%= CatName::DEFAULT %>
!SLIDE
# Testing code that relies on these values?
!SLIDE
# Mock and stub it in a helper!
!SLIDE
# spec/javascripts/support/jasmine.yml
@@@ yaml
spec_dir: spec/javascripts
helpers: [ "helpers/**.*" ]
!SLIDE
# Helpers load after code-under-test, but before specs
!SLIDE
## spec/javascripts/helpers/application_stubs.js.coffee
@@@ coffeescript
window.Routes = { what: 'ever' }
window.CatTypes = [ 'cute', 'mean' ]
window.DefaultCatName = "Fluffy"
!SLIDE bullets incremental
# Gems with JavaScript assets
* `jquery-rails`
* `backbone-rails`
!SLIDE
@@@ coffeescript
#= require jquery
$(->
alert "this works"
)
!SLIDE
# But now that we have Sprockets...
!SLIDE
# Jasmine libraries in gems!
!SLIDE bullets incremental
# `jasmine-spec-extras`
* `jasmine-jquery`
* `sinon`
!SLIDE
## spec/javascripts/helpers/spec_helper.js.coffee
@@@ coffeescript
#= require jasmine-jquery
#= require sinon
!SLIDE
## spec/javascripts/backbone/views/cats\_view\_spec.js.coffee
@@@ coffeescript
describe 'CatsView', ->
it 'should fire the action', ->
spy = sinon.spy()
view.bind('meow', spy)
view.$('button').trigger('click')
expect(spy.called).toBeTruthy()
!SLIDE smaller
## spec/javascripts/backbone/views/cats\_view\_spec.js.coffee
@@@ coffeescript
describe 'CatsView', ->
it 'should hit the server', ->
data = [ 'cat' ]
@server.respondWith('GET', 'cats', this.validResponse(data))
view.$('button').trigger('click')
@server.respond()
expect(view.cats).toEqual(data)
!SLIDE
# More Jasmine libraries will be added later!
!SLIDE bullets incremental
# Any of these folders in a loaded gem get added to the asset path
* app/assets/javascripts
* lib/assets/javascripts
* vendor/assets/javascripts
!SLIDE
# Very exciting!

27
intro/05_phantomjs.md Normal file
View File

@ -0,0 +1,27 @@
!SLIDE
# PhantomJS
!SLIDE
# Standalone Qt WebKit widget with JavaScript control
!SLIDE bullets incremental
# Jasmine runner source
* JHW - Filesystem
* PhantomJS - (preferably) Server
!SLIDE
# Sinon.JS XHR Mocking can do a lot
!SLIDE bullets incremental
# Some things don't work
* IFRAME
* Dynamically loading other JS
!SLIDE
# Use PhantomJS and `guard-jasmine`
!SLIDE
# Doesn't bother me!

53
intro/06_debugging.md Normal file
View File

@ -0,0 +1,53 @@
!SLIDE
# Debugging
!SLIDE
# Most problems are debuggable
!SLIDE
# Qt WebKit widget has a big limitation...
!SLIDE
# No stack traces!
!SLIDE
# Chrome, Safari, and other WebKit browsers implement their own stack traces
!SLIDE
# How do you debug problems like SyntaxErrors and other weird ones?
!SLIDE bullets incremental
# Write out the runner file!
* `--keep`
* `runner_output`
!SLIDE
# One-time shot?
!SLIDE
# `jasmine-headless-webkit --keep`
!SLIDE
# `--runner-out runner.html`
!SLIDE
# `open runner.html`
!SLIDE
# Write it all the time?
!SLIDE
## spec/javascripts/support/jasmine.yml
@@@ yaml
runner_output: "runner.html"
!SLIDE
# Debugging Sprockets includes
!SLIDE
# `jasmine-headless-webkit -l`
!SLIDE
# List all files that JHW will include, in order

21
intro/07_conclusion.md Normal file
View File

@ -0,0 +1,21 @@
!SLIDE
# Conclusion
!SLIDE
# For unit testing JavaScript
!SLIDE
# In a real browser
!SLIDE
# While supporting Rails conventions
!SLIDE
# Try `jasmine-headless-webkit`!
!SLIDE bullets incremental
# Learn more
* http://johnbintz.github.com/jasmine-headless-webkit/
* http://tryjasmine.com/

70
presentation.css Normal file
View File

@ -0,0 +1,70 @@
/* line 22, /Users/john/Projects/jasmine-headless-webkit-presentation/app/assets/stylesheets/presentation.css.scss */
#preso, .slide {
width: 1280px;
height: 800px;
background-color: #fdf6e3;
}
/* line 31, /Users/john/Projects/jasmine-headless-webkit-presentation/app/assets/stylesheets/presentation.css.scss */
#timeInfo {
display: inline;
float: right;
}
/* line 35, /Users/john/Projects/jasmine-headless-webkit-presentation/app/assets/stylesheets/presentation.css.scss */
pre.sh_sourceCode, .sh_yaml, .sh_haml {
background-color: #002b36;
-webkit-box-shadow: 0 0 5px #073642;
-moz-box-shadow: 0 0 5px #073642;
-o-box-shadow: 0 0 5px #073642;
box-shadow: 0 0 5px #073642;
}
/* line 40, /Users/john/Projects/jasmine-headless-webkit-presentation/app/assets/stylesheets/presentation.css.scss */
pre.sh_sourceCode code, .sh_yaml code, .sh_haml code {
color: #fdf6e3;
}
/* line 44, /Users/john/Projects/jasmine-headless-webkit-presentation/app/assets/stylesheets/presentation.css.scss */
pre.sh_sourceCode .sh_string, .sh_yaml .sh_string, .sh_haml .sh_string {
color: #dc322f;
}
/* line 48, /Users/john/Projects/jasmine-headless-webkit-presentation/app/assets/stylesheets/presentation.css.scss */
pre.sh_sourceCode .sh_symbol, .sh_yaml .sh_symbol, .sh_haml .sh_symbol {
color: #cb4b16;
}
/* line 52, /Users/john/Projects/jasmine-headless-webkit-presentation/app/assets/stylesheets/presentation.css.scss */
pre.sh_sourceCode .sh_comment, .sh_yaml .sh_comment, .sh_haml .sh_comment {
color: #586e75;
}
/* line 56, /Users/john/Projects/jasmine-headless-webkit-presentation/app/assets/stylesheets/presentation.css.scss */
pre.sh_sourceCode .sh_keyword, .sh_yaml .sh_keyword, .sh_haml .sh_keyword {
color: #b58900;
}
/* line 60, /Users/john/Projects/jasmine-headless-webkit-presentation/app/assets/stylesheets/presentation.css.scss */
pre.sh_sourceCode .sh_number, .sh_yaml .sh_number, .sh_haml .sh_number {
color: #2aa198;
}
/* line 64, /Users/john/Projects/jasmine-headless-webkit-presentation/app/assets/stylesheets/presentation.css.scss */
pre.sh_sourceCode .sh_function, .sh_yaml .sh_function, .sh_haml .sh_function {
color: #859900;
}
/* line 69, /Users/john/Projects/jasmine-headless-webkit-presentation/app/assets/stylesheets/presentation.css.scss */
#footer {
width: 1260px;
}
/* line 73, /Users/john/Projects/jasmine-headless-webkit-presentation/app/assets/stylesheets/presentation.css.scss */
body {
color: #002b36;
background-color: #93a1a1;
}
/* line 78, /Users/john/Projects/jasmine-headless-webkit-presentation/app/assets/stylesheets/presentation.css.scss */
h1 {
color: #002b36;
}
/* line 82, /Users/john/Projects/jasmine-headless-webkit-presentation/app/assets/stylesheets/presentation.css.scss */
h2 {
color: #073642;
}

28
presentation.js Normal file
View File

@ -0,0 +1,28 @@
$(function() {
var delay, isTiming, time, timer;
isTiming = false;
time = 0;
delay = 1000;
timer = null;
timer = function() {
var minute, output, second;
$('#footer span#timeInfo').remove();
$('#footer').append('<span id="timeInfo" />');
minute = ("00" + (Math.floor(time / 60))).substr(-2);
second = ("00" + (time % 60)).substr(-2);
output = "" + minute + ":" + second;
if (isTiming) output += " (running)";
$('#footer #timeInfo').text(output);
if (isTiming) time += 1;
return setTimeout(timer, delay);
};
timer();
return $(document).keyup(function(event) {
if (event.keyCode === 77) {
isTiming = !isTiming;
if (isTiming) time = 0;
}
return true;
});
});

6
showoff.json Normal file
View File

@ -0,0 +1,6 @@
{
"name": "jasmine-headless-webkit",
"sections": [
{"section": "intro"}
]
}