ruby on rails - tests - ¿Cómo hacer pruebas de integración con RSpec y Devise/CanCan?
rspec rails tutorial (6)
Si tengo un usuario modelo de Devise, del cual solo aquellos usuarios con la función: admin pueden ver una determinada URL, ¿cómo puedo escribir una prueba de integración RSpec para verificar que el estado arroje 200 para esa url?
def login(user)
post user_session_path, :email => user.email, :password => ''password''
end
Esto fue pseudo-sugerido en la respuesta a esta pregunta: Autenticación de anotación en especificación de solicitud , pero no puedo por mi vida hacer que funcione con el dispositivo. CanCan recibe un usuario nulo cuando verifica la habilidad, que no tiene los permisos correctos, naturalmente.
No hay acceso al controlador en las especificaciones de integración, por lo que no puedo anotar el actual_user, pero me gustaría hacer algo como esto.
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
¡¡¡NOTA!!! : todo esto ha cambiado desde que se hizo la pregunta. La mejor forma actual de hacerlo es aquí: http://github.com/plataformatec/devise/wiki/How-To:-Test-with-Capybara
A mediados de 2017, tenemos una oportunidad más, en mi opinión, de integrar el dispositivo en nuestras Rspecs. Podemos utilizar autenticación de stub con el método de sign in
ayuda definido como se describe a continuación:
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
También debe agregar en spec_helper.rb
o rails_helper.rb
referencia al archivo recién creado:
require ''support/controller_helpers''
...
RSpec.configure do |config|
...
config.include Devise::TestHelpers, :type => :controller
config.include ControllerHelpers, :type => :controller
...
end
Luego, en el método, simplemente coloque al comienzo del método body sign_in
para el contexto del usuario autenticado y ya está todo listo. Los detalles actualizados se pueden encontrar en los documentos de diseño aquí
Ah, tan cerca. Esto funciona: me faltaba la forma de parámetro adecuada y el redireccionamiento.
post_via_redirect user_session_path, ''user[email]'' => user.email, ''user[password]'' => user.password
Encontré este enlace muy útil https://github.com/plataformatec/devise/wiki/How-To:-Test-controllers-with-Rails-3-and-4-(and-RSpec)
La propia respuesta de @ pschuegr me llevó al otro lado de la línea. Para completar, esto es lo que hice que me permite configurar fácilmente tanto las especificaciones de solicitud como las especificaciones del controlador (usando FactoryGirl para crear la instancia de usuario):
en /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
Luego, en especificación de solicitud:
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
y de manera similar, use ''signed_in_as_valid_user'' en las especificaciones del controlador (que ajusta el método Devise :: TestHelpers sign_in con un usuario de FactoryGirl)
Puede crear una macro (/spec/support/controller_macros.rb) y escribir algo como:
module ControllerMacros
def login_user
before(:each) do
@request.env["devise.mapping"] = :user
@user = Factory(:user)
sign_in @user
end
end
end
También puede incluir cualquier atributo CanCan que desee. Entonces, en tu especificación:
describe YourController do
login_user
it "should ..." do
end
Usé un enfoque ligeramente diferente, usando Warden :: Test :: Helpers.
En mi spec / support / macros.rb agregué:
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
Y luego incluyó eso en la configuración de RSpec en spec_helper.rb:
RSpec.configure do |config|
config.include RequestMacros, :type => :request
end
Y luego en las especificaciones de solicitud en sí:
describe "index" do
it "redirects to home page" do
sign_in_as_a_user
visit "/url"
page.should_not have_content ''content''
end
end
En contraste con el método post_via_redirect user_session_path
, esto realmente funciona y me permite usar current_user en before_filters, por ejemplo.