Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rspec Capybara - Login(user) not working

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 "[email protected]" 
        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
like image 696
joeyk16 Avatar asked Mar 15 '23 20:03

joeyk16


1 Answers

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:

  1. If you're using Devise for authentication, Devise provides authentication helpers you should use.

  2. 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 => '[email protected]'
          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.

like image 87
madcow Avatar answered Mar 23 '23 06:03

madcow