0
votes

I have a Rails 3.2 app with Devise and CanCan. User abilities are defined by roles. There are five Roles in the database with id values 1-5, and a User has_one role through a Membership. So, for example, Membership.create(user_id: 2, role_id: 4) will lead to User.find(2).role == Role.find(4) # => true

My ability file looks like

if user.has_role? :admin
  can :manage, Model
  can :manage, AnotherModel
  # etc.
elsif user.has_role? :basic
  can :read, Model
  can :read, AnotherModel
elsif user.has_role? (etc. for other roles)
  (etc.)
else
  cannot :manage, :all

I want to kick out people who are attempting to access pages they are not authorized for. My application controller includes:

rescue_from CanCan::AccessDenied do |exception|
  reset_session
  redirect_to new_user_session_path
end

This behavior works properly when clicking around in development—-a basic user created via rails console gets kicked out when trying to do admin things, and a user with no roles (created in console, then User.last.membership.destroy so that User.last.role # => nil) cannot log in to the dashboard--instead the user is immediately redirected to the login page (a User with no role cannot manage anything).

I'm having problems when trying to test this same behavior, specifically for users with no role:

# spec/support/login_helpers.rb
def login_via_sign_in_page(user)
  visit new_user_session_path
  fill_in :user_email, with: user.email
  fill_in :user_password, with: user.password
  click_button 'Sign in'
end

# spec/features/dashboard_spec.rb
describe "as a user with no role" do
  let(:user) { FactoryGirl.create(:user) }

  before { login_via_sign_in_page(user) }

  it "should redirect to the sign_in page" do
    current_path.should == new_user_session_path
  end
end

The above test fails, with RSpec showing that the user successfully made it to the dashboard page instead of being redirected to the sign in page. However, the following specs do pass:

# spec/features/dashboard_spec.rb
describe "as a guest browser (no login whatsoever)" do
  it "should redirect to the sign_in page" do
    visit dashboard_index_path
    current_path.should == new_user_session_path
  end
end

describe "as an admin user" do
  let(:user) { FactoryGirl.create(:admin_user) }

  before { login_via_sign_in_page(admin_user) }

  it "should go to the dashboard" do
    visit dashboard_index_path
    current_path.should == dashboard_index_path
  end
end

...as well as things like basic user getting redirected to the sign_in page when attempting admin actions

I have read this post, which seems to be dealing with a similar issue, but the suggestions there have not helped.

Finally, I get confusing results when using debugger and save_and_open_page. The former will give me user # => <A legit User object> and user.role # => nil. However, save_and_open_page shows me logged in on the dashboard page.

1

1 Answers

0
votes

Have you tried including the Warden::Test::Helpers, and the rest of the config required for testing Devise with Capybara? Take a look here How To: Test with Capybara. Which driver are you using?