Configure RSpec and Capybara with Ruby on Rails

Posted on November 25, 2018 - 7 Minute Read

In this tutorial I'm going to show you how to configure your Rails app to use RSpec and Capaybara. In addition, we will also install and configure Factory Bot Rails and Database Cleaner, since these Gems help with a better testing experience.

1. Create a New App and Skip Tests

Since we'll be using rspec-rails as the test framework, we need to skip the default Rails test suite.

  1. Open up a new terminal and create a new Rails app. Be sure to pass the --skip-test flag. This will skip the default test suite
rails new rspec-test-app --skip-test
cd rspec-test-app/

2. Install and Configure RSpec Rails

rspec-rails is a testing framework for Rails 3.x, 4.x and 5.x. rspec-rails extends Rails' built-in testing framework to support rspec examples for requests, controllers, models, views, helpers, mailers and routing.

TLDR: rspec-rails is a popular alternative to the default Rails test suite.

  1. Add gem 'rspec-rails' to your Gemfile in the :development, :test group.
group :development, :test do
    ...
    gem 'rspec-rails', '~> 3.8'
end
  1. In the terminal window, run bundle install
  2. In the terminal window, run rails generate rspec:install per rspec-rails instructions

3. Install and Configure Capybara

Capybara is a library written in the Ruby programming language which makes it easy to simulate how a user interacts with your application.

  1. Add gem 'capybara' to your Gemfile in the :development, :test group.
group :development, :test do
    ...
    gem 'rspec-rails', '~> 3.8'
    gem 'capybara'
end
  1. In the terminal window, run bundle install
  2. Create a new directory at spec/support/ by running mkdir spec/support in the terminal window
  3. Create capybara.rb in spec/support by running touch spec/support/capybara.rb in the terminal window
  4. Open spec/support/capybara.rb and add the following:
require 'capybara/rails'
require 'capybara/rspec'
  1. Open spec/rails_helper.rb and add require 'support/capybara'. Make sure to add it after require 'rspec/rails'
# This file is copied to spec/ when you run 'rails generate rspec:install'
require 'spec_helper'
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
# Prevent database truncation if the environment is production
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'rspec/rails'
# Add additional requires below this line. Rails is not loaded until this point!
require 'support/capybara'

4. Install and Configure Database Cleaner

Database Cleaner is used to ensure a clean state for testing.

  1. Add gem 'database_cleaner' to your Gemfile in the :test group.
group :test do
    gem 'database_cleaner'
end
  1. In the terminal window, run bundle install
  2. Create database_cleaner.rb in spec/support by running touch spec/support/database_cleaner.rb in the terminal window
  3. Delete config.use_transactional_fixtures = true from spec/rails_helper.rb
  4. Open spec/support/database_cleaner.rb and add the following:
RSpec.configure do |config|

  config.use_transactional_fixtures = false
  
  config.before(:suite) do
    if config.use_transactional_fixtures?
      
      raise(<<-MSG)
        Delete line `config.use_transactional_fixtures = true` from rails_helper.rb
        (or set it to false) to prevent uncommitted transactions being used in
        JavaScript-dependent specs.
        During testing, the Ruby app server that the JavaScript browser driver
        connects to uses a different database connection to the database connection
        used by the spec.
        
        This Ruby app server database connection would not be able to see data that
        has been setup by the spec's database connection inside an uncommitted
        transaction.
        Disabling the use_transactional_fixtures setting helps avoid uncommitted
        transactions in JavaScript-dependent specs, meaning that the Ruby app server
        database connection can see any data set up by the specs.
      MSG

    end
  end
  
  config.before(:suite) do
    DatabaseCleaner.clean_with(:truncation)
  end

  config.before(:each) do
    DatabaseCleaner.strategy = :transaction
  end

  config.before(:each, type: :feature) do
    # :rack_test driver's Rack app under test shares database connection
    # with the specs, so we can use transaction strategy for speed.
    driver_shares_db_connection_with_specs = Capybara.current_driver == :rack_test

    if driver_shares_db_connection_with_specs
      DatabaseCleaner.strategy = :transaction
    else
      # Non-:rack_test driver is probably a driver for a JavaScript browser
      # with a Rack app under test that does *not* share a database 
      # connection with the specs, so we must use truncation strategy.
      DatabaseCleaner.strategy = :truncation
    end
  end

  config.before(:each) do
    DatabaseCleaner.start
  end

  config.after(:each) do
    DatabaseCleaner.clean
  end

end
  1. Open spec/rails_helper.rb and add require 'support/database_cleaner'. Make sure to add it after require 'rspec/rails'. Also, make sure this is the first file your require after require 'rspec/rails'
