loading presentation...
jasmine-headless-webkit
The fastest way to test your browser-targeted JavaScript!
Ajax-y apps are complex nowadays!
- jQuery
- Backbone
- Tons of other JavaScripty things
- Client/server communication
Lots of different ways to test
Standalone JavaScript Engines
- Node.JS
- EnvJS
- Rhino
- ...and others!
Great for testing JS Libraries
Not so great in testing in "real" browsers
Fake DOMs aren't quite the same
(with the way I write tests, at least)
Full-stack Integration testing tools
- Capybara
- Cucumber
- Selenium
Server-side dependency management
Server-based testing tools
- Jasmine gem
jasmine-rails
Compiles assets for testing
What I wanted is a JS testing tool that...
- Runs fast
- In a real browser so I can use jQuery & Backbone straight
- That supports modern Ruby webapp conventions
- Is built for continuous testing
johnbintz.github.com/jasmine-headless-webkit
gem install jasmine-headless-webkit
Gemfile
gem 'jasmine-headless-webkit', '~> 0.8.0'
Rails 3.1 Application
- Asset pipeline using Sprockets
spec/javascripts
holds tests
The Pivotal Labs jasmine
gem
spec/javascripts/support/jasmine.yml
Supporting the Jasmine gem conventions
(easier to convert existing projects to JHW)
spec/javascripts/support/jasmine.yml
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/**/*' ]
Sprockets and Jasmine load files differently
spec/javascripts/support/jasmine.yml
src_dir: app/assets/javascripts
asset_paths:
- lib/assets/javascripts
- vendor/assets/javascripts
spec_dir: spec/javascripts
# ...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"
//= require backbone/models/cat
//= require backbone/collections/cats
//= require backbone/views/global_view
class window.CatsView extends GlobalView
The Jasmine Way
src_dir: app/assets/javascripts
src_files: [ '**/*' ]
spec_dir: spec/javascripts
spec_files: [ '**/*[Ss]pec.*' ]
helpers: [ 'helpers/**/*' ]
Dir["app/assets/javascripts/**/*"]
Dir["spec/javascripts/**/*[Ss]pec.*"]
Dir["spec/javascripts/helpers/**/*"]
JHW ensures that no file is loaded twice
Ensures Sprockets dependencies are loaded in the right order
RSpec?
describe "CatsView" do
before do
@cats = [ stub ]
end
it 'should show cats' do
render
rendered.should have_css('#cats li')
end
end
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')
});
});
CoffeeScript?
describe "CatsView", ->
view = null
beforeEach ->
view = new CatsView(collection: [ {} ])
it 'should show cats', ->
view.render()
expect($(view.el)).toContain('#cats li')
Plenty of resources to learn Jasmine itself
pivotal.github.com/jasmine
For Backbone and Sinon.js
tinnedfruit.com/2011/03/03/testing-backbone-apps-with-jasmine-sinon.html
But once you know Jasmine...
Gems with JavaScript assets
jquery-rails
backbone-rails
#= require jquery
$(->
alert "this works"
)
But now that we have Sprockets...
Jasmine libraries in gems!
spec/javascripts/helpers/spec_helper.js.coffee
#= require jasmine-jquery
#= require sinon
spec/javascripts/backbone/views/cats_view_spec.js.coffee
describe 'CatsView', ->
it 'should fire the action', ->
spy = sinon.spy()
view.bind('meow', spy)
view.$('button').trigger('click')
expect(spy.called).toBeTruthy()
spec/javascripts/backbone/views/cats_view_spec.js.coffee
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)
More Jasmine libraries will be added later!
Any of these folders in a loaded gem get added to the asset path
- app/assets/javascripts
- lib/assets/javascripts
- vendor/assets/javascripts
templates/cats_view.jst.ejs
<h1>All the cats</h1>
<h2>Owned by <%= owner %></h2>
<ul id="#cats"></ul>
<h3>List generated: <%= date %></h3>
templates/cats_view.jst.hamljs
%h1 All the cats
%h2 Owned by #{owner}
%ul#cats
%h3 List generated: #{date}
(no highlighting for haml :( )
backbone/views/cats_view.js.coffee
#= 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
EJS and Eco come as part of Sprockets
JHW supports haml-sprockets
for .hamljs
gem 'jasmine-headless-webkit', '~> 0.8.0'
gem 'haml-sprockets'
Any gem that plugs into Sprockets is potentially usable
ERB files
- app/assets/javascripts/application.js.coffee.erb
ERB integrates with the host application
.erb
files are actively ignored
application.js.coffee.erb
window.Routes = <%= Routes.to_json %>
window.CatTypes = <%= CatType.all.to_json %>
window.DefaultCatName = <%= CatName::DEFAULT %>
Testing code that relies on these values?
Mock and stub it in a helper!
spec/javascripts/support/jasmine.yml
spec_dir: spec/javascripts
helpers: [ "helpers/**.*" ]
Helpers load after code-under-test, but before specs
spec/javascripts/helpers/application_stubs.js.coffee
window.Routes = { what: 'ever' }
window.CatTypes = [ 'cute', 'mean' ]
window.DefaultCatName = "Fluffy"
Standalone Qt WebKit widget with JavaScript control
Jasmine runner source
- JHW - Filesystem
- PhantomJS - (preferably) Server
Sinon.JS XHR Mocking can do a lot
Some things don't work
- IFRAME
- Dynamically loading other JS
Use PhantomJS and guard-jasmine
Most problems are debuggable
Qt WebKit widget has a big limitation...
Chrome, Safari, and other WebKit browsers implement their own stack traces
How do you debug problems like SyntaxErrors and other weird ones?
Write out the runner file!
jasmine-headless-webkit --keep
spec/javascripts/support/jasmine.yml
runner_output: "runner.html"
Debugging Sprockets includes
jasmine-headless-webkit -l
List all files that JHW will include, in order
For unit testing JavaScript
While supporting Rails conventions
Try jasmine-headless-webkit
!
Learn more
- johnbintz.github.com/jasmine-headless-webkit
- pivotal.github.com/jasmine
- tryjasmine.com
- tinnedfruit.com/2011/03/03/testing-backbone-apps-with-jasmine-sinon.html