giant robots smashing into other giant robots

Written by thoughtbot

jyurek

capybara-webkit doesn’t like #fork

Recently, when helping to convert a feature suite to use capybara-webkit, we ran into a problem where, about halfway through, the tests would start erroring out with Errno::EPIPE.

Errno::EPIPE is a “Broken Pipe” error. A pipe in Unix is a way for data to flow from one process to another, and a broken pipe means that one end of the pipe isn’t connected anymore. In this case, the pipe was broken because the webkit-server process that capybara-webkit uses went away. And since well-behaved processes don’t normally go away unless you ask them to, we assumed it was crashing.

With a little of digging, we found the feature that was causing the problem. Annoyingly, the error never popped up when the feature was run alone, meaning it was the interaction of multiple features or steps. After whittling away the options, we found the right situation to force the error: a feature using capybara-webkit followed by one specific scenario in a different feature (which, oddly, didn’t use any Javascript at all). Being able to reliably reproduce the error is a big step towards finding a solution.

Knowing what scenario we were dealing with, we could find the specific step that was the source of the problem. The step makes a call to fork. The way that capybara-webkit closes the browser when the tests are over is by using an at_exit hook, which is called when Ruby is just about to close. Forking a process clones everything about it, including, in the case of Ruby, its at_exit hooks. So, what happened was that the fork executed what it needed to execute and then exited like normal, but it meant that it took the webkit-server process with it because of the at_exit hooks it inherited, leaving no browser to run the javascript-enabled features.

This was good news, though. The webkit-server process wasn’t crashing! It was behaving exactly like it was expected to, but just a little premature. To get around the at_exit hooks, we call exit! in the forked process, which specifically bypasses at_exit hooks. This lets our fork get on with its work, and it keeps the server running for the rest of the test suite to use.

So, if you’re in the position where you have to fork in a cucumber suite and you’re using capybara-webkit, make sure you exit! from the fork, and you’ll save yourself some headaches. If you can help fix this problem for good, pull requests are welcome.

Modern applications use Javascript. You can make rich user interfaces that are faster and more responsive.

Since we all do TDD, we need to test our Javascript. There are plenty of approaches. It used to be a pain, but there’s no excuse any more.

If you’re using Capybara to go through the UI of a modern web application, perhaps with Cucumber, there’s going to be Javascript in that UI and you need to run it.

The default driver for Capybara is Rack::Test, which is pretty simple. It can follow redirects and do 90% of what you need but the remaining 10% is the shiny part, the Javascript part.

As an example, say you have a form that uses Javascript to auto-fill an “account name” field based on what you fill in for the “email address” field. If you used Capybara with just Rack::Test, the integration test won’t pass.

Selenium runs your test in a real browser. Someone took the time to write software that starts up Firefox, which is hard enough as a user, installs an extension so you can remote control it, and exposes a JSON REST API so you can communicate with it from your tests. It works with Capybara. All of that’s awesome.

However, it’s slow. There’s also no real API for assessing what went wrong.

So, thoughtbot made Capybara Webkit.

Capybara Webkit is fast. It uses the Webkit engine, not a real browser UI. You can do console.log output. You can see errors in standard output.

It’s mostly easy to install.

Gemfile:

gem "capybara-webkit"

features/support/env.rb:

Capybara.javascript_driver = :webkit

However, you also have to install Qt. Instructions for OS X and Linux are in the README. If you’re on Windows, God help you.

Capybara Webkit is still young, however.

All the tests are asynchronous so you still need Capybara’s retrying methods.

It’s much younger than Selenium so there are some bugs that they’ve worked out that we haven’t. The issues queue is very active.

Capybara Webkit is built around a cool library called QtWebkit, which is a headless browser acting as a server that listens for commands using a lightweight socket layer. So when you boot up your test suite, that server also starts in a background process. Our Ruby driver implements the Capybara API and communicates with that server.

Webkit is open source, powers Safari, Chrome, and other browsers. It’s fast and standards-compliant.

It’s not a browser itself, and calling it a browser engine is even a stretch. It’s really a set of libraries for building a browser. It’s not packaged as a standalone library.

There is no ‘WebKit’ as a single library. We use QtWebKit because it’s the most complete at filling in the blanks to make a unified browser library.

Qt is a C++ library and a bunch of tools to make C++ development suck less.

QtWebkit appears like it was written so that Nokia could build a mobile Webkit browser. It has lots of injection points and hooks, a nice API, and is well documented. Webkit itself is not documented so this was a big win. Instead of building a browser with it, we used it to build a test harness.

Written by .