Capybara in Alpine Linux (Ruby on Rails testing)

March 10, 2018

A project I am on recently switched to a Dockerfile based on ruby:2.5.0-alpine3.7.

Alpine Linux, unfortunately, is missing solid support for most libraries you'd want to use with Capybara. This is because as a build target, Alpine Linux is usually not supported well by some of the drivers Capybara is used with.

My goal was to get some JavaScript-centric tests (implemented under capybara-webkit) working again with RSpec.

Dead-end solutions

Here's a quick overview of what didn't work:

  • capybara-webkit - Relies on an old version of Qt (Qt 5.5). Getting a working binary or compiling from source is probably possible on Alpine Linux, but not without hours of investment. Trying to bring in an older version of Qt by sourcing older Alpine packages introduces dependency hell errors, and was similarly not fruitful.
  • poltergeist - Regarded as the best solution for JavaScript testing in Capybara. Unfortunately, its dependency phantomjs freezes and generally won't work properly on Alpine Linux as documented here.

What worked for me

Using Selenium (selenium-webdriver) with Chromium was the trick.

First, modify your Dockerfile to install the package dependencies:

# Disclaimer: You may not actually need all of these RUN apk --no-cache add \ chromium-chromedriver\ zlib-dev \ chromium \ xvfb \ wait4ports \ xorg-server \ dbus \ ttf-freefont \ mesa-dri-swrast \ udev

Then, edit your test setup file (for me, spec/rails_helper.rb):

Capybara.register_driver :selenium do |app| chrome_options = do |o| o.add_argument '--headless' o.add_argument '--no-sandbox' end, browser: :chrome, options: chrome_options) end Capybara.default_driver = :selenium

The necessity of --no-sandbox

The --no-sandbox option evades this error that would normally stop you:

$ chromium-browser Failed to move to new namespace: PID namespaces supported, Network namespace supported, but failed: errno = Operation not permitted [1583:1583:0330/] Check failed: ReceiveFixedMessage(fds[0], kZygoteBootMessage, sizeof(kZygoteBootMessage), &boot_pid).

Debugging further

If you're still running into errors, here's my general methodology for debugging:

  • Be sure chromedriver -v and chromium-browser -v runs successfully
    • If they don't, google around to hunt down the error reason and find a system reconfiguration (e.g. missing package?) or startup flag/argument that fixes the issue.
    • Once you find the reason and a fix, you can dig into the source code of selenium-webdriver and/or capybara to figure out how to specify the fix inside of those libraries. If it's a command-line flag you think you need, my solution above may be of help to inject additional startup arguments for chromedriver.

Credit to the following project for inspiration: westy92/headless-chrome-alpine

By Daniel Starling

Software consultant in Portland, OR

Contact me

Daniel Starling

Software consultant in Portland, OR

Need help? Contact me!