55 Minutes

Welcome to the 55 Minutes blog.
55 Minutes is a web development consultancy in San Francisco building apps for design-led businesses and startups. On this blog we discuss the technology tools of our trade: Ruby on Rails, Django, Sass, OS X, and more.

Using RSpec and capybara-webkit to Test for JavaScript Errors

Even if your Rails application doesn’t have enough JavaScript to warrant a full front-end test suite, you can still automate a basic JavaScript smoke test using RSpec and capybara-webkit. It’s as simple as using the have_errors matcher. Here’s how to set up capybara-webkit and add a basic JavaScript spec.

tl;dr

With capybara-webkit properly installed, just add an example like this:

it 'should not have JavaScript errors', :js => true do
  visit(root_path)
  expect(page).not_to have_errors
end

It’s not comprehensive by any means, but this test will alert you to major JavaScript bugs like syntax errors or failing jQuery selectors due to markup changes.

Read on to learn how to set up RSpec, capybara, and capybara-webkit in a new Rails app.

1. Configure Rails for RSpec

Rails doesn’t use RSpec out of the box, so after creating a new Rails project you’ll need to add this gem to your Gemfile and run bundle:

group :test do
  gem 'rspec-rails', :group => :development
end

Next, in config/initializers/generators.rb, tell Rails to use RSpec format whenever it generates test code. This applies to things like rails generate [controller|model|resource|scaffold] You can also disable generated code for specs that you don’t find useful.

Rails.application.config.generators do |g|
  g.test_framework :rspec, :view_specs => false,
                           :controller_specs => false,
                           :request_specs => false,
                           :routing_specs => false
end

Now run the RSpec installer to create the spec directory and the spec_helper.rb configuration file:

rails generate rspec:install

2. Install Qt

You’ll need to have the Qt libraries in order to install capybara-webkit. Here’s how to do it on the Mac, assuming you have homebrew:

brew install qt

If that fails, or if you’re on a different platform, check the capybara-webkit wiki for instructions.

3. Install capybara and capybara-webkit

Add these gems to your Gemfile and run bundle:

group :test do
  gem 'capybara'
  gem 'capybara-webkit'
  gem 'database_cleaner'
end

Capybara-webkit runs your Rails app separately from your RSpec code, which means that the database transaction test strategy used by Rails leads to problems. The database_cleaner gem provides a nice workaround, which is why we need it in addition to the capybara gems.

Open spec_helper.rb and configure capybara, capybara-webkit, and database_cleaner as follows:

require 'capybara/rspec'
require 'capybara/webkit/matchers'
Capybara.javascript_driver = :webkit

RSpec.configure do |config|
  config.use_transactional_fixtures = false
  config.before(:each) do
    DatabaseCleaner.strategy = example.metadata[:js] ? :truncation : :transaction
    DatabaseCleaner.start
  end
  config.after(:each) do
    DatabaseCleaner.clean
  end

  config.include(Capybara::Webkit::RspecMatchers, :type => :feature)
end

4. Write a simple JavaScript smoke test

Browser-driven tests are known as feature specs in RSpec terminology, and belong in spec/features/. This is where we’ll put our simple JavaScript test. (You may also hear these referred to as integration tests.)

Create a spec/features/home_spec.rb file like this:

require 'spec_helper'

feature 'Home' do
  it 'should not have JavaScript errors', :js => true do
    visit(root_path)
    expect(page).not_to have_errors
  end
end

The most interesting part is :js => true. This RSpec metadata is what instructs capybara-webkit to run the test against a real HTTP version of your app, using the WebKit browser engine (similar to what powers Safari and Chrome).

Without :js => true, the normal capybara driver is used, which by default interacts with Rails directly via Rack. JavaScript testing is not possible with this default driver, but it is very fast. To keep your specs fast, use capybara-webkit only for tests that require a JavaScript runtime.

5. Running the test

If everything goes well, you should see this output when running rake spec:

/Users/mbrictson/.rbenv/versions/2.0.0-p247/bin/ruby -S rspec ./spec/features/home_spec.rb
.

Finished in 1.11 seconds
1 example, 0 failures

Randomized with seed 44770

Of course, a test is only good if it catches errors. Here’s what it looks like when a syntax error creeps into our JavaScript:

Failures:

  1) Home should not have JavaScript errors
     Failure/Error: expect(page).not_to have_errors
       Expected no Javascript errors, got:
         - SyntaxError: Parse error
     # ./spec/features/home_spec.rb:6:in `block (2 levels) in <top (required)>'

Next steps

Once you have a nice test suite running locally, considering automating it using a continuous integration server. Our tutorial on Running capybara-webkit specs with Jenkins CI will help you get started.

Finally, if you like the RSpec and capybara practices outlined in this post, check out our rails-starter template for new Rails projects. RSpec, capybara, and capybara-webkit are baked right in, along with many other useful tools and techniques.

comments powered by Disqus