Testing with rspec and capybara in rails
We’re supposing, you’ve a rails app already working. Now you want to write test cases for testing your rails app. Let’s see how to do.
Add gem 'rspec-rails'
to your Gemfile
in the :development, :test
group
.
group :development, :test do
...
gem 'rspec-rails', '~> 3.8', '>= 3.8.2'
end
- In the terminal window, run
bundle install
- In the terminal window, run
rails generate rspec:install
. - Add
gem 'factory_bot_rails'
to yourGemfile
in the:development, :test
group
.
group :development, :test do
...
gem 'rspec-rails', '~> 3.8', '>= 3.8.2'
gem 'factory_bot_rails', '~> 5.1'
end
the terminal window, run bundle install
- Create a new directory at
mkdir spec/factories/
by runningmkdir spec/factories
in the terminal window. This is required by factory_bot_rails - Create a new directory at
spec/support/
by runningmkdir spec/support
in the terminal window - Create
factory_bot.rb
inspec/support
by runningtouch spec/support/factory_bot.rb
in the terminal window - Open
spec/support/factory_bot.rb
and add the following:
RSpec.configure do |config|
config.include FactoryBot::Syntax::Methods
end
Add gem 'capybara'
to your Gemfile
in the :development, :test
group
.
group :development, :test do
...
gem 'rspec-rails', '~> 3.8', '>= 3.8.2'
gem 'factory_bot_rails', '~> 5.1'
gem 'capybara', '~> 3.29'
end
- In the terminal window, run
bundle install
- Create
capybara.rb
inspec/support
by runningtouch spec/support/capybara.rb
in the terminal window - Open
spec/support/capybara.rb
and add the following:
require 'capybara/rspec'
- Add
gem 'database_cleaner'
to yourGemfile
in the:test
group
.
group :test do
gem 'database_cleaner', '~> 1.7'end
- In the terminal window, run
bundle install
- Open
spec/support/capybara.rb
and add the following:
require 'capybara/rspec'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 app-under-test that the browser driver
connects to uses a different database connection to the
database connection used by the spec. The app's database
connection would not be able to access uncommitted
transaction data setup over the spec's database
connection.
MSG
end
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
config.before(:each, type: :feature) do
driver_shares_db_connection_with_specs = Capybara.current_driver
== :rack_test
unless driver_shares_db_connection_with_specs
DatabaseCleaner.strategy = :truncation
end
end
config.before(:each) do
DatabaseCleaner.start
end
config.append_after(:each) do
DatabaseCleaner.clean
end
end
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.
In the terminal window, run rails db:migrate RAILS_ENV=test — trace
to migrate the database. I’ve a user model already with following association in app/models/user.rb
.
has_many :businesses, -> { distinct} , through: :memberships, dependent: :destroy
And business model with following validation in app/models/business.rb
.
validates :name, :phone, :address1, :city, :state, :zip, :country, presence: true
And a scope businesses
to fined user’s approved business
scope :businesses, -> do where(approved: true)end
Now generatespec/models/business_spec.rb
by running following command:
rails generate rspec:model business
Update spec/models/business_spec.rb
with the following code:
require 'rails_helper'RSpec.describe Business, type: :model do
context 'business scope test' do
before(:each) do
Business.new(name: 'Test1', phone: '12345678', address1: 'Test
Address-1', city: 'Test City-1', state: 'Test State-1', zip:
'1234', country: 'Test Country-1').save! Business.new(name: 'Test2', phone: '12345678', address1: 'Test
Address-2', city: 'Test City-2', state: 'Test State-2', zip:
'1234', country: 'Test Country-2', approved:true).save! Memberships.create(user_id: 2, business_id: Business.first.id) end it 'should return approved businesses for a user' do
expect(User.second.businesses.size).to eq(1)
end
end
end
Run rspec
. It will first create two business, one with approved: true
and one will have approved: false
by default. Then it will create a membership of second user for first business in our database. Then it will retrieve all businesses of second user with approved: true
which counts to 1.