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
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)
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
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
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
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