Skip to content

How To: sign in and out a user in Request type specs (specs tagged with type: :request)

Pedro Schlickmann Mendes edited this page May 30, 2023 · 10 revisions

There are two approaches by which you can do this: (i) A Simple Approach and (ii) A More Complicated approach:

(1) Simple Approach

spec/rails_helper.rb

RSpec.configure do |config|
  # ...
  config.include Devise::Test::IntegrationHelpers, type: :request
end

And just use sign_in in your request spec. This is the equivalent of declaring include Devise::Test::IntegrationHelpers in an system/feature spec or Rails system/controller test.

A quick and dirty sessions test:

#./spec/requests/sessions_spec.rb
require 'rails_helper'
RSpec.describe "Sessions" do
  it "signs user in and out" do
    # user = create(:user)    ## uncomment if using FactoryBot
    # user = User.create(email: 'test@test.com', password: "password", password_confirmation: "password") ## uncomment if not using FactoryBot
    sign_in user
    get root_path
    expect(response).to render_template(:index) # add gem 'rails-controller-testing' to your Gemfile first.
    
    sign_out user
    get root_path
    expect(response).not_to render_template(:index) # add gem 'rails-controller-testing' to your Gemfile first.
  end
end

ps: in case you have the confirmable module enabled, you will need to call user.confirm before sign_in user.

And you're off to the races!

(2) A more complicated example:

Tested example code with the following environment:

rails 4.2.5.1
ruby-2.2.3p173
devise      3.5.4
rspec-core  3.4.2
rspec-rails 3.4.1

spec/support/request_spec_helper.rb

module RequestSpecHelper

  include Warden::Test::Helpers

  def self.included(base)
    base.before(:each) { Warden.test_mode! }
    base.after(:each) { Warden.test_reset! }
  end

  def sign_in(resource)
    login_as(resource, scope: warden_scope(resource))
  end

  def sign_out(resource)
    logout(warden_scope(resource))
  end

  private

  def warden_scope(resource)
    resource.class.name.underscore.to_sym
  end

end

spec/rails_helper.rb

Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }

RSpec.configure do |config|
  # ...
  config.include RequestSpecHelper, type: :request
  # ...
end

config/routes.rb

Rails.application.routes.draw do

  devise_for :users

  authenticated do
    root to: "secret#index", as: :authenticated_root
  end

  root to: "home#index"
  
  # ...

end

spec/requests/sessions_spec.rb

require 'rails_helper'

RSpec.describe "Sessions" do

  it "signs user in and out" do
    user = User.create!(email: "user@example.org", password: "very-secret")
    user.confirm
    
    sign_in user
    get authenticated_root_path
    expect(controller.current_user).to eq(user)
    
    sign_out user
    get authenticated_root_path
    expect(controller.current_user).to be_nil
  end
end
Clone this wiki locally