Headless Chrome

Erica Kastner · April 21, 2017

Google Chrome version 59 will ship with the headless option. This means you can test your web applications using chrome without needing a running window manager or xvfb.

There is one problem: the latest chromedriver (version 2.29) does not support versions of Chrome higher than 58.

The solution is to build the latest chromedriver that does support the latest chrome/chromium. Unfortunately, Google does not make nightly builds of chromedriver public. You have to download the chromium source and build chromedriver yourself.

UPDATE: It turns out that chromedriver still relies on XOrg for keycode decoding when handling sendKeys commands from selenium. Thus, you still need xvfb for real testing to work.

How all the pieces work together

In my case, I am running the ruby version of cucumber. Cucumber uses the capybara gem to send commands to selenium-webdriver. Selenium-webdriver in turn starts up your local copy of chromedriver, which then starts up chrome and controls the browser through a special debug port.

This means our system has to have a copy of the latest chromium installed, along with our custom chromedriver build.

To get the latest chromium, I used a tool on github that downloads the latest snapshot compiled for linux.

To get the latest chromedriver, I followed the build instructions but ran it all in a docker container in order to maintain a clean building environment. I then copied the built chromedriver and its shared libraries out of the container.

Once I had the built chrome and chromedriver, I was ready to run selenium/capybara tests against it.

Configuring the tests

When configuring capybara, you need to tell selenium-webdriver the path to your custom chromium binary and send the --headless flag, along with other flags you’ll likely need in a CI build node environment.

For running in docker:

Capybara.register_driver :headless_chromium do |app|
  caps = Selenium::WebDriver::Remote::Capabilities.chrome(
    "chromeOptions" => {
      'binary' => "/chromium-latest-linux/466395/chrome-linux/chrome",
      'args' => %w{headless no-sandbox disable-gpu}
    }
  )
  driver = Capybara::Selenium::Driver.new(
    app,
    browser: :chrome,
    desired_capabilities: caps
  )
end

Capybara.default_driver = :headless_chromium

Now, capybara will drive a headless chromium!

I’ve created a repo that lets you test this all out.