ruby on rails 3 - ejemplos - Autenticación de copiado en especificación de solicitud
django (5)
Al escribir una especificación de solicitud, ¿cómo se configuran las sesiones y / o los métodos de controlador de stub? Intento anular la autenticación en mis pruebas de integración - rspec / requests
Aquí hay un ejemplo de una prueba
require File.dirname(__FILE__) + ''/../spec_helper''
require File.dirname(__FILE__) + ''/authentication_helpers''
describe "Messages" do
include AuthenticationHelpers
describe "GET admin/messages" do
before(:each) do
@current_user = Factory :super_admin
login(@current_user)
end
it "displays received messages" do
sender = Factory :jonas
direct_message = Message.new(:sender_id => sender.id, :subject => "Message system.", :content => "content", :receiver_ids => [@current_user.id])
direct_message.save
get admin_messages_path
response.body.should include(direct_message.subject)
end
end
end
El ayudante:
module AuthenticationHelpers
def login(user)
session[:user_id] = user.id # session is nil
#controller.stub!(:current_user).and_return(user) # controller is nil
end
end
Y el ApplicationController que maneja la autenticación:
class ApplicationController < ActionController::Base
protect_from_forgery
helper_method :current_user
helper_method :logged_in?
protected
def current_user
@current_user ||= User.find(session[:user_id]) if session[:user_id]
end
def logged_in?
!current_user.nil?
end
end
¿Por qué no es posible acceder a estos recursos?
1) Messages GET admin/messages displays received messages
Failure/Error: login(@current_user)
NoMethodError:
undefined method `session'' for nil:NilClass
# ./spec/requests/authentication_helpers.rb:3:in `login''
# ./spec/requests/message_spec.rb:15:in `block (3 levels) in <top (required)>''
Nota para los usuarios de Devise ...
Por cierto, la respuesta de @David Chelimsky puede necesitar un pequeño ajuste si estás usando Devise . Lo que estoy haciendo en mi prueba de integración / solicitudes (gracias a esta publicación de ):
# file: spec/requests_helper.rb
def login(user)
post_via_redirect user_session_path, ''user[email]'' => user.email, ''user[password]'' => user.password
end
Esto me pareció muy útil para Devise: https://github.com/plataformatec/devise/wiki/How-To:-Test-controllers-with-Rails-3-and-4-(and-RSpec)
FWIW, al trasladar mis pruebas de Test :: Unit a RSpec, quería poder iniciar sesión con varias sesiones (de diseño) en mis especificaciones de solicitud. Me tomó un poco de excavación, pero conseguí que esto funcionara para mí. Usando Rails 3.2.13 y RSpec 2.13.0.
# file: spec/support/devise.rb
module RequestHelpers
def login(user)
ActionController::IntegrationTest.new(self).open_session do |sess|
u = users(user)
sess.post ''/users/sign_in'', {
user: {
email: u.email,
password: ''password''
}
}
sess.flash[:alert].should be_nil
sess.flash[:notice].should == ''Signed in successfully.''
sess.response.code.should == ''302''
end
end
end
include RequestHelpers
Y...
# spec/request/user_flows.rb
require ''spec_helper''
describe ''User flows'' do
fixtures :users
it ''lets a user do stuff to another user'' do
karl = login :karl
karl.get ''/users''
karl.response.code.should eq ''200''
karl.xhr :put, "/users/#{users(:bob).id}", id: users(:bob).id,
"#{users(:bob).id}-is-funny" => ''true''
karl.response.code.should eq ''200''
User.find(users(:bob).id).should be_funny
bob = login :bob
expect { bob.get ''/users'' }.to_not raise_exception
bob.response.code.should eq ''200''
end
end
Editar : error fijo
También podrías cerrar fácilmente la sesión.
controller.session.stub(:[]).with(:user_id).and_return(<whatever user ID>)
Todos los operadores especiales de ruby son de hecho métodos. Llamar a 1+1
es lo mismo que 1.+(1)
, lo que significa que +
es solo un método. Del mismo modo, la session[:user_id]
es lo mismo que llamar al método []
en la session
, como session.[](:user_id)
Una especificación de solicitud es una envoltura delgada alrededor de ActionDispatch::IntegrationTest
, que no funciona como las especificaciones del controlador (que envuelve ActionController::TestCase
). Aunque hay un método de sesión disponible, no creo que sea compatible (es decir, probablemente esté allí porque un módulo que se incluye para otras utilidades también incluye ese método).
Recomiendo iniciar sesión publicando en cualquier acción que use para autenticar usuarios. Si establece la contraseña ''contraseña'' (por ejemplo) para todas las fábricas del usuario, puede hacer algo como esto:
def login(user) post login_path, :login => user.login, :password => ''password'' end