简体   繁体   中英

capybara-webkit js: true rspec tests not able to interact with database

I have used RSpec in conjunction with Capybara and Capybara-webkit on many Rails projects and it usually works smoothly. For some reason I'm having problems configuring the js: true feature specs to work this time around. They are not interacting with the database properly. I use factory_girl and database_cleaner to manage the test db content. I have DatabaseCleaner.strategy = :truncation in database_cleaner.rb for the js: true tests but it still doesn't work. Oddly, when I put in ActiveRecord::Base.establish_connection into databse_cleaner.rb the tests work fine. Why??

Here is rails_helper.rb :

# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
abort("The Rails environment is running in production mode!") if 
Rails.env.production?

require 'spec_helper'
require 'rspec/rails'

Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }

ActiveRecord::Migration.maintain_test_schema!

Capybara::Webkit.configure(&:block_unknown_urls)

RSpec.configure do |config|
  # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
  config.fixture_path = "#{::Rails.root}/spec/fixtures"

  config.use_transactional_fixtures = false

  config.infer_spec_type_from_file_location!

  # Filter lines from Rails gems in backtraces.
  config.filter_rails_from_backtrace!
  # arbitrary gems may also be filtered via:
  # config.filter_gems_from_backtrace("gem name")
end

This is the important parts of spec_helper.rb :

ENV['RAILS_ENV'] ||= 'test'

ENV['BUNDLE_GEMFILE'] = File.expand_path('../../Gemfile', __FILE__)
require 'bundler/setup'
Bundler.require
require 'pry-byebug'
require 'capybara/rspec'
require 'capybara/webkit'
require 'database_cleaner'
require 'webmock/rspec'

WebMock.disable_net_connect!(allow_localhost: true)

# use `describe 'Feature', type: :feature, js: true` to use this driver
Capybara.javascript_driver = :webkit

# tests use regular (faster) driver if they don't require js
Capybara.default_driver = :rack_test

Capybara::Webkit.configure do |config|
  config.allow_unknown_urls
end

RSpec.configure do |config|
  config.after(:suite) do
    FileUtils.rm_rf(Dir["#{Rails.root}/spec/test_files/"])
  end

  config.include Capybara::DSL
...

This is database_cleaner.rb (located in spec/support ):

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

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

  config.before(:each, js: true) do
    DatabaseCleaner.strategy = :truncation
  end

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

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

When I change this, the tests can interact with the db properly:

config.before(:each, js: true) do
  ActiveRecord::Base.establish_connection
  DatabaseCleaner.strategy = :truncation
end

Why? I shouldn't have to explicitly tell it to establish a db connection.

Your question states that you're using :transaction for your js tests, but the code shows :truncation. Truncation is what you should be using for your js tests so I assume the question is a typo.

You should be using the recommended database_cleaner - https://github.com/DatabaseCleaner/database_cleaner#rspec-with-capybara-example - which detects whether truncation is needed based on the driver being used rather than the 'js: true' metadata and also uses append_after rather than just after , which is very important for test stability.

I also don't see a require 'capybara/rails' anywhere in your rails_helper or spec_helper

When you set js: true , you're essentially just using Capybara which in essence is a Selenium-driven browser request. Any code running outside the test process (like this Selenium browser request) does not see the database fixture.

Preferable to what you're doing though, is to share the data state across the Selenium web server and test the code itself.

Somewhere in Rspec.config (possibly your database_cleaner.rb), you'll want to set

config.use_transactional_fixtures = false

"Everyday Rails Testing with Rspec" has a trick that was sometimes needed for certain test scenarios where you need to share the same DB connection before Rails 5. Although it can cause other issues as pointed out in comments below:

Make a spec/support/shared_db_connection.rb file and add this content:

class ActiveRecord::Base 
  mattr_accessor :shared_connection 
  @@shared_connection = nil

  def self.connection
    @@shared_connection || retrieve_connection
  end 
end
ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM