Lors de l'écriture d'une spécification de demande, comment définissez-vous les sessions et/ou les méthodes de contrôleur de stub? J'essaie de bloquer l'authentification dans mes tests d'intégration - rspec/requests
Voici un exemple de test
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
L'aide:
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
Et l'ApplicationController qui gère l'authentification:
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
Pourquoi n'est-il pas possible d'accéder à ces ressources?
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)>'
Une spécification de demande est une enveloppe mince autour de ActionDispatch::IntegrationTest
, qui ne fonctionne pas comme les spécifications du contrôleur (qui encapsulent ActionController::TestCase
). Même s'il existe une méthode de session, je ne pense pas qu'elle soit prise en charge (c'est-à-dire qu'elle est probablement là car un module qui est inclus pour d'autres utilitaires inclut également cette méthode).
Je vous recommande de vous connecter en publiant les actions que vous utilisez pour authentifier les utilisateurs. Si vous créez le mot de passe "mot de passe" (par exemple) pour toutes les usines d'utilisateurs, vous pouvez faire quelque chose comme ceci:
def login (utilisateur) post login_path,: login => user.login,: mot de passe => 'mot de passe' fin
BTW, la réponse de @David Chelimsky peut nécessiter un petit ajustement si vous utilisez Devise . Ce que je fais dans mes tests d'intégration/de requêtes (grâce à ce post StackOverflow ):
# file: spec/requests_helper.rb
def login(user)
post_via_redirect user_session_path, 'user[email]' => user.email, 'user[password]' => user.password
end
FWIW, en portant mes tests Test :: Unit sur RSpec, je voulais pouvoir me connecter avec plusieurs sessions (devise) dans mes spécifications de demande. Il a fallu creuser, mais cela a fonctionné pour moi. Utilisation de Rails 3.2.13 et 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
Et...
# 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
Modifier : faute de frappe fixe