I'm trying to write integration tests with rspec, factory_girl & capybara. I also have cucumber installed, but I'm not using it (to my knowledge).
I basically want to prepopulate the db with my user, then go to my home page and try to log in. It should redirect to user_path(@user).
However, sessions don't seem to be persisted in my /rspec/requests/ integration tests.
My spec: /rspec/requests/users_spec.rb
require 'spec_helper'
describe "User flow" do
  before(:each) do
    @user = Factory(:user)
  end
  it "should login user" do
    visit("/index")
    fill_in :email, :with => @user.email
    fill_in :password, :with => @user.password
    click_button "Login"
    assert current_path == user_path(@user)
  end
end
Returns:
Failures:
  1) User flow should login user
     Failure/Error: assert current_path == user_path(@user)
     <false> is not true.
     # (eval):2:in `send'
     # (eval):2:in `assert'
     # ./spec/requests/users_spec.rb:16
Instead, it redirects to my please_login_path - which should happen if the login fails for any reason (or if session[:user_id] is not set).
If I try to put session.inspect, it fails as a nil object.
If I try to do this in the controller tests (/rspec/controllers/sessions_spec.rb), I can access the session with no problem, and I can call session[:user_id]
If you are using Devise, you'll need to include Warden::Test::Helpers (right after the require of spec_helper is a good place) as outlined in the warden wiki.
The call to session is returning nil because capybara doesn't provide access to it when running as an integration test.
I have the same problems and although filling out a form might be an option for some, I had to roll my own authentication ruby because I was using a third party auth system (Janrain to be exact).... in my tests I ended up using something like this:
Here is what I have in my spec/support/test_helpers_and_stuff.rb
module AuthTestHelper
  class SessionBackdoorController < ::ApplicationController
    def create
      sign_in User.find(params[:user_id])
      head :ok
    end
  end
  begin
    _routes = Rails.application.routes
    _routes.disable_clear_and_finalize = true
    _routes.clear!
    Rails.application.routes_reloader.paths.each{ |path| load(path) }
    _routes.draw do
      # here you can add any route you want
      match "/test_login_backdoor", to: "session_backdoor#create"
    end
    ActiveSupport.on_load(:action_controller) { _routes.finalize! }
  ensure
    _routes.disable_clear_and_finalize = false
  end
  def request_signin_as(user)
    visit "/test_login_backdoor?user_id=#{user.id}"
  end
  def signin_as(user)
    session[:session_user] = user.id
  end
end
Then in my request spec, with capybara and selenium, I did the following:
describe "Giveaway Promotion" do
  context "Story: A fan participates in a giveaway", js: :selenium do
    context "as a signed in user" do
      before :each do
        @user = Factory(:user)
        request_signin_as @user
      end
      it "should be able to participate as an already signed in user" do
        visit giveaway_path
        ....
      end
    end
  end
end
BTW, I came up with solutions after trying the proposed solutions to this post and this post and neither of them worked for me. (but they certainly inspired my solution)
Good luck!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With