Transient Test Failures in Rails

Capybara, threading, and database transactions

Posted on June 24, 2016

Update: As of Rails 5.1, this monkey patch is no longer necessary. The test threads now share a database connection by default.


After adding JavaScript tests, I began to notice transient test failures. A lot of advice floating around the internet recommends solving this issue using Database Cleaner, but it's misguided. Rails has transactional fixtures already built in, rendering Database Cleaner completely unnecessary. Even worse, it doesn't solve the underlying problem!

By default, each test is wrapped in a database transaction. The problem is that the JavaScript tests are spawned in a different thread. The transaction does not work across threads, so tests can hit the database before another test has had a chance to rollback its changes. To fix this, you can force threads to share the same connection by adding the following monkey patch to your test helper.

class ActiveRecord::Base
  mattr_accessor :shared_connection
  @@shared_connection = nil

  def self.connection
    @@shared_connection || retrieve_connection
  end
end
ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection

I originally found this monkey patch in the Capybara README, but it has since been removed. The original source appears to be this blog post.

While this monkey patch fixed my transient test failures, some people have run into some issues. Here is an alternate solution that may help.

Happy testing!