I'm having trouble finding examples of valid_session in RSpec, and now all my scaffolded tests are broken after having added authorization.
Going through Michael Hartl's Rails Tutorial, I'm using the authentication which is described here, except I'm requiring login for all pages and use 'skip_before_filter' for signin etc.
I've added a user fixture, which I've verified gets loaded:
userexample:
id: 1
name: Example Name
email: examplename#example.com
password_digest: $2a$10$NuWL8f2X0bXaCof3/caiiOwlF2rago7hH10JECmw1p75kEpf0mkie
remember_token: YXjPrFfsK8SFQOQDEa90ow
Then in the controller spec
def valid_session
{ remember_token: "YXjPrFfsK8SFQOQDEa90ow" }
end
The code of the Session Helper
module SessionsHelper
def sign_in(user)
cookies.permanent[:remember_token] = user.remember_token
self.current_user = user
end
def signed_in?
return !current_user.nil?
end
def sign_out
self.current_user = nil
cookies.delete(:remember_token)
end
def current_user=(user)
#current_user = user
end
def current_user
#current_user ||= User.find_by_remember_token(cookies[:remember_token])
end
end
Am I using valid_session as intended? Will supplying a remember_token with the session even work without explicitly signing in the user with sign_in? Could this be solved in some other way?
This should work for you...
def valid_session
controller.stub!(:signed_in?).and_return(true)
end
...based on something similar that worked for me :D
def valid_session
controller.stub!(:authorize).and_return(User)
end
Related
Hello i have a Rspec/Capybara test im trying to make.
Im a logged in user that as admin user should be the only user to add Sizes to my app.
I just can't get the test to Login the user. Can anyone see why?
Please look at the sessions controller below. I do have a log_in method.
Error is
Failures:
1) adding size allow a admin user to add a size
Failure/Error: log_in(admin)
NoMethodError:
undefined method `log_in' for #<RSpec::ExampleGroups::AddingSize:0x007f8e4fa828e0>
# ./spec/features/sizes_features.rb:9:in `block (2 levels) in <top (required)>'
Test
require "rails_helper"
RSpec.feature "adding size" do
let(:size01) { FactoryGirl.build :size01 }
let(:user) { FactoryGirl.build :user }
let(:admin) { FactoryGirl.create(:user, admin: true) }
scenario "allow a admin user to add a size" do
log_in(admin)
size = create(:size01)
visit new_size_path
fill_in 'Title', with: "example"
click_button 'Create Size'
expect(current_path).to eql(sizes_path)
expect(page).to have_content("example")
end
scenario "user can't add size" do
log_in(user)
visit sizes_path
expect(current_path).to eql(root_path)
expect(page).to have_content("Rescricted Web Page")
end
scenario "vistor can't add size" do
visit sizes_path
expect(current_path).to eql(root_path)
end
end
FactoryGirl
FactoryGirl.define do
factory :user, :class => User do
username "example"
email "example#example.com"
admin "false"
password_digest "<%= User.digest('password') %>"
activated "true"
activated_at "<%= Time.zone.now %>"
end
end
Sessions controller.
module SessionsHelper
# Logs in the given user.
def log_in(user)
session[:user_id] = user.id
end
# Returns the user corresponding to the remember token cookie.
def current_user
if (user_id = session[:user_id])
#current_user ||= User.find_by(id: user_id)
elsif (user_id = cookies.signed[:user_id])
user = User.find_by(id: user_id)
if user && user.authenticated?(:remember, cookies[:remember_token])
log_in user
#current_user = user
end
end
end
# Returns true if the user is logged in, false otherwise.
def logged_in?
!current_user.nil?
end
# Logs out the current user.
def log_out
session.delete(:user_id)
#current_user = nil
end
# Remembers a user in a persistent session.
def remember(user)
user.remember
cookies.permanent.signed[:user_id] = user.id
cookies.permanent[:remember_token] = user.remember_token
end
# Returns true if the given user is the current user.
def current_user?(user)
user == current_user
end
# Forgets a persistent session.
def forget(user)
user.forget
cookies.delete(:user_id)
cookies.delete(:remember_token)
end
# Logs out the current user.
def log_out
forget(current_user)
session.delete(:user_id)
#current_user = nil
end
# Redirects to stored location (or to the default).
def redirect_back_or(default)
redirect_to(session[:forwarding_url] || default)
session.delete(:forwarding_url)
end
# Stores the URL trying to be accessed.
def store_location
session[:forwarding_url] = request.url if request.get?
end
end
Here is why it's not working:
Access to session and request is not possible from the test, Access to
response is limited. Some drivers allow access to response headers and
HTTP status code, but this kind of functionality is not provided by
some drivers, such as Selenium.
source: Capybara documentation
You have two options:
If you're using Devise for authentication, Devise provides authentication helpers you should use.
Otherwise, here's how I would approach your situation:
Instead of trying to directly manipulate the session, create a shared context or a helper that logs in the user by interacting with the login form in the same way a user browsing your site would.
Here is one approach:
spec/support/when_authenticated.rb
RSpec.shared_context 'When authenticated' do
background do
authenticate
end
def authenticate
visit '/sessions/new'
within('form#session') do
fill_in 'Email', :with => 'user#example.com'
fill_in 'Password', :with => 'password'
end
click_button 'Sign in'
end
end
Then, in your feature spec:
RSpec.feature 'User does something' do
include_context 'When authenticated'
# examples
end
This has the effect of running the authentication procedure before each example in your spec.
I am following tutorials mentioned https://www.railstutorial.org/book/log_in_log_out.
While I am executing a test with given command :
bundle exec rake test TEST=test/helpers/sessions_helper_test.rb
I am encountering Errors given below :
1) Error:
ApplicationHelperTest#test_current_user_returns_nil_when_remember_digest_is_wrong:
NoMethodError: undefined method remember' for #<ApplicationHelperTest:0x000000075bf4d0>
test/helpers/sessions_helper_test.rb:7:insetup'
2) Error:
ApplicationHelperTest#test_Current_user_returns_right_user_with_session_is_nill:
NoMethodError: undefined method remember' for #<ApplicationHelperTest:0x00000007702400>
test/helpers/sessions_helper_test.rb:7:insetup'
I have a helper class methods defined in /apps/helpers/session_helper.rd.
--remember method is part of this class .. still the /test/helpers/sessions_helper_test is unable to find that method.
Code for /test/helpers/sessions_helper_test.rb file is
require 'test_helper'
class ApplicationHelperTest < ActionView::TestCase
def setup
#user = users(:michael)
remember(#user)
end
test "Current_user returns right user with session is nill" do
assert_equal #user, current_user
assert is_logged_in?
end
test "current_user returns nil when remember digest is wrong" do
#user.update_attribute(:remember_digest, User.digest(User.new_token))
assert_nil current_user
end
end
This is a code for module SessionsHelper
module SessionsHelper
# Logs in the given user.
def log_in(user)
session[:user_id] = user.id
end
# Remembers a user in a persistent session.
def remember(user)
user.remember
cookies.permanent.signed[:user_id] = user.id
cookies.permanent[:remember_token] = user.remember_token
end
# Returns the current logged-in user (if any).
def current_user
if (user_id = session[:user_id])
#current_user ||= User.find_by(id: user_id)
elsif (user_id = cookies.signed[:user_id])
user = User.find_by(id: user_id)
if user && user.authenticated?(cookies[:remember_token]) #here is an Evaluation Magic for a given Method
log_in user
#current_user = user
end
end
end
# Returns true if the user is logged in, false otherwise.
def logged_in?
!current_user.nil?
end
# Logs out the current user. # Actions (Set digest to Nill) (Delete the Cookie) (Delete the Session) (Set current_user variable to nill)
def log_out
forget(current_user)
session.delete(:user_id)
#current_user = nil
end
def forget(user)
user.forget # is to forget the user .. means set th remember_digest to nill -- Go to User Model
cookies.delete(:user_id)
cookies.delete(:remember_token)
end
end
Users.yml file is :
# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
michael:
name: Michael Example
email: michael#example.com
password_digest: <%= User.digest('password') %>
archer:
name: Sterling Archer
email: duchess#example.gov
password_digest: <%= User.digest('password') %>
-----------------Got the Solution -------------------
you need to include HelperModule to test Module ..
after fix code for test/helpers/sessions_helper_test.rb will look like
require 'test_helper'
class ApplicationHelperTest < ActionView::TestCase
include SessionsHelper # This line is added to code.
def setup
#user = users(:michael)
remember(#user)
end
test "Current_user returns right user with session is nill" do
assert_equal #user, current_user
assert is_logged_in?
end
test "current_user returns nil when remember digest is wrong" do
#user.update_attribute(:remember_digest, User.digest(User.new_token))
assert_nil current_user
end
end
Following the tutorial as well and had a similar issue. You can avoid using include by updating your class from:
class ApplicationHelperTest < ActionView::TestCase
to:
class SessionsHelperTest < ActionView::TestCase
I'm going through Michael Hartl's Rails tutorial. I downloaded the source code samle_app_rails_4.
Then I add a test for signing out a user, it works fine in my browser, but in Rspec,
it fails. I changed nothing to the source code but add this to the user_pages_spec.rb.
require 'spec_helper'
describe "User pages" do
describe "sign out" do
let(:user) { FactoryGirl.create(:user) }
before :each do
sign_in user
end
it "should sign out a user" do
delete signout_path
expect(page).to have_content("Sign in")
end
end
end
The sign_in method is defined in spec/support/utilities.rb
include ApplicationHelper
def sign_in(user, options={})
if options[:no_capybara]
# Sign in when not using Capybara as well.
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
The sessions_controller.rb is like this( I ignored create action here.)
class SessionsController < ApplicationController
def new
end
def destroy
sign_out
redirect_to root_url
end
end
And sessions_helper.rbis like this:
module SessionsHelper
def sign_in(user)
remember_token = User.new_remember_token
cookies.permanent[:remember_token] = remember_token
user.update_attribute(:remember_token, User.encrypt(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.encrypt(cookies[:remember_token])
#current_user ||= User.find_by(remember_token: remember_token)
end
def current_user?(user)
user == current_user
end
def sign_out
self.current_user = nil
cookies.delete(:remember_token)
end
end
I have tried many solutions, post an issue on github, and this Cookies do not persist in Rspec on rails 3.1
I also go through these questions but nothing is helpful. https://stackoverflow.com/questions/tagged/railstutorial.org.
I even upgrade my rspec and capybara gem. Maybe something wrong with my test file?
delete signout_path is not right for signing out a user?
I find it's weird in sample app, as an user has logged in, he can still visit signin_path and signup_path.
Wish someone can help me, big thanks!
The page variable you are accessing in your example is only available with use of Capybara methods such as visit and click. By directly issuing the HTTP delete operation, you are bypassing Capybara and the setting of the page variable.
You can access the response body as response.body using your example, but note that the tutorial shows a test of sign-out at http://ruby.railstutorial.org/book/ruby-on-rails-tutorial#code-signout_test using a different request spec and Capybara's click method.
As I read the code, SessionsController#destroy redirects to static_pages#home which does not contain the string "Sign in"
in your spec you redirect to root_url after signout the user, so you should have the string "Sign in" in the root_url, just add for example <h1>Sign in</h1> to your root_url view and it will be passing, if your root url don't contains the form to sign in, in this case you should redirect to signin_path (wich will be contains the string "Sign in")
I am new to programming, this is my first application.
While creating an application in Rails, i have two models. User&list,nested.
resources :users do
resources :lists
end
These are the following routes i obtain with this setting:
user_lists GET /users/:user_id/lists(.:format) lists#index
POST /users/:user_id/lists(.:format) lists#create
new_user_list GET /users/:user_id/lists/new(.:format) lists#new
edit_user_list GET /users/:user_id/lists/:id/edit(.:format)lists#edit
user_list GET /users/:user_id/lists/:id(.:format) lists#show
PUT /users/:user_id/lists/:id(.:format) lists#update
DELETE /users/:user_id/lists/:id(.:format) lists#destroy
With regards i have created the views with the following links.
<div class="stats">
<a href="<%= user_lists_path(current_user) %>">
<%= pluralize(current_user.lists.count, 'List') %>
</a>
</div>
<div class="list">
<%= link_to 'Create List', new_user_list_path(current_user) %>
</div>
These work as expected, however when i use the same url helpers in testing i get an error.
describe "List create page" do
let(:user) { FactoryGirl.create(:user) }
before do
user.save
visit new_user_list_path(user)
end
it { should have_selector('title', text: 'SocialTask | List') }
it { should have_selector('h1', text: 'Create list') }
describe "invalid list creation" do
before { click_button 'Create list' }
it { should have_content('Error in creating list') }
end
end
This causes the tests to have an error.
Failure/Error: visit new_user_list_path(user)
NoMethodError:
undefined method `lists' for nil:NilClass
I have tried playing around with the url that did not work.
I tried updating rspec/capybara that did not work either.
I have also checked the inclusion of
config.include Rails.application.routes.url_helpers
in the spec helper.
How do i get the helpers to work? Or am i missing some minor detail?
Thanks in advance.
Helper Methods.
module SessionsHelper
def sign_in(user)
cookies.permanent[:remember_token] = user.remember_token
self.current_user = user
end
def current_user=(user)
#current_user = user
end
def current_user
#current_user ||= User.find_by_remember_token(cookies[:remember_token])
end
def signed_in?
!current_user.nil?
end
def sign_out
self.current_user = nil
cookies.delete(:remember_token)
end
def current_user?(user)
current_user == user
end
end
The rspec helper to sign in.
support/utilities.rb
include ApplicationHelper
def sign_in(user)
visit signin_path
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
cookies[:remember_token] = user.remember_token
end
Without seeing the stack trace, I think your problem is in the view on this line:
<%= pluralize(current_user.lists.count, 'List') %>
It seems like current_user is nil. Normally you should define some kind of helper method in your RSpec suite to simulate a user logging in. That way, current_user will return the user that you stub out in the test.
Here's an example:
# spec/support/session_helper.rb
module SessionHelper
def login(username = 'admin')
request.session[:user_id] = User.find_by_username(username).id
end
end
Yours will differ depending on how you authenticate your users. For example, Devise publishes its own set of test helpers, so you can simply include its helpers directly:
# spec/support/devise.rb
RSpec.configure do |config|
config.include Devise::TestHelpers, :type => :controller
end
Seems it's getting an error because the user doesn't exists. Try to change user.save to user.save! then you'll catch the error on creation I think..
I have a simple user login system:
module SessionsHelper
def logged_in?
current_user.present?
end
def current_user
#current_user ||= begin
if session[:current_user_id]
User.find(session[:current_user_id]) rescue nil
end
end
end
end
which I include in ApplicationController:
class ApplicationController < ActionController::Base
include SessionsHelper
helper SessionsHelper
I am trying to test the banners controller:
require 'spec_helper'
describe Admin::BannersController do
describe 'POST create' do
let(:user){ create(:user_admin) }
before do
controller.stub(:current_user){ user }
end
it "create action should render new template when model is invalid" do
Banner.any_instance.stubs(:valid?).returns(false)
post :create
response.should render_template(:new)
end
:user_admin is the properly set up Factory Girl admin user.
However the test still says: You are not authorized to access this page.
This is from Cancan.
Did I not stub it properly? Thanks.
def fake_user
user = FactoryGirl.build(:user, :id => 100000 + rand(100000))
stub(controller).current_user { user }
user
end