ruby-on-railsrubyrspeccapybara

default_driver being ignored by Capybara in Rails/RSpec tests


I am hoping someone can point out what I am doing wrong. I wanted to configure RSpec/Capybara to do my system tests such that the default behaviour would be to run headless, but if I set js:true on the test, then it would run in standard browser mode so I could watch it, and work out why the test is failing.

I originally set javascript_driver to :selenium_chrome in my spec/rails_helper.rb file and js:true on the failing test. That did not make a browser window appear. I then tried setting default_driver to :selenium_chrome as well, but that too failed to generate any effect either.

For completeness sake, here is the full spec/rails_helper.rb file:

# This file is copied to spec/ when you run 'rails generate rspec:install'
require 'spec_helper'

ENV['RAILS_ENV'] ||= 'test'
require_relative '../config/environment'

# Require any support files.
Dir[Rails.root.join('spec/support/**/*.rb')].sort.each { |f| require f }
require 'rspec/rails'

# Prevent database truncation if the environment is production
abort("The Rails environment is running in production mode!") if Rails.env.production?

# Add additional requires below this line. Rails is not loaded until this point!
require "capybara/rails"
require "capybara/rspec"

require 'action_view/helpers/number_helper'
require 'action_view/record_identifier'

# Checks for pending migrations and applies them before tests are run.
# If you are not using ActiveRecord, you can remove these lines.
begin
  ActiveRecord::Migration.maintain_test_schema!
rescue ActiveRecord::PendingMigrationError => e
  puts e.to_s.strip
  exit 1
end

RSpec.configure do |config|
  # Reset the database before each test
  config.use_transactional_fixtures = true

  # setup for factory bot
  config.include FactoryBot::Syntax::Methods

  config.before(:suite) do
    Rails.application.load_seed
  end

  config.before(:each) do
    FactoryBot.rewind_sequences
  end

  config.include Rails.application.routes.url_helpers
end

# Capybara configuration
# Capybara.register_driver :chrome do |app|
#   options = Selenium::WebDriver::Chrome::Options.new
#   options.add_argument('--start-maximized')
#   Capybara::Selenium::Driver.new(app, browser: :chrome, options: options)
# end
Capybara.default_driver = :selenium_chrome
Capybara.javascript_driver = :selenium_chrome

My RSpec test file looks like this:

require 'rails_helper'

RSpec.describe "Clients", type: :system do

  # other tests deleted not relevant to question.

  describe "Payee Reference functionality" do
    let!(:payee) { FactoryBot.create(:payee) }

    it "hides payee reference field when self-paying is selected", js:true do
      visit new_client_path

      puts Capybara.default_driver    # -> selenium_chrome
      puts Capybara.javascript_driver # -> selenium_chrome
      puts Capybara.current_driver    # -> selenium_chrome_headless

      # Check that the payee reference field is initially hidden
      expect(page).to have_select('client_paid_by_id', selected: 'Self Paying')
      expect(page).to have_css('div[data-payee-reference-target="referenceField", display:none]', visible: false)
    end
  end
end

So I would have expected current_driver to be selenium_chrome. Interestingly, if I set current_driver to :selenium_chrome in the actual test before the visit command, it does use a standard browser. However, this feels like the wrong approach.


Solution

  • You can achieve this by removing

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

    and add the following to your rails_helper.rb

    
      config.before(:each, type: :system) do |example|
        if example.metadata[:js]
          driven_by :selenium_chrome
        else
          driven_by :selenium_chrome_headless
        end
      end
    

    This will set the driver to :selenium_chrome if js true and :selenium_chrome_headless otherwise.