GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS

Written by thoughtbot

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.