Use Capybara-webkit in Rails RSpec


About Capybara-webkit

Capybara-webkit is a headless browser. It can execute javascript. (capybara can’t execute javascript.)
If you want to do integration test you had better use capybara-webkit instead of capybara.

Prepare Gems

group :test do
  gem 'factory_girl_rails'
  gem 'capybara'
  gem 'capybara-webkit'   # add capybara-webkit
  gem 'database_cleaner'  # add database cleaner

You need to add database_cleaner.
It makes database clean every test case.

Database clear vs Shared Connection said that…

When running your tests by default, Rails wraps each scenario in a database transaction. This means, at the end of each test, Rails will rollback any changes to the database that happened within that spec.
Unfortunately, when we use a JavaScript driver, the test is run in another thread. This means it does not share a connection to the database.

There are 2 ways to use same data between capybara and capybara-webkit threads.

  • one is that commit all data and use it between 2 threads. after each test all of data is deleted.
  • another is taht share the database connection between 2 threads. recommended former (commit and delete data).
If you want to know why ? You should read this article.

Change config


  • set Capybara.javascript_driver.
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= 'test'
require 'spec_helper'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
# Add additional requires below this line. Rails is not loaded until this point!
Capybara.javascript_driver = :webkit # add this line.
  • comment in to load spec/support/**/*.rb files.
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }  # comment in this line.

# Checks for pending migrations before tests are run.
# If you are not using ActiveRecord, you can remove this line.
  • set use_transactional_fixtures to commit all queries in testcase. It makes capybara and capybara-webkit use same data.
  • If you want to know detail you should check this article.
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
config.use_transactional_fixtures = false # set false

Add Helper

  • add this file as spec/support/database_cleaner.rb to clear database every test.
  • add this WaitForAjax module as spec/support/wait_for_ajax.rb to wait ajax request callback.

Use capybara-webkit

  • add spec file as /spec/features/**.rb
  • add js: true option to scenario function
  feature "new todo title is inputed" do
    scenario "new todo should create in html" , js:true do
      visit "/"

Ajax test

  • add wait_for_ajax function after ajax trigger(e.g. click)
  feature "todo's all-completed checkbox is clicked" do
    scenario "all todos should be deleted in html", js: true do
      visit "/"
      click_button("delete button") # request delete to server using ajax
      expect().to be XXXX


I created integration test useing capybara-webkit.

kashiro/todomvc_on_rails_fork (feature/update branch)

  • clone and checkout
git clone [email protected]:kashiro/todomvc_on_rails_fork.git
cd todomvc_on_rails_fork
git checkout feature/update
  • add qt for capybara-webkit
brew install qt
  • update gems
bundle install
  • execute test
rspec spec