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