ruby on rails - sign_in - Configuración de Warden para su uso en las especificaciones del controlador RSpec
rails use devise (2)
Pude usar el método de inicio de sesión de Devise para iniciar sesión en un usuario en las especificaciones de mi controlador. Pero ahora que estoy eliminando a Devise de mi aplicación, no estoy seguro de cómo obtener una funcionalidad similar trabajando solo con Warden por su cuenta.
¿Qué debo hacer para configurar los spec/spec_helper.rb
y spec/support/*.rb
spec/spec_helper.rb
relacionados para que Warden se ejecute dentro de las especificaciones del controlador lo suficiente?
He intentado configurar un archivo en spec/support/warden.rb
con estos contenidos:
RSpec.configure do |config|
config.include Warden::Test::Helpers
config.after do
Warden.test_reset!
end
end
Luego tengo llamadas similares a esta para autenticar una fábrica de user
:
before { login_as FactoryGirl.create(:user) }
Pero aquí está el error que sigo viendo:
NameError:
undefined method `user'' for nil:NilClass
Este error se remonta a mi authenticate_user!
Método en el controlador:
def authenticate_user!
redirect_to login_path, notice: "You need to sign in or sign up before continuing." if env[''warden''].user.nil?
end
Apreciaría cualquier orientación que alguien pueda proporcionar.
Hay un problema básico con lo que estás tratando de hacer. Warden es un middleware de Rack, pero las especificaciones del controlador RSpec ni siquiera incluyen Rack, ya que este tipo de especificaciones no están diseñadas para ejecutar toda la pila de aplicaciones, sino solo el código del controlador. Puede probar su middleware con pruebas separadas solo para ellos, pero en este caso, no creo que tenga sentido probar que Warden sí funciona.
Para probar que Warden está configurado correctamente, debe usar especificaciones de solicitud o especificaciones de integración (pepino, capibara o similar).
Aunque técnicamente es posible simular a Warden en las especificaciones del controlador, creo que no le brinda muchos beneficios al tiempo que aumenta la complejidad de su código de prueba de manera significativa. Tenga en cuenta que el middleware Rack está pensado para operar de manera transparente, de modo que sea fácil intercambiar el middleware dentro y fuera de la manera que lo desee. Su controlador no debe depender directamente de Warden (excepto quizás para ApplicationController
), por lo que tener una dependencia de prueba de Warden para su controlador es un signo de encapsulación rota.
Me encontré con este mismo problema recientemente, así que espero que este comentario sea útil.
No pensé que esta pregunta se aplicara a mi situación, pero sí: Stubbing Warden en las pruebas del controlador
Resulta que, Warden no se incluye en las especificaciones del controlador RSpec, por lo que necesitas hacer algo de magia para lograrlo.
Los ayudantes de prueba del controlador de Kentaro Imai para la publicación del blog de Warden fueron particularmente útiles. Así es como lo conseguí trabajando para RSpec.
Paso 1: Cree spec/spec_helper/warden.rb
y pegue estos contenidos, que Kentaro derivó de Devise:
module Warden
# Warden::Test::ControllerHelpers provides a facility to test controllers in isolation
# Most of the code was extracted from Devise''s Devise::TestHelpers.
module Test
module ControllerHelpers
def self.included(base)
base.class_eval do
setup :setup_controller_for_warden, :warden if respond_to?(:setup)
end
end
# Override process to consider warden.
def process(*)
# Make sure we always return @response, a la ActionController::TestCase::Behavior#process, even if warden interrupts
_catch_warden {super} || @response
end
# We need to setup the environment variables and the response in the controller
def setup_controller_for_warden
@request.env[''action_controller.instance''] = @controller
end
# Quick access to Warden::Proxy.
def warden
@warden ||= begin
manager = Warden::Manager.new(nil, &Rails.application.config.middleware.detect{|m| m.name == ''Warden::Manager''}.block)
@request.env[''warden''] = Warden::Proxy.new(@request.env, manager)
end
end
protected
# Catch warden continuations and handle like the middleware would.
# Returns nil when interrupted, otherwise the normal result of the block.
def _catch_warden(&block)
result = catch(:warden, &block)
if result.is_a?(Hash) && !warden.custom_failure? && [email protected](:performed?)
result[:action] ||= :unauthenticated
env = @controller.request.env
env[''PATH_INFO''] = "/#{result[:action]}"
env[''warden.options''] = result
Warden::Manager._run_callbacks(:before_failure, env, result)
status, headers, body = warden.config[:failure_app].call(env).to_a
@controller.send :render, :status => status, :text => body,
:content_type => headers[''Content-Type''], :location => headers[''Location'']
nil
else
result
end
end
end
end
end
Paso 2: en spec/spec_helper.rb
, dentro del bloque RSpec.configure
, agregue esta línea para incluir el nuevo módulo:
config.include Warden::Test::ControllerHelpers, type: :controller
Paso 3: para iniciar sesión en un usuario en un bloque before
, use una sintaxis similar a esta:
before { warden.set_user FactoryGirl.create(:user) }
Paso 4: Asegúrese de que hace referencia a request.env[''warden'']
en sus controladores, no env[''warden'']
. Este último no funcionará en las especificaciones del controlador en el entorno de test
.
¡Punta de sombrero para Kentaro Imai, a quien le debo una cerveza un día (o en otra vida)!