Rails, Devise, Rspec: Undefined method 'sign_in'
Asked Answered
L

7

39

I am trying to write Rspec tests in Rails, using Devise helper methods for signing in and out. The sign_in method is not working. However, it had been working earlier, before a slew of changes to the app.

Things I have tried:

  • I am including the test helpers in Rspec.configure.
  • Using Warden's login_as
  • Clearing the Rails cache.
  • Getting rid of Capybara to see if that were causing the issue
  • I am not setting the session explicitly in my controller specs (e.g. no valid_session)

So far, no dice. What do I need to do differently to test my controllers with a signed-in user?

Error message:

 OrderItemsController GET #index renders the :index view
 Failure/Error: sign_in :admin
 NoMethodError:
      undefined method `sign_in' for #  <RSpec::ExampleGroups::OrderItemsController_2::GETIndex:0x00000102c002d0>
 # ./spec/controllers/order_items_controller_spec.rb:6:in `block (2 levels) in <top (required)>'

Controller Spec

require 'spec_helper'

describe OrderItemsController do
    before (:each) do
        admin = create(:admin)
        sign_in :admin
    end

    describe "GET #index" do
        it "renders the :index view" do
            get :index
            expect( response ).to render_template :index
        end
    end
end

spec_helper.rb

require 'rspec/rails'
require 'capybara/rspec'

RSpec.configure do |config|

  config.include ApplicationHelper
  config.include ControllersHelper
  config.include UsersHelper
  config.include Devise::TestHelpers, type: :controller
  config.include FactoryGirl::Syntax::Methods

end

Gemfile

group :development, :test do
    gem 'rspec-rails', '~> 3.0.0.beta'
    gem 'capybara'
    gem 'factory_girl_rails'
    gem 'faker'
    gem 'dotenv-rails'
    gem 'guard'
    gem 'guard-annotate'
    gem 'guard-rspec', require: false
    gem 'guard-livereload', require: false
    gem 'foreman'
end

factories/user.rb

FactoryGirl.define do

    factory :user do
        first                   { Faker::Name.first_name }
        last                    { Faker::Name.last_name }
        email                   { Faker::Internet.email }
        admin                   false
        password                "secrets1"
        password_confirmation   "secrets1"
        confirmed_at            Date.today

        factory :admin do
            admin               true
        end
    end
end

Thanks in advance.

Luckless answered 25/5, 2014 at 20:27 Comment(0)
L
31

Did you recently upgrade to RSpec 3 like I did? This is from the RSpec 3 documentation:

Automatically Adding Metadata RSpec versions before 3.0.0 automatically added metadata to specs based on their location on the filesystem. This was both confusing to new users and not desirable for some veteran users.

In RSpec 3, this behavior must be explicitly enabled:

​# spec/rails_helper.rb
RSpec.configure do |config|
    config.infer_spec_type_from_file_location!
end

Since this assumed behavior is so prevalent in tutorials, the default configuration generated by rails generate rspec:install enables this.

If you follow the above listed canonical directory structure and have configured infer_spec_type_from_file_location!, RSpec will automatically include the correct support functions for each type.

After I add that configuration snippet, I no longer have to specify the spec type (e.g. type: :controller).

Lesbianism answered 10/6, 2014 at 1:21 Comment(0)
S
9

If you need the sign_in method in a request spec file, then you should include this:

config.include Devise::Test::IntegrationHelpers, type: :request
Skirt answered 28/4, 2021 at 22:55 Comment(1)
Nice answer. And just to clarify, the line goes inside the block that starts with RSpec.configure do |config|Kobylak
L
8

I figured out a solution. I explicitly defined the controller's Describe block as a controller type.

describe OrderItemsController, :type => :controller do

I still don't understand why this code worked earlier but now needs this (seemingly redundant) explicit declaration. Regardless, I'd appreciate learning what happened here. Thanks!

Luckless answered 25/5, 2014 at 21:47 Comment(3)
Thanks for your answer, helped me. I'm going from Rails 4 to 4.1. You? I'll check the controller test guides and if I find anything I will mention it here.Lesbianism
Still on Rails 4.0.3. Thanks for looking.Luckless
Think I found it. Please see my answer.Lesbianism
O
7

I can provide you an example (works for me - rspec / capybara / simplecov etc..)

spec/spec_helper.rb

 require 'capybara/rspec'
 require 'capybara/rails'

 RSpec.configure do |config|
  config.use_transactional_fixtures = true

  config.infer_base_class_for_anonymous_controllers = false

  config.include FactoryGirl::Syntax::Methods
  config.include Devise::TestHelpers, type: :controller
  config.include Capybara::DSL
  config.include Warden::Test::Helpers
  config.include Rails.application.routes.url_helpers
end

spec/integration/user_flow_spec.rb

require 'spec_helper'

feature 'Verify contract' do
  # Create employee
  let(:employee) { create(:employee) }
  let (:book) { create(:book) }

  # Sign in employee before each test!
  before :each do
    login_as employee, scope: :user
  end

  scenario 'create book' do
    # Visit Index and click to create
    visit employee_books_path
    click_link 'Create'
    expect(current_path).to eq(employee_books_path)
  end
end

I hope it will be ok :) I think your problem is missing Warden test helpers...

Oystercatcher answered 25/5, 2014 at 21:34 Comment(3)
Now it's saying undefined method 'get' and 'post', so I can't tell if your answer has bypassed my issue. Again, all of this worked earlier, it's just weird.Luckless
@steel, your comment here helped me to realize I was indeed in the same boat as you, and thus your answer worked for me too.Lesbianism
Showing your spec_helper helped me. It works. Thanks.Yeargain
S
7

You can use the Devise helper in the file spec/spec_helper.rb:

RSpec.configure do |config|
   config.include Devise::TestHelpers, type: :controller
end
Sliwa answered 19/2, 2016 at 17:30 Comment(0)
T
2

For Rails 5 and Rspec 3 you need to add this into your spec_helper.rb

config.include Devise::Test::ControllerHelpers, type: :controller

Terrazzo answered 14/7, 2017 at 19:1 Comment(0)
H
-1

You can use login_as method instead like this:

# rails_helper.rb
RSpec.configure do |config|
   config.include Warden::Test::Helpers
end

In your spec file use:

#spec/integration/user_flow_spec.rb
before :each do
    employee = create(:employee)
    login_as employee, scope: :user
end
Hereto answered 7/7, 2021 at 5:11 Comment(1)
The undefined method error indicates the correct module(s) wasn't mixed in. Your solution, while it would work, does not address the original question.Luckless

© 2022 - 2024 — McMap. All rights reserved.