如何测试 after_sign_in_path_for(resource)?

发布于 2024-11-19 10:40:56 字数 1403 浏览 2 评论 0原文

我在 Rails 应用程序上设置了身份验证和注册。我使用 after_sign_in_path_for() 根据各种场景自定义用户登录时的重定向。

我想问的是如何测试这个方法?似乎很难隔离,因为它是在用户登录时由 Devise 自动调用的。我想做这样的事情:

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

但这显然不是这样做的方法,因为我只是得到一个错误:

 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>

那么,我该如何测试这个方法?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

她比我温柔 2024-11-26 10:40:57

奇怪的是,我今天就想知道这件事。这就是我的想法。我创建了 ApplicationController 的匿名子类。在这个匿名子类中,我将要测试的受保护方法公开为公共方法。然后我直接测试了它们。

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

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
不顾 2024-11-26 10:40:57

类似地,如果您想在注册后测试重定向,您有两个选择。

首先,您可以遵循与上面类似的模式,并非常直接地测试 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

或者,您可以采取更多集成测试的方法并执行以下操作:

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

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
活泼老夫 2024-11-26 10:40:57

我最近通过谷歌找到了这个答案,并认为我会添加我的解决方案。我不喜欢接受的答案,因为它正在测试应用程序控制器上方法的返回值,而不是测试应用程序的所需行为。

我最终只是测试了创建新会话作为请求规范的调用。

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)

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)

习惯成性 2024-11-26 10:40:57
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
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
我也只是我 2024-11-26 10:40:57

对于新人,我建议这样做:

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

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文