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 dependencyphantomjs
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 = Selenium::WebDriver::Chrome::Options.new.tap do |o|
o.add_argument '--headless'
o.add_argument '--no-sandbox'
end
Capybara::Selenium::Driver.new(app, 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/111647.538009:FATAL:zygote_host_impl_linux.cc(182)] 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
andchromium-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/orcapybara
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 forchromedriver
.
Credit to the following project for inspiration: westy92/headless-chrome-alpine