How do I get Devise session#create test to pass - ruby-on-rails

Here is my test:
require 'test_helper'
class SessionsControllerTest < ActionController::TestCase
setup do
#request.env["devise.mapping"] = Devise.mappings[:user]
#u = Factory :user, :password => :mypass, :password_confirmation => :mypass
end
test 'log in page loads' do
get :new
assert :success
end
test 'log in with devise password' do
post :create, :user => {:email => #u.email, :password => 'mypass'}
ap session
end
end
gives this output, indicating that the sign in failed:
Loaded suite test/functional/sessions_controller_test
Started
.{
"action" => "create",
"locale" => "en",
"controller" => "sessions",
"user" => {
"password" => "mypass",
"email" => "458286#email.com"
}
}
{
"flash" => {
:alert => "Invalid email or password."
}
}
.
Finished in 0.49123 seconds.
This is my session controller:
#this is an extension of the devise controller for sessions
class SessionsController < Devise::SessionsController
before_filter :set_title_h1, :only => :new
before_filter :debug, :only => :create
before_filter :old_password_system_fix, :only => :create
private
def set_title_h1
#layout[:show_h1] = false
title 'Sign in Or Register'
end
def after_sign_in_path_for(resource)
#override Devise default sign in path /opt/local/lib/ruby/gems/1.8/gems/devise-1.1.2/lib/devise/controllers/helpers.rb
#edit_user_registration_path
'/en/main/index' #forces locale to be defined
end
def after_sign_out_path_for(resource)
#override Devise default sign out path /opt/local/lib/ruby/gems/1.8/gems/devise-1.1.2/lib/devise/controllers/helpers.rb
main_index_path
end
def old_password_system_fix
#purpose is to bring old users into the new system by setting their old password to the new format
require 'digest/md5'
email = params[:user][:email]
pw = params[:user][:password]
#get user
u = User.find_by_email email
return if u.nil?
#if they don't have a devise-style pw, authenticate with old
if u.encrypted_password.blank? && u.old_password.present?
#if [params pw] == md5 [old pw] then create devise-style pw & salt, store it, and let them through to devise auth action
if u.old_password == Digest::MD5.hexdigest(pw)
set_devise_style_pw(u, pw)
#if no match, give "invalid email or pw" message.
else
#flash[:notice] = "Sign in failed."
flash[:notice] = t 'devise.failure.invalid'
#render :new
redirect_to new_user_session_path
end
end
end
def debug
ap params
end
end
What am I missing and how can I test a new session via a functional test?

Turns out you have to use an integration test, not a functional test. Don't ask me why...

Related

"visit named_route_path" throws ArgumentError

I have this route setup in a Rails 3.1.12 app:
get '/compte/activer/:username/:token' => 'create_user#activate', :as => :create_user_activate
Here's the request spec:
describe "#activate with valid token" do
it "activates the account" do
user = User.create_basic("conradk", "email#email.com", "Conrad K.", "password", "password", "Hello world!")
visit create_user_activate_path(:username => user.username, :token => user.activation_token)
page.should have_content(I18n.t('activerecord.success.messages.account_activated'))
end
end
Here's the controller:
class CreateUserController < ApplicationController
def activate username, token
end
end
When I run the specs, I get this error:
Failure/Error: visit create_user_activate_path(:username => user.username, :token => user.activation_token)
ArgumentError:
wrong number of arguments (0 for 2)
What did I do wrong?
Try this
class CreateUserController < ApplicationController
def activate
end
end
Your controller method should be defined like below:
class CreateUserController < ApplicationController
def activate
#params will have your username and token
user_name = params[:username]
token = params[:token]
end
end

Devise Rspec registration controller test failing on update as if it was trying to confirm email address

I have the following route:
devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks",
:registrations => 'users/registrations',
:sessions => "users/sessions" }
and the following controller test (registrations_controller_spec.rb):
require File.dirname(__FILE__) + '/../spec_helper'
describe Users::RegistrationsController do
include Devise::TestHelpers
fixtures :all
render_views
before(:each) do
#request.env["devise.mapping"] = Devise.mappings[:user]
end
describe "POST 'create'" do
describe "success" do
before(:each) do
#attr = { :email => "user#example.com",
:password => "foobar01", :password_confirmation => "foobar01", :display_name => "New User" }
end
it "should create a user" do
lambda do
post :create, :user => #attr
response.should redirect_to(root_path)
end.should change(User, :count).by(1)
end
end
end
describe "PUT 'update'" do
before(:each) do
#user = FactoryGirl.create(:user)
#user.confirm! # or set a confirmed_at inside the factory. Only necessary if you are using the confirmable module
sign_in #user
end
describe "Success" do
it "should change the user's display name" do
#attr = { :email => #user.email, :display_name => "Test", :current_password => #user.password }
put :update, :id => #user, :user => #attr
puts #user.errors.messages
#user.display_name.should == #attr[:display_name]
end
end
end
end
Now, when I run rspec spec I get (what I think) are weird results:
The "should create a user" test passes. The user count has increased by 1.
However, my "should change the user's display name" fails as follows:
1) Users::RegistrationsController PUT 'update' Success should change the user's display name
Failure/Error: #user.display_name.should == #attr[:display_name]
expected: "Test"
got: "Boyd" (using ==)
And the weird bit is that my statement:
puts #user.errors.messages
Renders the following message:
{:email=>["was already confirmed, please try signing in"]}
What's going on? The user is signed in! That's proved by the fact that the Rspec error returned the display_name of "Boyd". And why is it displaying a message looks as though it's related with account confirmation as opposed to updating a user's details?
Any help would be greatly appreciated!
This works. Thanks holtkampw for seeing what I wasn't! I put some extra code in there just to double check and everything is well!
it "should change the user's display name" do
subject.current_user.should_not be_nil
#attr = { :email => #user.email, :display_name => "Test", :current_password => #user.password }
puts "Old display name: " + subject.current_user.display_name
put :update, :id => subject.current_user, :user => #attr
subject.current_user.reload
response.should redirect_to(root_path)
subject.current_user.display_name == #attr[:display_name]
puts "New display name: " + subject.current_user.display_name
end

