Как сделать интеграционное тестирование с RSpec и Devise / CanCan? - PullRequest
36 голосов
/ 03 мая 2011

Если у меня есть пользователь модели Devise, из которых только те пользователи с ролью: admin могут просматривать определенный URL-адрес, как я могу написать интеграционный тест RSpec, чтобы проверить, что статус возвращает 200 для этого URL-адреса?

def login(user)
  post user_session_path, :email => user.email, :password => 'password'
end

Это было предложено псевдо-предложением в ответе на этот вопрос: Аутентификация аутентификации в спецификации запроса , но я не могу заставить ее работать с устройством. CanCan получает нулевого пользователя при проверке способности, которая, естественно, не имеет правильных разрешений.

Нет доступа к контроллеру в спецификациях интеграции, поэтому я не могу заглушить current_user, но я бы хотел сделать что-то вроде этого.

describe "GET /users" do
  it "should be able to get" do
    clear_users_and_add_admin #does what it says...
    login(admin)
    get users_path
    response.status.should be(200)
  end
end

ПРИМЕЧАНИЕ !!! : все изменилось с тех пор, как был задан вопрос. Текущий лучший способ сделать это здесь: http://github.com/plataformatec/devise/wiki/How-To:-Test-with-Capybara

Ответы [ 6 ]

47 голосов
/ 30 января 2012

@ Собственный ответ pschuegr заставил меня переступить черту. Для полноты, это то, что я сделал, чтобы мне было легко настроить как спецификации запроса, так и спецификации контроллера (используя FactoryGirl для создания пользовательского экземпляра):

в /spec/support/sign_in_support.rb:

#module for helping controller specs
module ValidUserHelper
  def signed_in_as_a_valid_user
    @user ||= FactoryGirl.create :user
    sign_in @user # method from devise:TestHelpers
  end
end

# module for helping request specs
module ValidUserRequestHelper

  # for use in request specs
  def sign_in_as_a_valid_user
    @user ||= FactoryGirl.create :user
    post_via_redirect user_session_path, 'user[email]' => @user.email, 'user[password]' => @user.password
  end
end

RSpec.configure do |config|
  config.include ValidUserHelper, :type => :controller
  config.include ValidUserRequestHelper, :type => :request
end

Тогда в спецификации запроса:

describe "GET /things" do
  it "test access to things, works with a signed in user" do
    sign_in_as_a_valid_user
    get things_path
    response.status.should be(200)
  end
end

describe "GET /things" do
  it "test access to things, does not work without a signed in user" do
    get things_path
    response.status.should be(302) # redirect to sign in page
  end
end

и аналогичным образом, используйте 'signature_in_as_valid_user' в спецификациях контроллера (что оборачивает метод sign_in Devise :: TestHelpers с пользователем из FactoryGirl)

28 голосов
/ 03 мая 2011

Ах, так близко.Это делает трюк - мне не хватало правильной формы параметра и перенаправления.

post_via_redirect user_session_path, 'user[email]' => user.email, 'user[password]' => user.password
20 голосов
/ 10 августа 2012

Я использовал немного другой подход, используя Warden :: Test :: Helpers.

В моем spec / support / macros.rb я добавил:

module RequestMacros
  include Warden::Test::Helpers

  # for use in request specs
  def sign_in_as_a_user
    @user ||= FactoryGirl.create :confirmed_user
    login_as @user
  end
end

И затем включилчто в конфигурации RSpec в spec_helper.rb:

RSpec.configure do |config|
  config.include RequestMacros, :type => :request
end

А затем в самих запросах спецификации:

describe "index" do
  it "redirects to home page" do
    sign_in_as_a_user 
    visit "/url"
    page.should_not have_content 'content'
  end
end

В отличие от метода post_via_redirect user_session_path, это на самом деле работает и позволяет мненапример, использовать current_user в before_filters.

0 голосов
/ 19 мая 2017

По состоянию на середину 2017 года у нас есть еще одна, на мой взгляд, лучшая возможность интегрировать разработки в наши Rspecs. Мы можем использовать аутентификацию заглушки с помощью вспомогательного метода sign in, определенного как описано ниже:

module ControllerHelpers
    def sign_in(user = double('user'))
      if user.nil?
        allow(request.env['warden']).to receive(:authenticate!).and_throw(:warden, {:scope => :user})
        allow(controller).to receive(:current_user).and_return(nil)
      else
        allow(request.env['warden']).to receive(:authenticate!).and_return(user)
        allow(controller).to receive(:current_user).and_return(user)
      end
    end
  end

Вы также должны добавить в spec_helper.rb или rails_helper.rb ссылку на вновь созданный файл:

require 'support/controller_helpers'
  ...
  RSpec.configure do |config|
    ...
    config.include Devise::TestHelpers, :type => :controller
    config.include ControllerHelpers, :type => :controller
    ...
  end

Тогда в методе просто поместите в начало тела метода sign_in для контекста для аутентифицированного пользователя, и все готово. Актуальные детали можно найти в документации для разработчиков здесь

0 голосов
/ 02 ноября 2014
0 голосов
/ 03 мая 2011

Вы можете создать макрос (/spec/support/controller_macros.rb) и написать что-то вроде:

module ControllerMacros
  def login_user
    before(:each) do
      @request.env["devise.mapping"] = :user
      @user = Factory(:user)
      sign_in @user
    end
  end
end

Вы также можете включить любые атрибуты CanCan, которые вы хотите. Тогда в вашей спецификации:

describe YourController do
    login_user

    it "should ..." do

    end
...