RSpec Rails, Selenium, and Heroku's New Chrome Testing Buildpack

September 9, 2024
Pete Nicholls
I lost an hour or two to this issue today, so I hope this helps someone else out.

Heroku’s New chrome-for-testing Buildpack

Earlier this year, Heroku shipped a new buildpack for improved browser testing on Heroku with Chrome called heroku/chrome-for-testing. This buildpack fixes some longstanding headaches with the previous approach, which involved adding two different buildpacks (heroku/google-chrome and heroku/chromedriver).

Selenium::WebDriver Error

While setting up a new Rails 7 app, I wanted to get end-to-end testing running in Heroku CI by writing system specs in RSpec Rails. I added the following gems in my Gemfile:

group :development, :test do  # For testing  gem "rspec-rails", "~> 7.0.0"  # For end-to-end system specs  gem "capybara"  gem "selenium-webdriver"end

When I wrote my system specs, they just worked without any extra configuration. When I pushed them to run in Heroku CI, I got the following error:

Selenium::WebDriver::Error::SessionNotCreatedError:  session not created: Chrome failed to start: exited normally.    (session not created: DevToolsActivePort file doesn't exist)

Solution

Sleuthing around the buildpack, I found a related issue. The comments hinted at needing to tweak the options passed to the driver.

My solution was to add a support file (spec/support/selenium.rb) with the following:

Capybara.register_driver :heroku_ci_chrome do |app|  options = Selenium::WebDriver::Chrome::Options.new  options.add_argument('--headless')  options.add_argument('--no-sandbox')  Capybara::Selenium::Driver.new(app, browser: :chrome, options: options)endRSpec.configure do |config|  config.before(:each, type: :system) do    driver = ENV['CI'] ? :heroku_ci_chrome : :selenium_chrome    driven_by(driver)  endend

This solution causes each :system spec to run with Selenium. If you would like only certain system specs to run with a browser, such as those tagged with :js, modify the before action like this: config.before(:each, type: :system, js: true). (I expect the same approach will work for :feature specs as well, although I haven’t tried this.)

While running tests locally, this will pop open a Chrome window, but you can change :selenium_chrome to :selenium_chrome_headless if you would like the browser to stay hidden (“headless”).

In Heroku CI, the CI environment variable is automatically set for you by Heroku, and it will use the standard Selenium Chrome driver with the --headless and --no-sandbox options. These were all I needed – no GOOGLE_CHROME_SHIM or --disable-dev-shm-usage like the previous buildpacks required.

One gotcha I fell for here is that there are Selenium defaults that Rails sets for out-of-box Rails testing that are not picked up by RSpec Rails. Rails' ApplicationSystemTestCase registers some drivers that might not be available in RSpec Rails. You can use the register_driver technique above to customise your own.

Resources

Let’s talk

Contact Us

Stories & insights

read the blog