Abuzhan Abuzhan - 2 months ago 23
Ruby Question

Problems with testing page redirection

I have been studying Ruby on Rails based on Micheal Hartl's tutorial book and encountered a very interesting problem with rspec testing of the redirection to the root page in case if some user in my website tries to edit profile of another one by hitting the appropriate url. The thing is that when I start the rails server and check this action manually, it actually redirects me to the root url, however, the spec tests show that:

Failure/Error: specify { expect(response).to redirect_to(root_url) }
Expected response to be a redirect to <http://www.example.com/> but was a redirect to <http://www.example.com/signin>.
Expected "http://www.example.com/" to be === "http://www.example.com/signin".
# ./spec/requests/authentication_pages_spec.rb:95:in `block (5 levels) in <top (required)>'


I have searched the net in order to find cure for this issue, and found that there are actually several similar problems and people advise to use
no_capybara: true
in the
rb
file, however, I have already used this solution. The code part for this test is below:

describe "as wrong user" do
let(:user) { FactoryGirl.create(:user) }
let(:wrong_user) { FactoryGirl.create(:user, email: "wrong@example.com") }
before { sign_in user, no_capybara: true }

describe "submitting a GET request to the Users#edit action" do
before { get edit_user_path(wrong_user) }
specify { expect(response.body).not_to match(full_title('Edit user')) }
specify { expect(response).to redirect_to(root_url) }
end

describe "submitting a PATCH request to the Users#update action" do
before { patch user_path(wrong_user) }
specify { expect(response).to redirect_to(root_url) }
end
end


Controller code is also here:

class UsersController < ApplicationController
before_action :signed_in_user, only: [:index, :edit, :update]
before_action :correct_user, only: [:edit, :update]

def index
@users = User.all
end

def show
@user = User.find(params[:id])
end

def new
@user = User.new
end

def create
@user=User.new(user_params)
if @user.save
sign_in @user
flash[:success] = "Welcome to the Sample App!"
redirect_to @user
else
render 'new'
end
end

def edit
end

def update
if @user.update_attributes(user_params)
flash[:success] = "Profile updated"
redirect_to @user
else
render 'edit'
end
end

private

def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end

#Before filters

def signed_in_user
unless signed_in?
store_location
redirect_to signin_url, notice: "Please sign in."
end
end

def correct_user
@user = User.find(params[:id])
redirect_to(root_url) unless current_user?(@user)
end
end


Here are also session helper codes for the controller:

def current_user?(user)
user == current_user
end

def sign_out
current_user.update_attribute(:remember_token, User.encrypt(User.new_remember_token))
cookies.delete(:remember_token)
self.current_user = nil
end

def redirect_back_or(default)
redirect_to(session[:return_to] || default)
session.delete(:return_to)
end


I would be very glad for any answer, and ready to provide any details!

Answer

It seems like that the sign_in of the user is not working. Please check first if the user really is signed in via debugger / byebug or just write a small test case to verify it with get edit_user_path(user) (it should not redirect).

You might also want to check if your test sign_in method is implemented correctly: Can't understand no_capybara option in michael hart'l tutorial test. The is also an explanation why no_capybara option has to be used here.

Comments