Как выполнить интеграционное тестирование с помощью RSpec и Devise/CanCan?
Если у меня есть пользователь модели 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
Ответы
Ответ 1
@pchuegr собственный ответ получил меня через линию. Для полноты, это то, что я сделал, что позволяет мне легко настроить как спецификации запросов, так и спецификации контроллера (используя 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
Затем в запросе spec:
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
и аналогичным образом использовать 'signed_in_as_valid_user' в спецификациях контроллера (который обертывает метод sign_in Devise:: TestHelpers с пользователем из FactoryGirl)
Ответ 2
А, так близко. Это делает трюк - мне не хватает правильной формы параметра и перенаправления.
post_via_redirect user_session_path, 'user[email]' => user.email, 'user[password]' => user.password
Ответ 3
Я использовал несколько иной подход, используя 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, например.
Ответ 4
Вы можете создать макрос (/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
Ответ 5
Я нашел эту ссылку очень полезной https://github.com/plataformatec/devise/wiki/How-To:-Test-controllers-with-Rails-3-and-4-(and-RSpec)
Ответ 6
По состоянию на середину 2017 года у нас есть еще одна, на мой взгляд, лучшая opprotunity для интеграции разработки в наши Rspec. Мы можем использовать аутентификацию заглушки со вспомогательным методом 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
для контекста для аутентифицированного пользователя, и вы все настроены. Обновленные данные можно найти в devome docs здесь