RSpec против Cookies - тест не пройден, даже если приложение работает (имитирует зарегистрированного пользователя) - PullRequest
4 голосов
/ 01 апреля 2012

Я читаю турориал "Ruby on Rails" Майкла Хартла, но я застрял здесь .

Я написал тесты для проверки авторизации пользователя при редактировании / обновлении пользователя,Я также написал код контроллера и он работает :

  1. Если пользователь не вошел в систему и пытается получить доступ к users#edit или users#update, он перенаправляется на страницу входа
  2. Если пользователь вошел в систему и пытается отредактировать другого пользователя, он перенаправлен в корень

Проблема в спецификации, которая проверяет пункт 2, я проверяю, что отправка запроса PUTна user_path я перенаправлен в корень, но при запуске rspec я получаю следующую ошибку:

Failures:

  1) Authentication authorization as wrong user submitting a PUT request to users#update 
     Failure/Error: specify { response.should 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>
     # ./spec/requests/authentication_pages_spec.rb:73:in `block (5 levels) in <top (required)>'

Кажется, он перенаправлен на signin_url вместо root_url, как если бы пользовательне регистрируется вообще ... и это, как мне кажется, вызывает проблему.

Приложение хранит токен в куки для аутентификации пользователя. Чтобы проверить это, я написал вспомогательный метод с именем signin_user(user) ипоместите его в файл spec/support/utilities.rb:

# spec/support/utilities.rb
def sign_in(user)
  visit signin_path
  fill_in "Email", with: user.email
  fill_in "Password", with: user.password
  click_button "Sign in"
  # Make signin work even when not using capybara (e.g. when using get, or post)
  cookies[:remember_token] = user.remember_token 
end

Как видите,ethod устанавливает cookie Remember_token, чтобы убедиться, что пользователь вошел в систему даже при использовании put, delete и т. д. ... или, по крайней мере, он должен работать!

Как я могу передать эту спецификацию так, как должна?

# spec/requests/authentication_pages_spec.rb
require 'spec_helper'

describe "Authentication" do
  subject { page }

  # ...

  describe "authorization" do
    # ...

    describe "as wrong user" do
      let(:user) { FactoryGirl.create(:user) }
      let(:another_user) { FactoryGirl.create(:user, email: "another@example.com") }

      before { sign_in(user) }

      # ...

      describe "submitting a PUT request to users#update" do
        before { put user_path(another_user) } 

        specify { response.should redirect_to(root_url) }
      end
    end
  end
end

ОБНОВЛЕНИЕ : А это мой UsersController:

class UsersController < ApplicationController
  before_filter :signed_in_user, :only => [:edit, :update]
  before_filter :correct_user, :only => [:edit, :update]

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

  def new
    @user = User.new
  end

  def create
    @user = User.new(params[:user])
    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(params[:user])
      sign_in(@user)
      flash[:success] = "Your profile was successfully updated"
      redirect_to @user
    else
      render "edit"
    end
  end

  private
    def signed_in_user
      unless signed_in?
        redirect_to signin_url, notice: "Please sign in to access this page."
      end
    end

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

Ответы [ 3 ]

3 голосов
/ 01 апреля 2012

Посмотрев на помощники из остального кода в вашем репозитории github, я думаю, что вижу проблему.

Вы используете переменную session для хранения :remember_token:

  def user_from_remember_token
    remember_token = session[:remember_token]
    User.find_by_remember_token(remember_token) unless remember_token.nil?
  end

Книга использует куки:

  def user_from_remember_token
    remember_token = cookies[:remember_token]
    User.find_by_remember_token(remember_token) unless remember_token.nil?
  end

Ваш помощник по тестированию устанавливает cookie:

# Make signin work even when not using capybara (e.g. when using get, or post)
cookies[:remember_token] = user.remember_token

но поскольку ваш user_from_remember_token ищет session[:remember_token], а не cookie, он считает, что пользователь не вошел в систему, поэтому тест перенаправляется на login_path вместо root_path.

Здесь говорится, почему они используют куки здесь: http://ruby.railstutorial.org/chapters/sign-in-sign-out?version=3.2#sec:a_working_sign_in_method


Если вы хотите продолжить использовать сеанс, вам нужно настроить тест для входа в систему с помощью post, чтобы put установил сеанс, например:

  describe "submitting a PUT request to users#update" do
    before do 
      post sessions_path, :email => user.email, :password => user.password
      put user_path(another_user)
    end
    specify { response.should redirect_to(root_url) }
  end
1 голос
/ 02 апреля 2012

Спасибо за ответ! Я работаю над книгой, и у меня та же проблема. Причина использования сеансов в том, что упражнение 2 в разделе 8.5 заключается в использовании сеанса вместо файлов cookie.

Мой ответ немного другой. Мой SessionsController использует переменные сеанса в параметрах:

  def create
    user = User.find_by_email(params[:session][:email])
    if user && user.authenticate(params[:session][:password])
      sign_in user
      redirect_back_or user
    else
      flash.now[:error] = 'Invalid email/password combination'
      render 'new'
    end
  end

поэтому исправление немного сложнее:

#spec/support/utilities.rb
def sign_in(user)
  visit signin_path
  fill_in "session_email",    with: user.email
  fill_in "session_password", with: user.password
  click_button "Sign in"
  # Sign in when not using Capybara as well.
  post sessions_path, {:session => { :email => user.email, :password => user.password }}
end
0 голосов
/ 15 августа 2012

У меня была та же проблема, но другая причина.

У меня была опечатка в spec / support / utilities.rb

def sign_in(user)
    visit signin_path
    fill_in "Email",  with: user.email
    fill_in "Password", with: user.password
    click_button "Sign in"
    # Sign in when not using Capybara as well
    cookies[:remember_toke] = user.remember_token
end

Обратите внимание, что в последней строке написано ": Remember_toke" вместо ": Remember_token"

Как-тоэто привело к сбою теста и перенаправлению на вход.

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

...