Сбой / ошибка: укажите {ожидать (ответ).для redirect_to(root_url) }

#ruby-on-rails #rspec #rubygems #rspec-rails #rspec3

#ruby-on-rails #rspec #rubygems #rspec-рельсы #rspec3

Вопрос:

Я не могу понять, почему не проходят тесты, он выполняет первое перенаправление, а не второе, как описано в самом коде контроллера, работает корректно, перенаправления происходят именно так, как описано.

Rspec 3.5.1

Рельсы 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: "wrong@example.com") }
        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
  

Тест завершается ошибкой со следующей ошибкой:

1) Авторизация AuthenticationPages как неправильного пользователя, отправляющего запрос GET пользователям, действие #edit должно перенаправлять на «http://www.example.com /» Сбой/ Ошибка: укажите { ожидать(ответ).для 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) Авторизация страниц аутентификации, поскольку неправильный пользователь отправляет запрос на ИСПРАВЛЕНИЕ пользователю, действие #update должно перенаправляться на «http://www.example.com /»
Сбой / ошибка: укажите {ожидать (ответ).для 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".
  

Я не могу понять, почему он перенаправляет на URL-адрес входа, когда он должен перенаправлять на корневой URL-адрес — пользователь вошел в спецификацию.

Вот пользовательский контроллер:

 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
  

Пользовательский класс:

 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-zd-.] (.[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
  

Комментарии:

1. Какой код для log_in метода используется в вашей спецификации?

2. Это создает пользователя с адресом электронной почты, отличным от адреса электронной почты по умолчанию. Тесты указывают, что исходный пользователь не должен иметь доступа к действиям неправильного пользователя по редактированию или обновлению.

3. Можете ли вы включить этот код в свой вопрос? Я думаю, это актуально.

4. Он первый когда-либо идет

Ответ №1:

Я подозреваю, что ваша проблема связана с

 before { log_in user, no_capybara: true }
  

попробуйте изменить его на

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

Комментарии:

1. Это решение не будет работать, нет метода сеанса. После изменения произошла ошибка Failure/Error: before { session[:user_id] = user.id } NoMethodError: undefined method сеанса ‘ for nil:NilClass `

2. Извините, я ошибочно предположил, что это был тест контроллера. Я немного смущен пользовательской частью log_in … Я предполагаю, что SessionsHelper является частью вашего приложения. В этом случае как log_in перенаправляется на него?

3. Если я вас правильно понял, что-то вроде этого: get /login, to: sessions#new post /login, to: sessions#create

4. хорошо, мне все еще не ясно из вашего кода, что log_in user на самом деле вызывает блок before? Я предполагаю, что у вас должен быть класс поддержки, который имеет этот метод — и я не имею в виду SessionsHelper, поскольку он, по-видимому, является помощником для ваших контроллеров приложений. Я подозреваю, что именно в этом заключается ваша проблема — попробуйте проверить expect(request.session[:user_id]).to eq(user.id) , действительно ли пользователь вошел в систему.

5. добавлена спецификация / support / utilities.rb

Ответ №2:

Проблема в вашем log_in методе (в спецификации, а не во вспомогательном коде), который фактически не регистрирует никого. Вот почему вы столкнулись с ошибкой входа в систему. Вы упоминаете, что этот код «создает пользователя с адресом электронной почты, отличным от адреса электронной почты по умолчанию», но это не то, что он должен делать; он должен устанавливать сеанс.

Простое создание пользователя не установит сеанс, и без установки сеанса будет false, logged_in? и вы будете перенаправлены на страницу входа.

Попробуйте что-то вроде этого вместо:

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

Это явно устанавливает сеанс в запросе на идентификатор пользователя, так что logged_in? он вернется true в ваш контроллер.

Комментарии:

1. Ошибка в методе сеанса, что я делаю, я делаю по книге Майкла Хартла