DEV Community

Adam Rogers
Adam Rogers

Posted on

Rails System Tests with Headless Chrome on Heroku CI

Sometimes your Rails apps just need to execute JavaScript in a real browser. But you also want to run tests on CI, which typically doesn't have a UI. So you need to configure Google Chrome to run headless, i.e. without popping up a browser window (but still exercising your app as if it were).

Urgh.

Having just worked through this now, here's what worked for us.

Prerequisites

Install chromedriver.

Configure test environment

In your app.json, add the chromedriver and google-chrome buildpacks, as well as the usual ruby one. Our app.json ended up looking like this:

{
  "environments": {
    "test": {
     "buildpacks": [
        { "url": "https://github.com/heroku/heroku-buildpack-ruby" },
        { "url": "https://github.com/heroku/heroku-buildpack-chromedriver" },
        { "url": "https://github.com/heroku/heroku-buildpack-google-chrome" }
      ],
      "addons": [
        "heroku-postgresql"
      ],
      "scripts": {
        "test-setup": "bin/rails assets:precompile",
        "test": "bin/rspec"
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Also, set any environment variables you might need in your test env via the Heroku UI. You can set non-sensitive stuff in app.json if you want, though.

Configure Capybara with a headless driver

# spec/rails_helper.rb

chrome_bin = ENV.fetch('GOOGLE_CHROME_SHIM', nil)

chrome_opts = chrome_bin ? { "chromeOptions" => { "binary" => chrome_bin } } : {}

opts = Selenium::WebDriver::Chrome::Options.new

chrome_args = %w[--headless --no-sandbox --disable-gpu]
chrome_args.each { |arg| opts.add_argument(arg)  }

Capybara.register_driver :headless do |app|
  Capybara::Selenium::Driver.new(
     app,
     browser: :chrome,
     options: opts,
     desired_capabilities: Selenium::WebDriver::Remote::Capabilities.chrome(chrome_opts)
  )
end

Capybara.javascript_driver = :headless
Enter fullscreen mode Exit fullscreen mode

...and that's about it.

The bit that we found we had to do that was different from other posts of this nature we found was setting Selenium::WebDriver::Chrome::Options.new. Without this, everything we tried to tell Chrome to be headless was ignored.

If you're reading this, I hope it helps!

References

Top comments (0)