Kirti Thorat
Kirti Thorat

Reputation: 53028

Devise + RSpec : How to authenticate a user?

I am using Devise for member authentication. I need to test the log in scenario for a member. sign_in(member) doesn't check authentication information - it just signs in the member thats why i am using authenticate_member! method for authentication as suggested in Github Issue: How to authenticate the user with warden/devise in a customized way? .

BUT I get an exception saying ArgumentError: uncaught throw :warden.

        #spec/features/member.rb
        FactoryGirl.define do
          factory :member do
            email "[email protected]"
            password "12345678"
            firstname "John"
            lastname  "Doe"
            location "United States"
          end
        end

       #spec/controllers/sessions_spec.rb
       it "authenticate member" do

          create(:member)
          @request.env["devise.mapping"] = Devise.mappings[:member]
          @request.env["warden"] = warden

          controller.allow_params_authentication!
          expect(controller.authenticate_member!(:scope => :member, :force => true)).not_to be nil

        end

I also tried to set controller.resource = FactoryGirl.attributes_for(:member) thinking that resource is not set but then i get exception as

NoMethodError: protected method 'resource=' called for #<Devise::SessionsController:0x007ffc4e5bab10>

How to resolve this issue?

Upvotes: 2

Views: 1859

Answers (1)

Kirti Thorat
Kirti Thorat

Reputation: 53028

I posted a github issue on Devise regarding this question: Github Issue: RSpec with Devise : How to authenticate a user?

I was advised to use a post to sessions#create in order to simulate the POST request from the sign in form.

Here is the alternative solution:

   #spec/controllers/sessions_spec.rb
   it "authenticate member" do

     create(:member)
     @request.env["devise.mapping"] = Devise.mappings[:member]
     @request.env["warden"] = warden

     ## Added post request to "create"  
     post :create, :member => FactoryGirl.attributes_for(:member)

     ## Added new expectations 
     expect(controller.member_signed_in?).to be true
     expect(controller.current_member.email).to eq "[email protected]"

     ## "session["warden.user.member.key"][0].first" stores the "id" of logged in member
     ## Replace "member" in "session["warden.user.member.key"][0].first" with your 
     ## devise model name. For example: If your devise model name is customer then you  
     ## need to check "session["warden.user.customer.key"][0].first"   
     expect(session["warden.user.member.key"][0].first).to eq member.id

    end

NOTE: I would have liked to get an explanation of why my previous code as suggested in question and as provided by Devise team in Github Issue: How to authenticate the user with warden/devise in a customized way? didn't work out which it should have. Feel free to post a new answer if anyone finds an explanation as to why my previous code for member authentication didn't work.

Upvotes: 2

Related Questions