How to test after_sign_in_path_for(resource)?
Asked Answered
A

5

19

I have devise authentication and registration set up on my Rails app. I'm using after_sign_in_path_for() to customise the redirect when the user signs in based on various scenarios.

What I'm asking is how to test this method? It seems hard to isolate since it is called automatically by Devise when the user signes in. I want to do something like this:

describe ApplicationController do
  describe "after_sign_in_path_for" do
    before :each do
      @user = Factory :user
      @listing = Factory :listing
      sign_in @user
    end

    describe "with listing_id on the session" do
      before :each do
        session[:listing_id] = @listing.id
      end

      describe "and a user in one team" do
        it "should save the listing from the session" do
          expect {
            ApplicationController.new.after_sign_in_path_for(@user)
          }.to change(ListingStore, :count).by(1)
        end

        it "should return the path to the users team page" do
          ApplicationController.new.after_sign_in_path_for(@user).should eq team_path(@user.team)
        end
      end
    end
  end
end

but that's obviously not the way to do it because I just get an error:

 Failure/Error: ApplicationController.new.after_sign_in_path_for(@user)
 RuntimeError:
   ActionController::Metal#session delegated to @_request.session, but @_request is nil: #<ApplicationController:0x00000104581c68 @_routes=nil, @_action_has_layout=true, @_view_context_class=nil, @_headers={"Content-Type"=>"text/html"}, @_status=200, @_request=nil, @_response=nil>

So, how can I test this method?

Anaheim answered 12/7, 2011 at 0:26 Comment(0)
V
33

Oddly, I was wondering this very thing today. Here's what I came up with. I created an anonymous subclass of ApplicationController. In this anonymous subclass, I exposed the protected methods that I wanted to test as public methods. Then I tested them directly.

describe ApplicationController do
  controller do
    def after_sign_in_path_for(resource)
        super resource
    end
  end

  before (:each) do
    @user = FactoryGirl.create(:user)
  end

  describe "After sigin-in" do
    it "redirects to the /jobs page" do
        controller.after_sign_in_path_for(@user).should == jobs_path
    end
  end

end
Varied answered 12/7, 2011 at 0:35 Comment(2)
Thank you! You just saved me another Devise headacheTurley
Thank you su much. I was thinking about this but did not have any idea about this controller.after_sign_in_path_for(@user).should == jobs_pathHordein
V
4

On a similar note - if you want to test the redirect after sign-up, you have two options.

First, you can follow a pattern similar to above and very directly test the method in RegistrationsController:

require 'spec_helper'

describe RegistrationsController do

  controller(RegistrationsController) do
    def after_sign_up_path_for(resource)
        super resource
    end
  end

  describe "After sign-up" do
    it "redirects to the /organizations/new page" do
        @user = FactoryGirl.build(:user)
        controller.after_sign_up_path_for(@user).should == new_organization_path
    end
  end
end

Or, you can take a more integration-testing sort of approach and do the following:

require 'spec_helper'

describe RegistrationsController do

  describe "After successfully completing the sign-up form" do

    before do
        @request.env["devise.mapping"] = Devise.mappings[:user]
    end

    it "redirects to the new organization page" do
        post :create, :user => {"name" => "Test User", "email" => "[email protected]", "password" => "please"}
        response.should redirect_to(new_organization_path)
    end
  end
end
Varied answered 12/7, 2011 at 3:35 Comment(0)
C
2

I found this answer through Google recently and thought I would add my solution. I didn't like the accepted answer because it was testing the return value of a method on the application controller vs testing the desired behavior of the app.

I ended up just testing the call to create a new sessions as a request spec.

RSpec.describe "Sessions", type: :request do
    it "redirects to the internal home page" do
        user = FactoryBot.create(:user, password: 'password 123', password_confirmation: 'password 123')
        post user_session_path, params: {user: {email: user.email, password: 'password 123'}}
        expect(response).to redirect_to(internal_home_index_path)
    end
end

(Rails 5, Devise 4, RSpec 3)

Curriculum answered 4/8, 2018 at 20:13 Comment(0)
T
1
context "without previous page" do
  before do
    Factory.create(:user, email: "[email protected]", password: "123456", password_confirmation: "123456")
    request.env["devise.mapping"] = Devise.mappings[:user]
    post :create, user: { email: "[email protected]", password: "123456" }
  end
end 

  it { response.should redirect_to(root_path) }
context "with previous page" do
  before do
    Factory.create(:user, email: "[email protected]", password: "123456", password_confirmation: "123456")
    request.env["devise.mapping"] = Devise.mappings[:user]
    request.env['HTTP_REFERER'] = 'http://test.com/restaurants'
    post :create, user: { email: "[email protected]", password: "123456" }
  end

  it { response.should redirect_to("http://test.com/restaurants") }
end
Thornburg answered 16/8, 2012 at 12:24 Comment(0)
P
1

For the newcomers, I would recommend doing this way:

RSpec.describe ApplicationController, type: :controller do
  let(:user) { create :user }

  describe "After sing-in" do
    it "redirects to the /yourpath/ home page" do
      expect(subject.after_sign_in_path_for(user)).to eq(yourpath_root_path)
    end
  end
end
Paleoecology answered 19/9, 2017 at 23:36 Comment(3)
Can please clarify what 'subject' is?Catabolite
@Abdul-RahmanAhmad 'ApplicationController' as it is in RSpec.describe ApplicationController.Paleoecology
Thank you, got itCatabolite

© 2022 - 2024 — McMap. All rights reserved.