# This file is copied to spec/ when you run 'rails generate rspec:install'
require 'spec_helper'
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
# Prevent database truncation if the environment is production
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'rspec/rails'
# Add additional requires below this line. Rails is not loaded until this point!
require 'support/database_cleaner'
require 'support/capybara'

5. Install and Configure Factory Bot Rails

factory_bot is a fixtures replacement with a straightforward definition syntax, support for multiple build strategies (saved instances, unsaved instances, attribute hashes, and stubbed objects), and support for multiple factories for the same class (user, admin_user, and so on), including factory inheritance.

TLDR: factory_bot makes it easy to create sample data to test against

  1. Add gem 'factory_bot_rails' to your Gemfile in the :development, :test group.
group :development, :test do
    ...
    gem 'rspec-rails', '~> 3.8'
    gem 'capybara'
    gem 'factory_bot_rails'
end
  1. In the terminal window, run bundle install
  2. Create factory_bot.rb in spec/support by running touch spec/support/factory_bot.rb in the terminal window
  3. Open spec/support/factory_bot.rb and add the following:
RSpec.configure do |config|
  config.include FactoryBot::Syntax::Methods

  config.before(:suite) do
    begin
      DatabaseCleaner.start
      # Test factories in spec/factories are working.
      FactoryBot.lint
    ensure
      DatabaseCleaner.clean
    end
  end

end
  1. Open spec/rails_helper.rb and add require 'support/factory_bot'. Make sure to add it after require 'support/database_cleaner'.
# This file is copied to spec/ when you run 'rails generate rspec:install'
require 'spec_helper'
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
# Prevent database truncation if the environment is production
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'rspec/rails'
# Add additional requires below this line. Rails is not loaded until this point!
require 'support/database_cleaner'
require 'support/factory_bot'
require 'support/capybara'
  1. Create a new directory at mkdir spec/factories/ by running mkdir spec/factories in the terminal window. This is required by factory_bot_rails

  2. To ensure everything is set up correctly, open up a terminal window and run rails spec. You should get something similar to the following:

No examples found.


Finished in 0.00045 seconds (files took 0.29464 seconds to load)
0 examples, 0 failures

6. Create Our First Test (Optional)

Now that our app's test suite is configured with RSpec, Capybara, Factory Bot Rails and Database Cleaner, let's write some tests to ensure everything is working.

  1. In the terminal window, run rails g scaffold Article name:string description:text to generate a new scaffold. You'll notice that this generates a whole lot of specs, as well as a factory.
invoke  active_record
create    db/migrate/20181127001549_create_articles.rb
create    app/models/article.rb
invoke    rspec
create      spec/models/article_spec.rb
invoke      factory_bot
create        spec/factories/articles.rb
invoke  resource_route
route    resources :articles
invoke  scaffold_controller
create    app/controllers/articles_controller.rb
invoke    erb
create      app/views/articles
create      app/views/articles/index.html.erb
create      app/views/articles/edit.html.erb
create      app/views/articles/show.html.erb
create      app/views/articles/new.html.erb
create      app/views/articles/_form.html.erb
invoke    rspec
create      spec/controllers/articles_controller_spec.rb
create      spec/views/articles/edit.html.erb_spec.rb
create      spec/views/articles/index.html.erb_spec.rb
create      spec/views/articles/new.html.erb_spec.rb
create      spec/views/articles/show.html.erb_spec.rb
create      spec/routing/articles_routing_spec.rb
invoke      rspec
create        spec/requests/articles_spec.rb
invoke    helper
create      app/helpers/articles_helper.rb
invoke      rspec
create        spec/helpers/articles_helper_spec.rb
invoke    jbuilder
create      app/views/articles/index.json.jbuilder
create      app/views/articles/show.json.jbuilder
create      app/views/articles/_article.json.jbuilder
invoke  assets
invoke    coffee
create      app/assets/javascripts/articles.coffee
invoke    scss
create      app/assets/stylesheets/articles.scss
invoke  scss
create    app/assets/stylesheets/scaffolds.scss
  1. In the terminal window, run rails db:migrate to migrate the database.
  2. In a terminal window, run rails spec to run the test suite against the generated tests. You should get something similar to the following:
Finished in 1.97 seconds (files took 2.22 seconds to load)
27 examples, 0 failures, 13 pending
  1. This was just an exercise to ensure the test suite is running correctly. The generated tests are working, but are mostly blank. For more examples on how to configure your tests, I recomend looking at RSpec Rails Examples
Categorized In:Tagged In: