0

I can not understand, why not pass the tests, it performs the first redirect and not the second, as described in the controller code itself works correctly, redirections occur exactly as described.

Rspec 3.5.1

Rails 5

Ruby 2.3.1

spec/features/authentication_pages_spec.rb

describe "autorization", type: :request do

    describe "for non-signed-in users" do
        let(:user) { FactoryGirl.create(:user) }

        describe "in the Users controller" do

            describe "visiting the edit page" do
                before { visit edit_user_path(user) }
                it { should have_title('Log in') }
            end

            describe "submitting to the update action" do
                before { patch user_path(user) }
                specify { expect(response).to redirect_to(login_path) }
            end
        end
    end

    describe "as wrong user" do
        let(:user) { FactoryGirl.create(:user) }
        let(:wrong_user) { FactoryGirl.create(:user, email: "[email protected]") }
        before { log_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 User#update action" do
            before { patch user_path(wrong_user) }
            specify { expect(response).to redirect_to(root_url) }
        end
    end
end
end

The test fails with the following error:

1) AuthenticationPages autorization as wrong user submitting a GET request to the Users#edit action should redirect to "http://www.example.com/" 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/login>.
   Expected "http://www.example.com/" to be === "http://www.example.com/login".

2) AuthenticationPages autorization as wrong user submitting a PATCH request to the User#update action should redirect to "http://www.example.com/" 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/login>.
   Expected "http://www.example.com/" to be === "http://www.example.com/login".

I cannot fathom why it's redirecting to the signin url when it should redirect to the root url - the user is signed in in the spec.

Here is the UserController:

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


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

def new
    @user = User.new
end

def create
    @user = User.new(user_params)
    if @user.save
     log_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 logged_in_user
  unless logged_in?
    flash[:danger] = "Please log in."
    redirect_to login_url
  end
end

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

Here are the relevant bits of my sessions_helper.rb file:

module SessionsHelper

# Logs in the given user.
def log_in(user)
  session[:user_id] = user.id
end

# Returns the current logged-in user (if any).
def current_user
  remember_token = User.encrypt(cookies[:remember_token])
  @current_user ||= User.find_by(id: session[:user_id])
end

def current_user?(user)
  user == current_user
end

# Returns true if the user is logged in, false otherwise.
def logged_in?
  !current_user.nil?
end

def log_out
    session.delete(:user_id)
    @current_user = nil
end
end

User class:

class User < ApplicationRecord
  has_secure_password
  before_save { self.email = email.downcase }
  before_create :create_remember_token
  validates :name, presence: true, length: { maximum: 50 }
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+(\.[a-z]+)*\.[a-z]+\z/i
  validates :email, presence: true, format: { with: VALID_EMAIL_REGEX     },uniqueness: { case_sensitive: false }
  validates :password, length: { minimum: 6 }

  def User.new_remember_token
      SecureRandom.urlsafe_base64
  end

  def User.encrypt(token)
      Digest::SHA1.hexdigest(token.to_s)
  end

  private

  def create_remember_token
      self.remember_token = User.encrypt(User.new_remember_token)
  end
 end

spec/support/utilities.rb

include ApplicationHelper

def valid_login(user)
  fill_in "Email",    with: user.email
  fill_in "Password", with: user.password
  click_button "Log in"
end

RSpec::Matchers.define :have_error_message do |message|
  match do |page|
    expect(page).to have_selector('div.alert.alert-error', text:   message)
  end
end

def log_in(user, options={})
    if options[:no_capybara]
        # Sign in when not using Capybara.
        remember_token = User.new_remember_token
        cookies[:remember_token] = remember_token
        user.update_attribute(:remember_token,       User.encrypt(remember_token))
    else
        visit login_path
        fill_in "Email",        with: user.email
        fill_in "Password",     with: user.password
        click_button "Log in"   
    end
end
4
  • What is the code for the log_in method used in your spec? Commented Oct 9, 2016 at 13:15
  • This creates a user with a different email address from the default. The tests specify that the original user should not have access to the wrong user’s edit or update actions.
    – Denis T.
    Commented Oct 9, 2016 at 14:11
  • Can you include that code in your question? I think it's relevant. Commented Oct 9, 2016 at 14:14
  • He is the first ever goes
    – Denis T.
    Commented Oct 9, 2016 at 15:35

2 Answers 2

1

I suspect your issue is related to

before { log_in user, no_capybara: true }

try changing it to

before { session[:user_id] = user.id }
11
  • This solution will not work, there is no method of session. After changing the error occurred Failure/Error: before { session[:user_id] = user.id } NoMethodError: undefined method session' for nil:NilClass `
    – Denis T.
    Commented Oct 9, 2016 at 12:24
  • Sorry, I wrongly assumed this was a controller test. I'm a little confused though about the log_in user part ... I assume SessionsHelper is part of your app. In which case how is log_in routed to it?
    – David
    Commented Oct 9, 2016 at 12:34
  • If I understand you correctly, something like this: get /login, to: sessions#new post /login, to: sessions#create
    – Denis T.
    Commented Oct 9, 2016 at 13:32
  • ok it's still not clear to me from your code what the log_in user within the before block actually calls? I assume you must have a support class that has this method - and I don't mean SessionsHelper as that appears to be a helper for your app controllers. I do suspect that this is where your problem lies - try testing for expect(request.session[:user_id]).to eq(user.id) to see whether user is actually logged in.
    – David
    Commented Oct 9, 2016 at 14:07
  • added spec / support / utilities.rb
    – Denis T.
    Commented Oct 9, 2016 at 15:42
1

The problem is with your log_in method (in the spec, not the helper code), which is not actually logging anybody in. That's why you hit the login error. You mention that this code "creates a user with a different email address from the default", but this is not what it should be doing; it should be setting the session.

Simply creating a user will not set the session, and without the session being set, logged_in? will be false and you will get redirected to the login page.

Try something like this instead:

before { @request.session[:user_id] = user.id }

This sets the session explicitly on the request to the user'd id, so that logged_in? will return true in your controller.

1
  • Error in session method, what I do, I do by the book by Michael Hartl
    – Denis T.
    Commented Oct 9, 2016 at 15:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.