I'm trying to set up my feature tests, following this guide:
https://github.com/integrallis/learn-rspec-capybara
As the examples from the guide are fine, I'm trying to do the same in my project. But my tests fail, because the cookies getting lost all the time.
describe "Profile Sessions" do
before do
#profile= Profile.new
#profile.assign_attributes(FactoryGirl.attributes_for(:profile))
#profile.password = "123456"
#profile.password_confirmation = "123456"
#profile.verified = true
#profile.save
end
before do
visit signin_path
end
context "success" do
before do
fill_in 'Mail', with: #profile.email, :match => :prefer_exact
fill_in 'Password', with: "123456", :match => :prefer_exact
click_button 'Sign In', :match => :prefer_exact
end
it "should be profile page" do
current_path.should == profile_path(#profile)
end
it "displays a welcome message" do
expect(page).to have_content('Signed in successfully.')
end
end
end
SessionsController
def create
profile = Profile.find_by_email(params[:session][:email].downcase)
if profile && profile.authenticate(params[:session][:password])
if profile.verified
sign_in profile
redirect_to current_profile
else
flash[:error] = I18n.translate('signup.not_verified')
redirect_to root_url
end
else
flash.now[:error] = 'Invalid email/password combination'
render 'new'
end
end
In the log file I can see that the signin process is successful and redirects it to the profile page. Here a before_filter is applied:
def login_required
unless signed_in?
redirect_to signin_path, :alert => "You must first log in or sign up before accessing this page."
end
end
SessionsHelper
def sign_in(profile)
remember_token = Profile.new_remember_token
cookies.permanent[:remember_token] = remember_token
profile.update_attribute(:remember_token, Profile.encrypt(remember_token))
self.current_profile = profile
end
def signed_in?
!current_profile.nil?
end
def current_profile=(profile)
#current_profile = profile
end
def current_profile
remember_token = Profile.encrypt(cookies[:remember_token])
#current_profile ||= Profile.find_by_remember_token(remember_token)
end
def sign_out
self.current_profile = nil
cookies.delete(:remember_token)
end
After the redirect to the profile page the remember_token cookie is nil, so the profile is not signed in.
EDIT 1:
The test passes if I do a visit_page after the login:
context "success" do
before do
fill_in 'Mail', with: #profile.email, :match => :prefer_exact
fill_in 'Password', with: "123456", :match => :prefer_exact
click_button 'Sign In', :match => :prefer_exact
end
it "should be profile page" do
visit profile_path(#profile)
current_path.should == profile_path(#profile)
end
it "displays a welcome message" do
visit profile_path(#profile)
expect(page).to have_content('Signed in successfully.')
end
end
But what is going wrong after the redirect by the SessionsController?
Related
I have looked through pretty much every Rails Tutorial Chapter 9 question on StackOverflow. No one seems to be having this same issue. Maybe it's just a typo or something stupid I've missed and I just need some fresh eyes. Any help would be appreciated.
Errors:
Failures:
1) Authentication authorization as non-admin user submitting a DELETE request to the Users#destroy action
Failure/Error: specify { expect(response).to redirect_to(root_url) }
Expected response to be a redirect to <http://www.example.com/> but was a redirect to <http://www.example.com/signin>.
Expected "http://www.example.com/" to be === "http://www.example.com/signin".
# ./spec/requests/authentication_pages_spec.rb:60:in `block (5 levels) in <top (required)>'
2) Authentication authorization as wrong user submitting a GET request to the Users#edit action
Failure/Error: specify { expect(response).to redirect_to(root_url) }
Expected response to be a redirect to <http://www.example.com/> but was a redirect to <http://www.example.com/signin>.
Expected "http://www.example.com/" to be === "http://www.example.com/signin".
# ./spec/requests/authentication_pages_spec.rb:108:in `block (5 levels) in <top (required)>'
3) Authentication authorization as wrong user submitting a PATCH request to the Users#update action
Failure/Error: specify { response.should redirect_to(root_url) }
Expected response to be a redirect to <http://www.example.com/> but was a redirect to <http://www.example.com/signin>.
Expected "http://www.example.com/" to be === "http://www.example.com/signin".
# ./spec/requests/authentication_pages_spec.rb:113:in `block (5 levels) in <top (required)>'
Failed examples:
rspec ./spec/requests/authentication_pages_spec.rb:60 # Authentication authorization as non-admin user submitting a DELETE request to the Users#destroy action
rspec ./spec/requests/authentication_pages_spec.rb:108 # Authentication authorization as wrong user submitting a GET request to the Users#edit action
rspec ./spec/requests/authentication_pages_spec.rb:113 # Authentication authorization as wrong user submitting a PATCH request to the Users#update action
Authentication spec:
require 'spec_helper'
describe "Authentication" do
subject { page }
describe "signin page" do
before { visit signin_path }
it { should have_content('Sign in') }
it { should have_title('Sign in') }
end
describe "signin" do
before { visit signin_path }
describe "with invalid information" do
before { click_button "Sign in" }
it { should have_title('Sign in') }
it { should have_error_message('Invalid') }
describe "after visiting another page" do
before { click_link "Home" }
it { should_not have_error_message('Invalid') }
end
end # End of invalid Sign in Tests
describe "with valid information" do
let(:user) { FactoryGirl.create(:user) }
before { valid_signin(user) }
it { should have_title(user.name) }
it { should have_link('Users', href: users_path) }
it { should have_link('Profile', href: user_path(user)) }
it { should have_link('Sign out', href: signout_path) }
it { should have_link('Settings', href: edit_user_path(user)) }
it { should_not have_link('Sign in', href: signin_path) }
describe "followed by signout" do
before { click_link "Sign out" }
it { should have_link('Sign in') }
end
end # End of valid Sign in Tests
end # End of Sign in Tests
describe "authorization" do
describe "as non-admin user" do
let(:user) { FactoryGirl.create(:user) }
let(:non_admin) { FactoryGirl.create(:user) }
before { sign_in non_admin, no_capybara: true }
describe "submitting a DELETE request to the Users#destroy action" do
before { delete user_path(user) }
specify { expect(response).to redirect_to(root_url) }
end # End of DELETE request
end # End of Authentication->authorization->as non-admin
describe "for non-signed-in users" do
let(:user) { FactoryGirl.create(:user) }
describe "in the Users controller" do
describe "visiting the edit page" do
before { visit edit_user_path(user) }
it { should have_title('Sign in') }
end # End of Authen->author->nonsignedin->User controller->visiting edit
describe "submitting to the update action" do
before { patch user_path(user) }
specify { expect(response).to redirect_to(signin_path) }
end # End of submitting update
describe "visiting the user index" do
before { visit users_path }
it { should have_title('Sign in') }
end # End of Auth-autho->not signed in->user index
end # End of Authen->author->nonsignedin->Users controller
describe "when attempting to visit a protected page" do
before do
visit edit_user_path(user)
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
end
describe "after signing in" do
it "should render the desired protected page" do
expect(page).to have_title('Edit user')
end
end
end
end # End of Authentication->authorization->for non-signed-in users
describe "as wrong user" do
let(:user) { FactoryGirl.create(:user) }
let(:wrong_user) { FactoryGirl.create(:user, email: "wrong#example.com") }
before { sign_in user, no_capybara: true }
describe "submitting a GET request to the Users#edit action" do
before { get edit_user_path(wrong_user) }
specify { expect(response.body).not_to match(full_title('Edit user')) }
specify { expect(response).to redirect_to(root_url) }
end
describe "submitting a PATCH request to the Users#update action" do
before { patch user_path(wrong_user) }
specify { response.should redirect_to(root_url) }
end
end
end # End of Authentication->authorization
end # End of Authentication Tests
Users controller:
class UsersController < ApplicationController
before_action :signed_in_user, only: [:index, :edit, :update, :destroy]
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: :destroy
before_action :signed_in_redirect, only: [:new, :create]
def destroy
User.find(params[:id]).destroy
flash[:success] = "User deleted."
redirect_to users_url
end
def index
#users = User.paginate(page: params[:page])
end
def new
#user = User.new
end
def show
#user = User.find(params[:id])
end
def create
#user = User.new(user_params)
if #user.save
sign_in #user
flash[:success] = "Welcome to the Sample App!"
redirect_to #user
else
render 'new'
end
end
def edit
end
def update
if #user.update_attributes(user_params)
flash[:success] = "Profile updated"
redirect_to #user
else
render 'edit'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation, :admin)
end
# Before filters
def signed_in_user
unless signed_in?
store_location
redirect_to signin_url, notice: "Please sign in."
end
end
def correct_user
#user = User.find(params[:id])
redirect_to(root_url) unless current_user?(#user)
end
def admin_user
redirect_to(root_url) unless current_user.admin?
end
def signed_in_redirect
redirect_to root_url, note: "Already signed in" if signed_in?
end
end
Let me know if there's anything additional I should post in order to help you help me. Thanks in advance.
-EDIT-
Sessions helper:
module SessionsHelper
def sign_in(user)
remember_token = User.new_remember_token
cookies.permanent[:remember_token] = remember_token
user.update_attribute(:remember_token, User.hash(remember_token))
self.current_user = user
end
def signed_in?
!current_user.nil?
end
def current_user=(user)
#current_user = user
end
def current_user
remember_token = User.hash(cookies[:remember_token])
#current_user ||= User.find_by(remember_token: remember_token)
end
def current_user?(user)
user == current_user
end
def sign_out
current_user.update_attribute(:remember_token,
User.hash(User.new_remember_token))
cookies.delete(:remember_token)
self.current_user = nil
end
def redirect_back_or(default)
redirect_to(session[:return_to] || default)
session.delete(:return_to)
end
def store_location
session[:return_to] = request.url if request.get?
end
end
-EDIT 2-
utilities.rb:
include ApplicationHelper
def sign_in(user, options={})
if options[:no_capybara]
# Sign in when not using Capybara.
remember_token = User.new_remember_token
cookies[:remember_token] = remember_token
user.update_attribute(:remember_token, User.hash(remember_token))
else
visit signin_path
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
end
end
def valid_signin(user)
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
end
RSpec::Matchers.define :have_error_message do |message|
match do |page|
expect(page).to have_selector('div.alert.alert-error', text: message)
end
end
-EDIT 3-
edited portion of spec/support/utilities.rb
def sign_in(user, options={})
if options[:no_capybara]
# Sign in when not using Capybara.
remember_token = User.new_remember_token
cookies[:remember_token] = remember_token
user.update_attribute(:remember_token, User.hash(remember_token))
puts user
else
visit signin_path
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
end
end
Edited portion of app/controllers/users_controller
def signed_in_user
puts current_user
unless signed_in?
store_location
redirect_to signin_url, notice: "Please sign in."
end
end
Output from rspec spec/
╭─von at Vons-Mac in ~/dev/web/rails/sample_app on updating-users✘✘✘ using ‹ruby-2.1.0#railstutorial_4_0› 14-05-15 - 19:33:59
╰─○ rspec spec/
..
F
F
F
.
#<User:0x00000106b79240>
.
.
.
...................................................#<User:0x000001026f1370>
.#<User:0x00000106361850>
.#<User:0x00000106d7b688>
.#<User:0x0000010267df38>
#<User:0x00000106a77220>
.#<User:0x00000107abc9f0>
#<User:0x0000010607c748>
.#<User:0x0000010686cd68>
#<User:0x00000101610ec0>
#<User:0x000001036d47b0>
#<User:0x00000101e54730>
.#<User:0x00000107bdc858>
.#<User:0x0000010244a590>
.........#<User:0x00000106b81008>
.#<User:0x00000106331a60>
.#<User:0x0000010629b330>
.#<User:0x0000010a96cae8>
#<User:0x0000010a092b48>
.#<User:0x0000010a9f8160>
#<User:0x0000010a09b1f8>
.#<User:0x0000010a0f84e8>
#<User:0x0000010aa6f580>
.#<User:0x000001064eef88>
#<User:0x0000010ab82080>
.#<User:0x00000106535320>
#<User:0x000001065c83c8>
.#<User:0x0000010665a1d8>
#<User:0x0000010a17d300>
.
And then the same errors before that basically said the user wasn't signed in when they should've been.
Not sure if this is helpful 5 years later. But I realized like a year or 2 ago that the issue was this: I was returning the entire User record when I should've been returning a field. Thus, the failing test and resulting error.
I am trying to write tests and application code to redirect users who are already signed-in to the root_path if they try to CREATE a user or visit the NEW user path.
Here are the tests I have written in user_pages_spec.rb:
describe "for signed in users" do
let(:user) { FactoryGirl.create(:user) }
before { sign_in user }
describe "using a 'new' action" do
before { get new_user_path }
specify { response.should redirect_to(root_path) }
end
describe "using a 'create' action" do
before { post users_path }
specify { response.should redirect_to(root_path) }
end
end
UsersController:
class UsersController < ApplicationController
before_action :unsigned_in_user, only: [:create, :new]
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
sign_in #user
flash[:success] = "Welcome to the Sample App!"
redirect_to #user
else
render 'new'
end
end
private
# Before filters
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
def unsigned_in_user
puts signed_in?
redirect_to root_url, notice: "You are already signed in." unless !signed_in?
end
end
The puts signed_in? returns false. I am assuming this is the problem because I would expect it to return true. Here are the errors after running the tests using rspec. Any help is appreciated.
Failures:
1) User pages for signed in users using a 'create' action
Failure/Error: before { post users_path }
ActionController::ParameterMissing:
param not found: user
# ./app/controllers/users_controller.rb:52:in `user_params'
# ./app/controllers/users_controller.rb:20:in `create'
# ./spec/requests/user_pages_spec.rb:162:in `block (4 levels) in <top (required)>'
2) User pages for signed in users using a 'new' action
Failure/Error: specify { response.should redirect_to(root_path) }
Expected response to be a <redirect>, but was <200>
# ./spec/requests/user_pages_spec.rb:158:in `block (4 levels) in <top (required)>'
Within the sessions_helper.rb file:
def signed_in?
!current_user.nil?
end
In spec/support/utilities.rb:
def sign_in(user, options={})
if options[:no_capybara]
# Sign in when not using Capybara.
remember_token = User.new_remember_token
cookies[:remember_token] = remember_token
user.update_attribute(:remember_token, User.encrypt(remember_token))
else
visit signin_path
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
end
end
Were you able to get your tests to pass?
In case you weren't, I had the same problem as you today, and was able to get the tests to pass by making two changes to the tests - passing a user hash when POSTing, and using the no_capybara option on the sign_in method, since get and post are not capybara methods and I think RSpec doesn't behave as we might expect if we switch from capybara to non-capybara methods within the same test.
describe "for signed-in users" do
let(:user) { FactoryGirl.create(:user) }
before { sign_in user, no_capybara: true }
describe "using a 'new' action" do
before { get new_user_path }
specify { response.should redirect_to(root_path) }
end
describe "using a 'create' action" do
before do
#user_new = {name: "Example User",
email: "user#example.com",
password: "foobar",
password_confirmation: "foobar"}
post users_path, user: #user_new
end
specify { response.should redirect_to(root_path) }
end
end
Same answer as najwa, but I used the FactoryGirl user with the Rails attributes method to avoid duplication:
describe "using a 'create' action" do
before { post users_path, user: user.attributes }
specify { response.should redirect_to(root_path) }
end
Helps to keep the data decoupled from the test code.
I'm trying to test my controllers using Capybara. I have tried numerous ways, but for some reason I can not get it to see the current_user session. I know the login works when I run my spec for it. I'm also visiting the login page before my controller test. But it always seems to redirect me back when the :logged_in function is hit.
So not sure what I'm missing?
Here's what I have..
session_controller
def create
user = User.find_by_username(params[:username])
if( user && user.authenticate(params[:password]))
user.update_attribute(:token, User.token_digest)
flash[:notice] = "Success"
session[:user_id] = user.id
session[:token] = user.token
redirect_to dashboard_index_path
else
flash[:notice] = "Failed"
flash.now.alert = "Invalid user name or password"
render "new"
end
end
application_controller
protect_from_forgery
before_filter :logged_in
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
def logged_in
if !current_user
redirect_to root_url
return
end
if session[:token] != current_user.token
redirect_to root_url
end
end
products_controller_spec
it 'Should display new product form' do
user_login
visit new_product_path
response.body.should have_content("<h1>Create New Product</h1>")
end
spec_helper.rb
def user_login
visit root_path #this is new_session
fill_in "username", :with => "admin"
fill_in "password", :with => "111111"
click_button "Login"
end
Well I got it working,Not sure its politically correct way but.. instead of visiting the page, I'm just hard setting the session. In spec_helper.rb..
def user_login
user = FactoryGirl.create(:user)
session[:user_id] = user.id
session[:token] = User.token_digest
end
I'm trying to test my app controller with RSpec on Ruby on Rails. I'm not using Capybara (since many use it). This is my spec test:
require 'spec_helper'
describe UserController do
it "create new user" do
get :create, :user => { :email => 'foo#example.com', :name => 'userexample' }
flash[:notice] = 'new user was successfully created.'
end
describe "signup" do
before { visit new_user_registration_path }
let(:submit) { "Create my account" }
describe "with invalid information" do
it "should not create a user" do
expect { click_button submit }.not_to change(User, :count)
end
end
describe "with valid information" do
before do
fill_in "Name", :with=> "Example User"
fill_in "Email", :with=> "user#example.com"
fill_in "Password", :with=> "foobar"
fill_in "Confirmation", :with=> "foobar"
end
it "should create a user" do
expect { click_button submit }.to change(User, :count).by(1)
end
end
end
end
Here is my Usercontroller:
class UserController < ApplicationController
def index
end
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
redirect_to user_session_path
else
redirect_to new_user_session_path
end
end
def show
#user = User.find(params[:id])
#redirect_to #user
end
end
When I tested it, I got the error: undefined method 'visit':
Failure/Error: before { visit new_user_registration_path }
NoMethodError:
undefined method `visit' for #<RSpec::Core::ExampleGroup::Nested_1::Nested_1::Nested_2:0x132cefbc0>
# ./spec/controllers/user_controller_spec.rb:11
You must to use Capybara for this function. I think your tests are not in the right place. You must to do requests specs for that. It's not for controllers specs. See the doc : https://github.com/rspec/rspec-rails/.
I'm newbie on ruby on rails and I'm trying to test my controller with respect on ruby on rails.
It worked before, but now I don't know what happened, but when I do the test, I got the next error message:
/Library/Ruby/Gems/1.8/gems/rspec-core-2.10.1/lib/rspec/core/configuration.rb:746:in `load': no such file to load -- /Users/armandodejesussantoyareales/Documents/project_newbie/Estaciones/estaciones/spec/controllers/user_controller_spec.rb (LoadError)
this is my spec file:
require 'spec_helper'
describe UserController do
it "create new user" do
get :create, :user => { :email => 'foo#example.com', :name => 'userexample' }
flash[:notice] = 'new user was successfully created.'
end
describe "signup" do
before { visit signup_path }
let(:submit) { "Create my account" }
describe "with invalid information" do
it "should not create a user" do
expect { click_button submit }.not_to change(User, :count)
end
end
describe "with valid information" do
before do
fill_in "Name", with: "Example User"
fill_in "Email", with: "user#example.com"
fill_in "Password", with: "foobar"
fill_in "Confirmation", with: "foobar"
end
it "should create a user" do
expect { click_button submit }.to change(User, :count).by(1)
end
end
end
end
and this is my Usercontroller
class UserController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
redirect_to user_session_path
else
redirect_to new_user_session_path
end
def show
#user = User.find(params[:id])
#redirect_to #user
end
end
/Users/armandodejesussantoyareales/Documents/project_newbie/Estaciones/estaciones/spec/controllers/user_controller_spec.rb
Are you sure that's the right path? In a terminal, what happens when you do type in:
ls /Users/armandodejesussantoyareales/Documents/project_newbie/Estaciones/estaciones/spec/controllers/user_controller_spec.rb
If you get an error saying No such file or directory, then that path doesn't exist. If it just echoes back the path, then it's fine.
Alternatively, you can just manually look for this file and verify the path. But either way, my guess is you are just entering the path to your spec file incorrectly.