RSpec Rails, Selenium, and Heroku's New Chrome Testing Buildpack
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
- Heroku Buildpack: Chrome for Testing
- RSpec Rails system specs
- Selenium::WebDriver::Error::SessionNotCreatedErr GitHub issue
- Capybara: Configuring and adding drivers