Upgrading capybara from 1.0.1 to 1.1.4 makes database_cleaner break my specs
Asked Answered
C

3

8

I have an old Rails application upgraded to version 3.2.11 that has a lot of request specifications written using capybara version 1.0.1 and running using the selenium driver. The database are cleaned after each test using database_cleaner using the truncation strategy.

I want to use poltergeist instead of selenium and upgraded capybara from 1.0.1 to 1.1.4 to be able to use the latest version of poltergeist. Only changing the capybara gem (and its dependencies) introduced problems running my specs.

I consistently get deadlock errors from my Postgresql database in the cleanup handler after each spec. My spec_helper is pretty basic and looks like this:

RSpec.configure do |config|
  config.mock_with :rspec

  config.use_transactional_fixtures = false

  config.before(:suite) do
    DatabaseCleaner.strategy = :truncation
    DatabaseCleaner.clean_with(:truncation)
  end

  config.before(:each) do
    DatabaseCleaner.start
  end

  config.after(:each) do
    DatabaseCleaner.clean
  end
end

The error I get is like this:

An error occurred in an after hook
  ActiveRecord::StatementInvalid: PG::Error: ERROR:  deadlock detected
DETAIL:  Process 41747 waits for AccessExclusiveLock on relation 17612 of database 16396; blocked by process 41752.
Process 41752 waits for RowExclusiveLock on relation 17529 of database 16396; blocked by process 41747.
HINT:  See server log for query details.
: ALTER TABLE "aaa" ENABLE TRIGGER ALL;ALTER TABLE "bbbb" ENABLE TRIGGER ALL;ALTER TABLE "ccc" ENABLE TRIGGER ALL;
  occurred at /xxx/.bundle/gems/activerecord-3.2.11/lib/active_record/connection_adapters/postgresql_adapter.rb:652:in `async_exec'

I use FactoryGirl to create test data but otherwise nothing special IMO.

I haven't been able to figure out what holds the other end of deadlock that is created by database_cleaner. Any ideas to figure that out are most welcome.

Anybody know of any changes between capybara 1.0.1 and 1.1.4 that has changed and may have started to cause these issues?

Chaw answered 10/1, 2013 at 19:43 Comment(5)
I actually experienced the opposite. I had deadlocks occurring intermittently in my tests until upgrading to capybara 1.1.4 from 1.1.2. Sorry my comment isn't more helpful. =/Bowse
Well I am glad that I am not the only one experiencing deadlock issues :-) I simply fail to see why two threads at a time is accessing the tables at the same time. DatabaseClean should only work after the actual tests are complete...Chaw
Oh also, this might be a stupid question, but have you tried updating your DatabaseCleaner gem? Also, FWIW I think for us the errors only started occurring only after we started using delayed_job (even though we turned it off for the tests).Bowse
I have tried updating DatabaseCleaner as well as a lot of other used gems - so far without success. I do use DelayedJob but have also tried to remove all uses of it so it can't be source of my problem.Chaw
=( damn. well, just in case you're interested, here's the commit that fixed our issues: github.com/enspiral/loomio/commit/…. And here are the before and after test suite results: travis-ci.org/enspiral/loomio/builds/4088113 and travis-ci.org/enspiral/loomio/builds/4103871. And this is our delayed_job initializer: github.com/enspiral/loomio/blob/master/config/initializers/…Bowse
N
5

I got around this issue in cucumber by placing

sleep 0.2

at the end of the step (or in your case "spec") that does some AJAX stuff. I imagine what happens is that cucumber/rspec calls database cleaner while the JS driver is still waiting for the ajax response.

Narwhal answered 25/2, 2013 at 16:28 Comment(4)
Worked for me. Seems strange there aren't more people that are encountering this.Hogan
Worked for me, too. Is there any real solution in sight?Drinking
This works but slows the test down unnecessarily and may sometimes fail. The fix is to put in a call to the Capybara API (like has_content?) at the end of the test. I've elaborated in the answer below.Truehearted
Sleeping during the specs slows things down and isn't necessarily a consistent fix. Sometimes things will still take more than 0.2 seconds to resolve and will fail the test.Finegan
T
5

The fix isn't to use sleep but to only use Capybara API methods as they wait for what's expected.

Below, line 2 fails (as current_path is non-waiting, but line 3 works (as has_selector? waits). The link to Jonas Nicklas' article below explains it well.

click_on 'signup_button'  # Which does an AJAX redirect to /dashboard
assert_equal dashboard_path, current_path  # This causes the deadlock error as Capybara doesn't wait.
assert page.has_selector?("#dashboard")  # This works as it causes Capybara to wait for the new page.

http://www.elabs.se/blog/53-why-wait_until-was-removed-from-capybara

Truehearted answered 5/6, 2013 at 22:10 Comment(1)
I’m quite sure this only works in Capybara 2. Have you tried it in Capybara < 2?Narwhal
F
1

The solution we use is to find something in the page that should change in response to a successful ajax call. So something like:

click_on('Save')
expect(page).to have_content('Saved')
Finegan answered 28/5, 2014 at 21:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.