uncaught throw :warden при тестировании перенаправления для пользователей, не вошедших в систему

Это спецификация для очень типичного контроллера с before_filter, который перенаправляет на страницу входа, когда незарегистрированный пользователь (он же гость) пытается получить доступ к /projects/new.

describe ProjectsController do
  (...)

  describe "GET new" do
    context 'when not logged in' do
      before { sign_in_nobody }

      context 'creating project' do
        before { get :new }

        it 'denies access' do
          expect(response).to be_redirect
        end
      end
    end
  end
end

Я указал все возможные результаты доступа к :index, :show и :new для гостей, пользователей, администраторов и суперадминистраторов. У меня не было никаких проблем с использованием ни зарегистрированных, ни гостевых пользователей, администраторов или нет, но на самом деле это первый раз, когда эта спецификация коснулась действия, которое включает before_filter :autheticate_user! Devise, и это с треском проваливается.

Как вы, наверное, уже подозреваете, спецификация даже не достигает expect(response).to be_redirect, а до этого шипит:

Failures:

1) ProjectsController GET new when not logged in creating project denies access
   Failure/Error: get :new
   ArgumentError:
     uncaught throw :warden
   # ./spec/controllers/projects_controller_spec.rb:344:in `block (5 levels) in <top (required)>'

Я искал ответ на вопрос: "как правильно протестировать неаутентифицированных (гостей) пользователей с помощью rspec и devise", но все говорят только о проблемах с фактической регистрацией пользователей в devise для RSpec для использовать. Проблема, которую я решил таким образом:

#spec/support/devise_authenticators.rb
include Devise::TestHelpers

def sign_in_nobody
  @request.env["devise.mapping"] = Devise.mappings[:user]
  sign_in User.new
end

def sign_in_user
  @request.env["devise.mapping"] = Devise.mappings[:user]
  sign_in FactoryGirl.create(:user)
end

Однако здесь не удается войти в систему, а «не войти в систему». Пока я не получил абсолютно ничего, и я знаю, что люди ДОЛЖНЫ каким-то образом протестировать эти сценарии.

Сейчас я использую обходной путь:

before { sign_in_nobody }

context 'creating project' do
  it 'denies access' do
    expect{ get :new }.to raise_exception("uncaught throw :warden")
  end
end

Но даже несмотря на то, что это практически правильно (uncaught throw :warden происходит только тогда, когда authenticate_user! терпит неудачу, поэтому его можно использовать как ожидание), в теории это кажется действительно грязным.

Любые идеи, как это сделать правильно?

(...Может быть, мне вообще не следует это проверять, учитывая, что правильность before_filter authenticate_user! является ответственностью Devise, а не моей?)


person ellmo    schedule 28.10.2013    source источник


Ответы (3)


Это должно работать. Я только что потратил некоторое время на исправление той же проблемы, и оказалось, что у нас есть помощник по тестированию, который переопределяет process для тестов контроллера. Devise также переопределяет его на catch :warden, поэтому мне просто нужно было include Devise::TestHelpers, прежде чем включать модуль params по умолчанию.

Пример того, о чем я говорю, когда говорю, что мы переопределили process, см. в разделе этот ответ, который описывает, как установить параметры по умолчанию, чтобы включить format: json

person Sammy Larbi    schedule 05.11.2013
comment
У меня такая же ошибка, но я не понимаю, куда вставлять include Devise::TestHelpers. Можешь мне помочь? Спасибо - person Rowandish; 08.07.2014
comment
Вы можете сделать это в своем тестовом классе или в помощнике для всех контроллеров. Например, см. 2 верхних заголовка на github.com/plataformatec/devise/wiki/ для Test::Unit и RSpec. - person Sammy Larbi; 08.07.2014
comment
Спасибо! У меня была эта проблема, когда возникала ошибка uncaught throw :warden, хотя у нас были включены соответствующие помощники по тестированию. Оказалось, что у нас был помощник default_params, точно такой же, как тот, на который вы ссылались, который вызывал проблему. - person Percy; 30.11.2016

Итак, урок в том, что uncaught throw :warden происходит, когда authenticate_user! терпит неудачу.

Итак, выясните, почему аутентификация вашего пользователя не удалась, и вы решите свою проблему.

person Pieter van der Merwe    schedule 23.02.2016

У меня была аналогичная проблема, и я решил ее следующим образом:

e = catch(:warden) { get root_url }
expect(e[:message]).to be(:not_activated)
person Sarah Neuber    schedule 06.02.2017