Reputation: 6980
I am using Rails 5 (Ruby 2.3.3) for one of my projects. I have written a test using Capybara (capybara-wekbit) and RSpec.
I am testing a controller action using request spec. Here is the controller
class TimelineController < ApplicationController
before_action :set_child
before_action :authenticate_user!
def index
end
private
def set_child
@child = Child.find(params[:child_id])
end
end
Here is the test
RSpec.describe "Timeline", type: :request do
it 'can visit the child timeline path', js: true do
child = FactoryGirl.create(:valid_child)
sign_in child.caregiver.user
p child
visit child_timeline_path(child)
end
end
The p child
line prints the following
#<Child id: 1, first_name: nil, last_name: nil, dob: "2018-06-21 00:00:00", caregiver_id: 1, doctor_id: 1, preferred_name: nil, gender: nil, street: nil, city: nil, province: nil, postal: nil, country: nil, email: nil, caregiver_relationship: nil, phone: nil, created_at: "2018-06-21 20:21:16", updated_at: "2018-06-21 20:21:16", avatar: nil, time_zone: "Pacific Time (US & Canada)", other_relationship: nil>
However, when RSpec calls visit child_timeline_path(child)
, the test fails with the following error:
1) Timeline can visit the child timeline path
Failure/Error: @child = Child.find(params[:child_id])
ActiveRecord::RecordNotFound:
Couldn't find Child with 'id'=1
I see the child record printed with the id. However, rspec is unable to find the record.
Here is the child factory (FactoryGirl)
FactoryGirl.define do
factory :valid_child, class: "Child" do |f|
f.association :doctor
f.association :caregiver
f.dob Date.today
end
end
Also, if it helps, here is the spec_helper.rb
require 'capybara/rspec'
Dir["./spec/support/**/*.rb"].sort.each {|f| require f}
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
config.include Capybara::DSL
config.include Devise::Test::IntegrationHelpers, type: :request
Capybara.javascript_driver = :webkit
# rspec-expectations config goes here. You can use an alternate
# assertion/expectation library such as wrong or the stdlib/minitest
# assertions if you prefer.
config.expect_with :rspec do |expectations|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
# rspec-mocks config goes here. You can use an alternate test double
# library (such as bogus or mocha) by changing the `mock_with` option here.
config.mock_with :rspec do |mocks|
mocks.verify_partial_doubles = true
end
# This option will default to `:apply_to_host_groups` in RSpec 4 (and will
# have no way to turn it off -- the option exists only for backwards
# compatibility in RSpec 3). It causes shared context metadata to be
# inherited by the metadata hash of host groups and examples, rather than
# triggering implicit auto-inclusion in groups with matching metadata.
config.shared_context_metadata_behavior = :apply_to_host_groups
config.before(:suite) do
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
end
config.around(:each) do |example|
DatabaseCleaner.cleaning do
example.run
end
end
end
Upvotes: 1
Views: 1623
Reputation: 49910
DatabaseCleaner.strategy = :transaction
means that the app under test and the tests need to share the same database connection in order to see created records. Unfortunately with Rails 5 (fixed in Rails 5.1+ obviating the need for database_cleaner at all) that isn't really supported between threads. This means that when running the js: true
feature tests (which run the app in a separate thread) you need to change the strategy to :truncation or :deletion. The suggested DatabaseCleaner configuration shows exactly what's needed - https://github.com/DatabaseCleaner/database_cleaner#rspec-with-capybara-example
Upvotes: 5