DEV Community

Cover image for Headless Chrome - Dual mode tests for Ruby on Rails

Posted on • Updated on • Originally published at

Headless Chrome - Dual mode tests for Ruby on Rails

Headless tests are necessary for CI environments and very useful for unobtrusive local development. No need to ditch the driver that directly controls the browser though, there's lots of debugging value in being able to switch between both modes.

You'll first need both drivers installed and configured, which will give you headless tests by default. Running your tests with a HEADLESS=0 environment variable will give you visual feedback from the test suite as it executes.

This visual mode used in combination with breakpoints has proved to be an excellent addition to my toolbelt when debugging. I've tested this to work on Rails 5.2.x & 6.0.0


I'm an RSpec type of guy, these are my Gemfile dependencies (don't forget to bundle install).

group :development, :test do


  gem 'rspec-rails', '~> 3.8'
  gem 'capybara', '~> 3.16'
  gem 'selenium-webdriver', '~> 3.141'
Enter fullscreen mode Exit fullscreen mode

Download chromedriver from here, make it executable, and send it somewhere cozy. For example on macOS after the executable is downloaded & unzipped:

$ cd ~/Downloads
$ chmod +x chromedriver
$ mv chromedriver /usr/local/bin/
Enter fullscreen mode Exit fullscreen mode

Capybara setup

Uncomment or add the following line on spec/rails_helper.rb

# spec/rails_helper.rb
Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f }
Enter fullscreen mode Exit fullscreen mode

Now the key config for this to work will live in spec/support/capybara.rb and will look something similar to:

# spec/support/capybara.rb
RSpec.configure do |config|
  config.include FactoryBot::Syntax::Methods
  config.include Capybara::DSL

  Capybara.server = :puma, { Silent: true }

  # Chrome non-headless driver
  Capybara.register_driver :chrome do |app|, browser: :chrome)

  # Chrome headless driver
  Capybara.register_driver :headless_chrome do |app|
    caps = { browser: 'ALL' })
    opts =

    chrome_args = %w[--headless --no-sandbox --disable-gpu --window-size=1920,1080 --remote-debugging-port=9222]
    chrome_args.each { |arg| opts.add_argument(arg) }, browser: :chrome, options: opts, desired_capabilities: caps)

  # Switch between :chrome / :headless_chrome to see tests run in chrome
  case ENV['HEADLESS']
  when 'true', 1, nil
    Capybara.javascript_driver = :headless_chrome
    Capybara.javascript_driver = :chrome
Enter fullscreen mode Exit fullscreen mode

As you can see two Selenium Drivers were configured (:chrome & :headless_chrome). But only one of the Drivers is used at a time, based on the HEADLESS environment variable.


The default behavior is Headless. The usual clean, quick, and simple.

$ bundle exec rspec
Enter fullscreen mode Exit fullscreen mode

Add the environment variable and a Chrome window will be summoned and controlled remotely.

$ HEADLESS=0 bundle exec rspec
Enter fullscreen mode Exit fullscreen mode

Like I said, debugging is the main motivation for this configuration. Breakpoints when tests aren't passing because an element is not visible is one the best examples I can think of. Being able to inspect on a Chrome window directly has saved me lots of time.

Hope it helps anyone, Pura Vida!

This post was originally published on

Top comments (0)