Search code examples
ruby-on-railsrspecdeviseselenium-chromedrivercapybara

Chromedriver getting rejected by test database


Have 2017 Rails project I'm trying to write Rspec tests for. It uses Capybara, FactoryBot and Devise.

I'm using Chromedriver, which fails to sign in the user during the first Rspec system test - the chrome browser brings up the bootstrap alert of wrong credentials.

I have confirmed the user is indeed in test database, and with the correct credentials using binding.pry.

If I don't use a driver (ie., if I take out :js => true from scenario), it logs the user in fine.

I have installed webdrivers gem, it is running chromedriver 114.0.5735.90, have this in the rails_helper:

Capybara.register_driver :selenium_chrome do |app|
  Capybara::Selenium::Driver.new(app, browser: :chrome)
end

Capybara.default_driver = :selenium_chrome
Capybara.javascript_driver = :selenium_chrome

application.rb

require 'webdrivers/chromedriver'
Webdrivers::Chromedriver.required_version = "114.0.5735.90"

test.log

Completed 401 Unauthorized in 9ms (ActiveRecord: 2.4ms)
Processing by Devise::SessionsController#new as HTML
  Parameters: {"utf8"=>"✓", "fan"=>{"email"=>"[email protected]", "password"=>"[FILTERED]", "remember_me"=>"0"}, "commit"=>"Sign in"}

gem


gem 'rails', '>= 5.0.1.rc2', '< 5.1'

group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug', platform: :mri
  gem 'rspec-rails', '~> 3.5.0'
  gem 'puma', '~> 3.0'
end

group :test do
  gem 'capybara', '~> 3.6.0'
  gem 'factory_girl_rails', '~> 4.7'
  gem 'faker'
  gem 'selenium-webdriver', '~> 3.6.0'
  gem "database_cleaner", "~> 1.5"
  gem 'shoulda-matchers', '~> 3.1'
  gem 'launchy'
end

... I tried using geckodriver instead, but get this error:

Failures:

  1) Splash and devise: Fans in Canada can sign in, visit signed in home page, and log out in
     Failure/Error: click_link('LOG IN')
     
     Selenium::WebDriver::Error::UnknownError:
       Invalid Content-Type

UPDATE

Thomas, much appreciated thank you.

I erased the other redundant question, as well as the server port/app_host.

So... we've got 3 different threads that do not communicate. Most likely an antiquated issue if project was updated, but I had it in mind to create the tests for this project before attempting updating it (I am not a professional developer).

I started to research the thread issue, which led me to this question, which led me to this post, which has (in section 3) code on how to get active record to run the same thread as the test, which worked.

However, it also mentions putting use_transactional_fixtures to true and no longer using database cleaner (rails 5.0.1), which I tried, but received this error:

An error occurred in a `before(:suite)` hook.
Failure/Error:
        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

Otherwise, this is my current configuration. It is factorybot, devise, rspec, capybara, chromedriver. I don't think any other config modifications have been made, will look more after a nap.

rails_helper

# This file is copied to spec/ when you run 'rails generate rspec:install'
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 'spec_helper'
require 'rspec/rails'
# Add additional requires below this line. Rails is not loaded until this point!
require "devise"
require "pundit/rspec"
require 'capybara/rails'

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

# If you are not using ActiveRecord, you can remove this line.
ActiveRecord::Migration.maintain_test_schema!

Capybara.register_driver :selenium_chrome do |app|
  Capybara::Selenium::Driver.new(app, browser: :chrome)
end

Capybara.default_driver = :selenium_chrome
Capybara.javascript_driver = :selenium_chrome

Capybara.run_server = true 

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

  def self.connection
    @@shared_connection || retrieve_connection
  end
end

# Forces all threads to share the same connection. This works on
# Capybara because it starts the web server in a thread.
ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection

RSpec.configure do |config|
  config.include Devise::Test::ControllerHelpers, type: :controller

  # controller spec macros
  config.extend ControllerMacros, :type => :controller

  # Include Factory Girl syntax to simplify calls to factories
  config.include FactoryGirl::Syntax::Methods 
  
  # 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!
  config.include Rails.application.routes.url_helpers
  # 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")
  config.include Warden::Test::Helpers, type: :feature
  config.after(type: :feature) { Warden.test_reset! }
  config.include Capybara::DSL
  config.filter_run_when_matching focus: true

end

Shoulda::Matchers.configure do |config|
  config.integrate do |with|
    with.test_framework :rspec
    with.library :rails
  end
end

application.rb

require 'webdrivers/chromedriver'
Webdrivers::Chromedriver.required_version = "114.0.5735.90"

... looking now, don't see any mention of database cleaner outside of the gemlist, but there's only ever one factorybot initiated user in test db, so I assume something's working somewhere.

if this is cool I'll proceed. i've been working on this first scenerio of the first of 50 system tests i want to make for over 10 days


Solution

  • You're creating multiple questions about the same issue, that's a sure way to get yourself banned from stackoverflow. You're also jumping to assumptions that don't seem to have any logical basis, like that it's a chromedriver issue.

    Given the information provided

    1. Why are you manually setting Capybara.server port? If you don't have a really good reason for doing that, remove it.
    2. Why are you setting Capybara.app_host, same as #1.
    3. I have confirmed the user is indeed in test database, and with the correct credentials using binding.pry. -- where did you put the binding.pry? Was it in test code or in application code? Did you connect to the DB directly and check if there is a record in it?
    4. When running Capybara using selenium you have multiple things going on a) Capybara runs the application in one thread - which has it's own connection to the database. b) Tests are run in another thread, and have their own DB connection c) Browser runs in its own process and connects to the application under test Given those things, there are a few possiblities
      1. you're running in transaction mode, which means records created in the test thread wouldn't be visible to the application - connecting to the DB directly (outside of ruby) while the tests are paused and checking if the records are actually getting committed to the DB would verify that
      2. your application isn't actually connecting to the DB your tests are - what other default configurations have been changed?
      3. you're telling the browser to connect to a completely different instance of the application running against a different DB (dev instance potentially?) - hence the suggestion to stop overriding Capybaras settings and just let it do it's thing. Have you watched the browser and seen what url it's going to? Look at the browser console and see where it posted the login credentials to, etc?

    This would all be easier if you updated the versions of software you're using to modern levels. For instance, newer rails will share the DB connection between the tests and application allowing to run in transaction mode and removing the need for database-cleaner, etc in most situations - simplifying setup