Ruby On Rails 3 Tutorial Chap 8: Unit tests not passing

I'm working through Hartl's book and I'm up to chapter 8. I've written some tests that I believe should be passing. I've quadruple checked my code against what's in the book, and double checked it against what's in the book's github repo, but I'm stumped. I'm getting the following errors from RSpec:
Failures:
1) UsersController POST 'create' should redirect to the user "show" page
Failure/Error: response.should redirect_to(user_path(assigns(:user)))
ActionController::RoutingError:
No route matches {:action=>"show", :controller=>"users", :id=>#<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil, encrypted_password: nil, salt: nil>}
# ./spec/controllers/users_controller_spec.rb:93:in `block (3 levels) in <top (required)>'
2) UsersController POST 'create' should have a welcome message
Failure/Error: flash[:success].should =~ /welcome to the sample app/i
expected: /welcome to the sample app/i
got: nil (using =~)
# ./spec/controllers/users_controller_spec.rb:98:in `block (3 levels) in <top (required)>'
Finished in 0.83875 seconds
46 examples, 2 failures
Like I said, I've checked the code again and again. Restarted spork, restarted rails server, ran without spork. I've checked it against the code in the book and in the github repo. I've even copy/pasted the spec and controller code in the github repo, but all to no avail.
I'm stumped. It's late and I need to crash. :)
Hopefully one of you guys can see something I'm not. Here's what I've got so far...
users_controller_spec.rb
require 'spec_helper'
describe UsersController do
render_views
# ...
describe "POST 'create'" do
# ...
describe 'success' do
before(:each) do
#attr = { :name => 'New User', :email => 'some-email#gmail.com', :password => 'foobar', :password_confirmation => 'foobar' }
end
it 'should create a new user' do
lambda do
post :create, :user => #attr
end.should change(User, :count).by(1)
end
end
it 'should redirect to the user "show" page' do
post :create, :user => #attr
response.should redirect_to(user_path(assigns(:user)))
end
it 'should have a welcome message' do
post :create, :user => #attr
flash[:success].should =~ /welcome to the sample app/i
end
end
end
users_controller.rb
class UsersController < ApplicationController
def new
#user = User.new
#title = 'Sign up'
end
def show
#user = User.find params[:id]
#title = #user.name
end
def create
#user = User.new(params[:user])
if #user.save
flash[:success] = 'Welcome to the Sample App!'
redirect_to #user
else
#title = 'Sign up'
render 'new'
end
end
end
user.rb
class User < ActiveRecord::Base
# Virtual properties (don't exist in db)
attr_accessor :password
# Accessible properties
attr_accessible :name, :email, :password, :password_confirmation
email_regex = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :name, :presence => true,
:length => { :maximum => 50 }
validates :email, :presence => true,
:format => { :with => email_regex },
:uniqueness => { :case_sensitive => false }
validates :password, :presence => true,
:confirmation => true,
:length => { :within => 6..40 }
before_save :encrypt_password
# Return true if the user's password matches the submitted password
def has_password?(submitted_password)
# Compare encrypted_password with the encrypted version of submitted_password
encrypted_password == encrypt(submitted_password)
end
# Static/Class methods
def self.authenticate(email, submitted_password)
user = find_by_email email
return nil if user.nil?
return user if user.has_password? submitted_password
end
# Private functionality.
# Anything after the 'private' pragma will be inaccessable from outside the class
private
def encrypt_password
self.salt = make_salt if new_record? # Using ActiveRecord goodness to make sure this only gets created once.
self.encrypted_password = encrypt(password)
end
def encrypt(string)
secure_hash("#{salt}--#{string}")
end
def make_salt
secure_hash("#{Time.now.utc}--#{password}")
end
def secure_hash(string)
Digest::SHA2.hexdigest(string)
end
end
routes.rb
SampleApp::Application.routes.draw do
#get '/users/new'
resources :users
match '/signup' => 'users#new'
match '/about' => 'pages#about'
match '/contact' => 'pages#contact'
match '/help' => 'pages#help'
root :to => 'pages#home'
end
Thanks in advance. If you guys really want to dig through or if I've missed something in my post, here's my code.
I'm very new to rails, and absolutely love it so far. Any help will be greatly appreciated.
Look closely at your users_controller_spec "success" spec: when will it create #attr? Before each test, or just before the "should create a new user" test? You use it in all the "POST 'create'" tests...
Once you make that non-spec-specific your tests will pass.
(By the way, having the code up in git is handy, but only if the code you're posting is actually checked in, otherwise... not as much ;)
your
it "should redirect to the user show page"
and
it "should have a welcome message"
is outside of the
describe "success" do
loop

Is there any way to check if rails set permanent cookie?

I'm using TestUnit and I want to test the remember me functionality (when user login).
the cookies variable(and also require/response .cookies) contain only the cookie value without the expire time.
Rails somehow tell the web-browser when the cookie should be expire, so I assume there must be a way to check the cookie expire time.
EDIT
test "set permanent cookie" do
post :create, email: 'email', password: 'password', remember_me: true
# cookies[:auth_token] = random_string
# #request.cookies[:auth_token] = also_random_string
# #response.cookies[:auth_token] = also_random_string
end
the problem is that I can get only the values of the cookies and not the hash that contain the expire time.
As you've noticed, the cookies Hash only contains the values, not the expiration times, when you inspect it after your post call (this has been the behavior since at least Rails 2.3).
You have two options:
First, you could inspect the response.headers["Set-Cookie"] item instead. It will include the expiration time in there. However, the Set-Cookie value is just a single string, which you would need to then parse. For example, cookies["foo"] = {:value => "bar", :expires => Time.now + 10.years } would give you:
response.headers["Set-Cookie"]
# => "foo=bar; path=/; expires=Mon, 16-Aug-2021 21:54:30 GMT"
The other option (taken from This Question/Answer), would be to stub the cookie jar and make sure it is sent an expires value:
stub_cookie_jar = HashWithIndifferentAccess.new
controller.stub(:cookies) { stub_cookie_jar }
post :create, email: 'email', password: 'password', remember_me: true
expiring_cookie = stub_cookie_jar['expiring_cookie']
expiring_cookie[:expires].to_i.should be_within(1).of(1.hour.from_now.to_i)
Unfortunately, I couldn't get the solutions presented or linked in #DylanMarkow's answer working, so here is how I tested that a "permanent" cookie was being set when a Remember Me checkbox was checked (the tests are influenced/blatantly copied from the Test::Unit tests that DHH made in the commit that added cookies.permanent to Rails).
Tests use RSpec and FactoryGirl.
spec/requests/authentication_requests_spec.rb
require 'spec_helper'
describe "Authentication Requests" do
# ...
describe "authorization" do
# ...
describe "cookies" do
let(:user) { FactoryGirl.create(:user) }
subject { response.headers["Set-Cookie"] }
context "when remember me is set" do
before { sign_in_request(user) }
it { should =~ %r(.+expires.+#{20.years.from_now.year}) }
end
context "when remember me is not set" do
before { sign_in_request(user, remember_me: false) }
it { should_not =~ %r(expires) }
end
end
end
end
spec/utilities.rb
def sign_in_request(user, remember_me: "true")
post session_path(
session: {
email: user.email,
password: user.password,
remember_me: remember_me
}
)
end
App code snippets below use i18n, Haml, Bootstrap, and Simple Form syntax:
app/views/sessions/new.html.haml
= simple_form_for :session, url: session_path, html: {class: 'form-vertical' } do |f|
= f.input :email
= f.input :password
.checkbox
= f.input :remember_me, as: :boolean, label: false do
= check_box_tag :remember_me, 1, true
= label_tag :remember_me
= f.submit t('.signin'), class: "btn btn-large btn-primary"
app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
# ...
def create
if user = User.authenticate(params[:session][:email],
params[:session][:password])
sign_in user
flash[:success] = t('flash.successful_signin')
redirect_to root_url
else
flash.now[:error] = t('flash.invalid_credentials')
render 'new'
end
end
# ...
end
app/models/user.rb
class User < ActiveRecord::Base
has_secure_password
# ...
before_create :generate_authentication_token
def self.authenticate(email, password)
find_by_email(email).try(:authenticate, password)
end
private
def generate_authentication_token
begin
self.authentication_token = SecureRandom.urlsafe_base64
end while User.exists?(authentication_token: self.authentication_token)
end
end
app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
# ...
private
# A cookie that does not have an expiry will automatically be expired by
# the browser when browser's session is finished.
# cookies.permanent sets the expiry to 20 years
# Booleans seem to get passed from forms as strings
def sign_in(user)
if remember_me
cookies.permanent[:authentication_token] = user.authentication_token
else
cookies[:authentication_token] = user.authentication_token
end
self.current_user = user
end
helper_method :sign_in
def remember_me
params[:session].try(:[], :remember_me) == "true" ||
params[:remember_me] == "true"
end
# ...
end

How can I spec out an authlogic sessions controller using using a stub?

I want to test my User Session Controller testing that a user session is first built then saved. My UserSession class looks like this:
class UserSession < Authlogic::Session::Base
end
The create method of my UserSessionsController looks like this:
def create
#user_session = UserSession.new(params[:user_session])
if #user_session.save
flash[:notice] = "Successfully logged in."
redirect_back_or_default administer_home_page_url
else
render :new
end
end
and my controller spec looks like this:
describe UserSessionsController do
it "should build a new user session" do
UserSession.stub!(:new).with(:email, :password)
UserSession.should_receive(:new).with(:email => "some_email#gmail.com", :password => "foobar")
post :create, :user_session => { :email => "some_email#gmail.com", :password => "foobar" }
end
end
I stub out the new method but I still get the following error when I run the test:
Spec::Mocks::MockExpectationError in 'UserSessionsController should build a new user session'
<UserSession (class)> received :new with unexpected arguments
expected: ({:password=>"foobar", :email=>"some_email#gmail.com"})
got: ({:priority_record=>nil}, nil)
It's although the new method is being called on UserSession before my controller code is getting called. Calling activate_authlogic makes no difference.
This worked for me when I was getting extra :new messages on UserSession with ({:priority_record=>nil}, nil)
UserSession.should_receive(:new).at_least(1).times.with({ :email => "some_email#gmail.com", :password => "foobar" })

Resources