Using Puma and Capybara for integration testing

When running integration tests in Rails using Capybara and Capybara Webkit engine, its always easy to forget that the application server used to run your tests is not the same as the one you would normally use in production or even development environments.

Rails has a very simple set of defaults when it comes to the tech stack. So, lets say you just started a new app and need to fire up the development server. With just rails server you'll get Webrick running on localhost:3000. Awesome, but the problem is that webrick is not a good choice for production use, so most people these days either use Puma or Unicorn, which are very similar in design and build for concurrency.

I personally prefer Puma and use it in development/production environments in tandem with Foreman. Using the same app server stack in every step of development pipeline makes it easy to spot bugs, so why not use it for integration tests?

Here's how its done. First, make sure that you have somewhat recent version of Puma bundled into application, and edit your rails_helper.rb file:

# Bunch of default rails requires 
require "spec_helper"
require File.expand_path("../../config/environment", __FILE__)
require "rspec/rails"

# Load capybara api
require "capybara/rspec"
require "capybara/rails"
require "capybara/webkit"

# Pretty much defaults
Capybara.default_driver = :webkit
Capybara.javascript_driver = :webkit

# Here's the meat part, we'll register our own server handler.
require "puma"
Capybara.register_server("puma") do |app, port|
  server = Puma::Server.new(app)
  server.add_tcp_listener(Capybara.server_host, port)
  server.run
end

If you're running spring or any other preloader, there's a big chance that you'll have to restart it. Capybara server handlers are pluggable and you can always switch runner to another server of your choice.