Skip to content

Instantly share code, notes, and snippets.

@josevalim
Created July 10, 2010 16:10
Star You must be signed in to star a gist
Save josevalim/470808 to your computer and use it in GitHub Desktop.
# In your test_helper.rb
class ActiveRecord::Base
mattr_accessor :shared_connection
@@shared_connection = nil
def self.connection
@@shared_connection || retrieve_connection
end
end
# Forces all threads to share the same connection. This works on
# Capybara because it starts the web server in a thread.
ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
@snoblenet
Copy link

Hi there,

Currently the following code, in Sidekiq worker, works in development:

url = "http://localhost:3000/downloads/#{download.unique_id}" if Rails.env.development?

However, the following code in the same Sidekiq worker does not work in test:

url = "http://localhost:4000/downloads/#{download.unique_id}" if Rails.env.test?

I get a connection refused error.

Capybara is configured as default_port = 4000 and run_server = true.

Do you think I could fix this with a variant of the code you've posted here?

@grillermo
Copy link

I gave up, and i'm using truncation in all my tests and the problem es gone.

@kuroda
Copy link

kuroda commented Mar 4, 2016

The solution using Mutex (thanks to @mikecmpbll) and wait_for_ajax (thanks to @divineforest) works well for me.

Here is another tip from me.

In some occation, the undefined method 'fields' error can occur even if you call wait_for_ajax after triggering an Ajax call.

In fact, we have to wait for all database accesses are completed, not just for ajax.

Suppose that you have following scenario among others:

scenario 'Update account' do
  visit edit_account_path
  fill_in 'account_name', with: 'foo'
  find('#update-account').click # Triggers an Ajax call
  wait_for_ajax
  user.reload
  expect(user.name).to eq('foo')
end

If any database access occurs after this scenario ends, we will get the undefined method 'fields' error on the next scenario.

To prevent this problem, we have to write another expectation that is fulfilled only after all database accesses are completed.

For example, if we know that a text appears on the browser screen at the end of scenario, we can write like this:

scenario 'Update account' do
  visit edit_account_path
  fill_in 'account_name', with: 'foo'
  find('#update-account').click # Triggers an Ajax call
  expect(page).to have_text('The account is updated.')
  user.reload
  expect(user.name).to eq('foo')
end

@jwg2s
Copy link

jwg2s commented Jul 18, 2016

@kuroda - have you found a more systematic way to fix this issue? We're experiencing the same thing, and rather than run around fixing a bunch of tests, ideally there's a lower level way to address the problem.

@lakim
Copy link

lakim commented Sep 9, 2016

We should work on a reliable solution for everyone.

The best take I've seen so far is @iangreenleaf's article and gem:
http://technotes.iangreenleaf.com/posts/the-one-true-guide-to-database-transactions-with-capybara.html
https://github.com/iangreenleaf/transactional_capybara

It bundles the shared connection monkey patch and the wait_for_ajax helper.
Version 0.1.0 has just been released with support for Capybara >= 2.6.0.

It doesn't use connection_pool nor a Mutex.
I haven't had the need for it so far, but it's just a PR away.

@chrise86
Copy link

Sorry to dig up an old thread (no pun intended), but I've been facing this issue on a Rails 5 app recently, and @mperham's solution worked great for me!

@gogocurtis
Copy link

lol yeah this thread is filled with golden lessons in concurrency.

@gnclmorais
Copy link

It’s 2019, do we still need this in Rails 5.2?

@nflorentin
Copy link

@gnclmorais, it seems that this is not useful anymore: https://github.com/teamcapybara/capybara#transactions-and-database-setup if you are running Rails 5.1 +.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment