Search code examples
ruby-on-railsrspeccapybaradatabase-cleaner

Capybara not holding user session after one page visit -- Rails 4.2


I can't get Capybara to hold a session beyond one page visit within one spec. I am familiar with the concept that Capybara's driver might be using a different database connection, but anything I do (including not using :js => true) doesn't seem to change anything.

I am just trying to visit a page that requires user authentication. It succeeds on first visit. It fails when I visit it a second time. (This of course all works when I manually test in development.) Code:

activity_areas_spec.rb

require "rails_helper"

RSpec.feature "Activity areas", :type => :feature do
  
  user = FactoryGirl.create(:user)
  before(:each) do
    login_as(user, :scope => :user)
  end
  after(:each) do
    Warden.test_reset!
  end
  
  ...

  feature "displays activities shared", :js => true do
    scenario "to public" do
      visit area_activities_path
      expect(page).to have_content I18n.t('pages.activity.areas.title') #passes
      visit area_activities_path
      expect(page).to have_content I18n.t('pages.activity.areas.title') #fails -- user is redirected to login page.
    end
  end
end

#rails_helper.rb
    ENV['RAILS_ENV'] ||= 'test'
    require File.expand_path('../../config/environment', __FILE__)
    # Prevent database truncation if the environment is production
    abort("The Rails environment is running in production mode!") if Rails.env.production?
    require 'rspec/rails'
    require 'spec_helper'
    require 'capybara/rails'
    require 'devise'
    require 'support/controller_macros'
    
    include Warden::Test::Helpers
    Warden.test_mode!
    
    ActiveRecord::Migration.maintain_test_schema!
    
    RSpec.configure do |config|
      # Factory girl
      config.include FactoryGirl::Syntax::Methods
      # Make routes available in specs
      config.include Rails.application.routes.url_helpers
      # Capybara
      config.include Capybara::DSL
      # To get Devise test helpers
      config.include Devise::TestHelpers, :type => :controller
      config.extend ControllerMacros::DeviseHelper, :type => :controller
      config.include ControllerMacros::AttributeHelper, :type => :controller
       
      config.use_transactional_fixtures = false
      config.infer_spec_type_from_file_location!
      config.filter_rails_from_backtrace!
      
      # Database cleaner gem configurations
      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

Since I was sensitive to the fact that Capy might be using a different database connection, I have tried following DatabaseCleaner's suggested code to the tee in the place of the above DatabaseCleaner commands:

config.before(:suite) do
    if config.use_transactional_fixtures?
      raise(<<-MSG)
        Delete line `config.use_transactional_fixtures = true` from rails_helper.rb
        (or set it to false) to prevent uncommitted transactions being used in
        JavaScript-dependent specs.

        During testing, the app-under-test that the browser driver connects to
        uses a different database connection to the database connection used by
        the spec. The app's database connection would not be able to access
        uncommitted transaction data setup over the spec's database connection.
      MSG
    end
    DatabaseCleaner.clean_with(:truncation)
  end  

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

  config.before(:each, type: :feature) do
    driver_shares_db_connection_with_specs = Capybara.current_driver == :rack_test

    if !driver_shares_db_connection_with_specs
      DatabaseCleaner.strategy = :truncation
    end
  end

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

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

See here.

#spec_helper.rb
    require 'factory_girl_rails'
    require "capybara/rspec"
    require 'sidekiq/testing'
    RSpec.configure do |config|
      config.expect_with :rspec do |expectations|
        expectations.include_chain_clauses_in_custom_matcher_descriptions = true
      end
        
      config.mock_with :rspec do |mocks|
        mocks.verify_partial_doubles = true
      end
    end

I'm confused easily, so much appreciated for any help that is provided in simple terms. And let me know if you need any other files.


Solution

  • As a quick guess your user = FactoryGirl.create(:user) needs to be inside your before block - otherwise it would only be run once when the feature is loaded - and then removed from the database before the first feature is run