How to test after_sign_in_path_for(resource)?

孤者浪人 提交于 2019-12-17 18:39:36

问题


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?


回答1:


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



回答2:


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" => "test@example.com", "password" => "please"}
        response.should redirect_to(new_organization_path)
    end
  end
end



回答3:


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)




回答4:


context "without previous page" do
  before do
    Factory.create(:user, email: "junior@example.com", password: "123456", password_confirmation: "123456")
    request.env["devise.mapping"] = Devise.mappings[:user]
    post :create, user: { email: "junior@example.com", password: "123456" }
  end
end 

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

  it { response.should redirect_to("http://test.com/restaurants") }
end



回答5:


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


来源:https://stackoverflow.com/questions/6658251/how-to-test-after-sign-in-path-forresource

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!