database_cleaner: truncation in capybara tests results in rspec freezing (while deletion works)

I found out that this code (necessary to truncate in case we are testing with capybara) makes RSpec freeze right after running capybara tests, while the same code with :deletion strategy works smoothly.

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

    config.around(:each) do |example|
      if example.metadata[:type] == :feature
        example.run
        DatabaseCleaner.clean_with :truncation #ONLY DELETION WORKS!
      else 
        DatabaseCleaner.start
        example.run
        DatabaseCleaner.clean
      end
    end

As a matter of fact, the following code works for truncation, which makes me think that DatabaseCleaner.start must be run for truncation as well.

    config.before(:each) do
      DatabaseCleaner.strategy = :transaction
    end
    config.before(:each, :type => :feature) do
      DatabaseCleaner.strategy = :truncation
    end
    config.before(:each) do
      DatabaseCleaner.start #runs for both strategies
    end

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

I don’t know whether this is a bug or a some kinds of choice due to some reasons, however I felt it was worth pointing it out.

About this issue

  • Original URL
  • State: closed
  • Created 10 years ago
  • Comments: 25 (7 by maintainers)

Commits related to this issue

Most upvoted comments

Not sure if this is helpful but we (@vormwald) had a weird hanging issue as well.

Changing…

config.around(:each) do |example|
  DatabaseCleaner.strategy = example.metadata[:js] ? :deletion : :transaction
  DatabaseCleaner.cleaning do
    example.run
  end
end

…to…

config.before(:each) do |example|
  DatabaseCleaner.strategy = example.metadata[:js] ? :deletion : :transaction
  DatabaseCleaner.start
end
config.after(:each) do
  DatabaseCleaner.clean
end

…fixed our issue.

At least for me, this was a deadlock between DatabaseCleaner truncating tables and RSpec starting a transaction for the test. Not sure of the RSpec conventions here, but adding this to spec_helper.rb fixed it for me:

RSpec.configure do |config|
   config.use_transactional_fixtures = false
end

I’m using Postgres. Not sure that matters. In any case, the idea is to not mix DatabseCleaner truncation or deletion with RSpec transactions.

This thread helped me to find a fix for my problem, so I’ll just post the fix here in case it’s helpful for anyone:

config.around(:each) do |example|
    DatabaseCleaner.strategy = example.metadata[:js] ? :truncation : :transaction
    DatabaseCleaner.cleaning do
      example.run
    end
  end

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

I’m not sure why the extra DatabaseCleaner.clean was necessary, but the dead lock issue came back without it. I’m also not sure why it was necessary to run the spec inside the DatabaseCleaner.cleaning block; using just DatabaseCleaner.start and DatabaseCleaner.clean didn’t work.

Just a bit more background on the issue I encounter since the above might not solve all the issues expressed on this thread:

Some feature specs were either taking too long or not exiting correctly, so it left a lock on the database, which caused all subsequent database-dependent specs to run extremely slow and then fail with this error:

Failure/Error: Unable to find matching line from backtrace
ActiveRecord::StatementInvalid:
  Mysql2::Error: Lock wait timeout exceeded; try restarting transaction: DELETE FROM `table_name`