How do I simulate a login with RSpec? How do I simulate a login with RSpec? ruby-on-rails ruby-on-rails

How do I simulate a login with RSpec?


The answer depends on your authentication implementation. Normally, when a user logs in, you'll set a session variable to remember that user, something like session[:user_id]. Your controllers will check for a login in a before_filter and redirect if no such session variable exists. I assume you're already doing something like this.

To get this working in your tests, you have to manually insert the user information into the session. Here's part of what we use at work:

# spec/support/spec_test_helper.rbmodule SpecTestHelper     def login_admin    login(:admin)  end  def login(user)    user = User.where(:login => user.to_s).first if user.is_a?(Symbol)    request.session[:user] = user.id  end  def current_user    User.find(request.session[:user])  endend# spec/spec_helper.rbRSpec.configure do |config|  config.include SpecTestHelper, :type => :controllerend

Now in any of our controller examples, we can call login(some_user) to simulate logging in as that user.


I should also mention that it looks like you're doing integration testing in this controller test. As a rule, your controller tests should only be simulating requests to individual controller actions, like:

it 'should be successful' do  get :index  response.should be_successend

This specifically tests a single controller action, which is what you want in a set of controller tests. Then you can use Capybara/Cucumber for end-to-end integration testing of forms, views, and controllers.


Add helper file in spec/support/controller_helpers.rb and copy content below

module ControllerHelpers    def sign_in(user)      if user.nil?        allow(request.env['warden']).to receive(:authenticate!).and_throw(:warden, {:scope => :user})        allow(controller).to receive(:current_user).and_return(nil)      else        allow(request.env['warden']).to receive(:authenticate!).and_return(user)        allow(controller).to receive(:current_user).and_return(user)      end    end  end

Now add following lines in spec/rails_helper.rb or spec/spec_helper.rb file

require 'support/controller_helpers'RSpec.configure do |config|    config.include Devise::TestHelpers, :type => :controller    config.include ControllerHelpers, :type => :controller  end

Now in your controller spec file.

describe  "GET #index" do    before :each do                @user=create(:user)        sign_in @user    end      ...end

Devise Official Link


As I couldn't make @Brandan's answer work, but based on it and on this post, I've came to this solution:

# spec/support/rails_helper.rbDir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f } # Add this at top of file...include ControllerMacros # Add at bottom of file

And

# spec/support/controller_macros.rbmodule ControllerMacros  def login_as_admin    admin = FactoryGirl.create(:user_admin)    login_as(admin)  end  def login_as(user)    request.session[:user_id] = user.id  endend

Then on your tests you can use:

it "works" do  login_as(FactoryGirl.create(:user))  expect(request.session[:user_id]).not_to be_nilend