1

I have a feature/integration spec that runs through an entire user flow. By the end of that user flow, a page in the app will display a few records from my Postgres database. When I run the test by itself, it passes. I can see it saving correctly through the various steps since the selenium driver opens up firefox: Capybara.current_driver = :selenium. However, this spec fails regularly, almost predictably, when it is run after a bunch of controller specs. In those controller specs the only interesting thing that I am doing is running this login function:

module DeviseMacros
  def login_user
    before(:each) do
      @request.env['devise.mapping'] = Devise.mappings[:user]
      user = create(:user_with_active_account)
      sign_in user
    end
  end
end

So I call it like this:

describe AwesomeController do
  login_user

  it 'responds with 200' do
    get :new
    expect(response.status).to eq 200
  end
end

When run after a controller spec I can immediately see that the test will fail since certain UI elements should appear depending on what's in the DB and clearly they are not present.

My DatabaseCleaner strategy is as follows:

RSpec.configure do |config|
  config.before(:suite) do
    DatabaseCleaner.clean_with(:truncation)
  end

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

  config.before(:each, js: true) do
    DatabaseCleaner.strategy = :truncation
  end

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

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

Through trial and error I changed

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

to

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

And walla, it passes. Of course now the test suite takes over 2x as long.

I have tagged all my :selenium tests with js: true in order to ensure :truncation is used for them but that really doesn't matter since :selenium is already driving those. However, most importantly, this feature spec still fails after those controller specs.

Where else should I be looking? How do I proceed with debugging?

The only other unique thing I have in here that may be related is:

# In spec/support/shared_db_connection.rb
# https://gist.github.com/josevalim/470808
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

Any advice or ideas on how to proceed with debugging would be greatly appreciated.

If you have any additional questions please ask. Thank you

Update: June 1, 2016

The exact line of code that causes the failure is:

module DeviseMacros
  def login_user
    before(:each) do
      @request.env['devise.mapping'] = Devise.mappings[:user]
      user = create(:user_with_active_account)
      sign_in user # <----- THIS GUY RIGHT HERE! When removed, the ControllerSpec fails but the integration test passes.
    end
  end
end

So for some reason it appears that hitting the DB with this controller spec (which uses :transaction strategy) effects the feature spec (which uses :truncation strategy).

I'm debating just not hitting the DB at all in the controller specs when trying to authenticate a devise user, which is cool with me, but I feel like it shouldn't have to be that way. Any ideas on how to proceed if I do indeed want to be able to use the sign_in method?

Thank you

Loading...
  • 863
  • 9
  • 21
  • BTW, what happens when you use the `transaction` strategy everywhere? Because I think this is what the ActiveRecord patch is about, isn't it? – Matouš Borák Jun 01 '16 at 08:05
  • @BoraMa Thanks for the suggestions. When `:transaction` is used everywhere I get way more errors that appear to be related to the DB. I updated with more info about the line of code that causes the issue above. Any ideas? – Loading... Jun 02 '16 at 03:18
  • OK, I would also vote for dumping this AR patch and try to resolve the issue without it. Can you post your `sign_in` method? BTW, I vaguely remember we had similar issues in the past with our tests. We ended up splitting the tests to two test suites: all non JS and all JS, and we run the two test suits separately without any further issues. – Matouš Borák Jun 02 '16 at 08:49

1 Answers1

0

Remove the shared connection hack, since it causes more issues than it's worth, and update your Database Cleaner config to the recommended one from the database cleaner README - https://github.com/DatabaseCleaner/database_cleaner#rspec-with-capybara-example

Thomas Walpole
  • 48,548
  • 5
  • 64
  • 78
  • I removed the shared_connection code and updated the database_cleaner rules to be exactly as in your link. The error still occurs. I did however discover the exact line of code that causes the error and updated my question above. Does that give you any more ideas? – Loading... Jun 02 '16 at 03:20
  • The solution required going over all the feature specs and explicitly tagging them with a tag (:js) in order to ensure that they ALL use `transaction`. Turns out those error were coming randomly from all the feature specs. Had to just bite the bullet and go with slower feature specs. – Loading... Jul 08 '16 at 20:11