1

Following Railscast #385 & #386 I have added authorization to my Rails 4 application (rails 4.2.6, rspec-rails 3.4.2). After adding authorization, all of my controller specs fail.

My feature specs still pass because in the spec I login as admin to perform actions that are not allowed visitors (:edit, :update...). If I make all actions allowed to a visitor my controller specs pass. However, any action that only the admin can perform will fail in the controller spec.

The scaffold generator creates an empty

  let(:valid_session) { { } }

that it says in the comments:

# This should return the minimal set of values that should be in the session in order to pass any filters (e.g. authentication) defined in MyController.

However, I don't know how to configure this :valid_session to allow authentication to pass.

When I try the solution posted in this question:

def valid_session
  controller.stub!(:signed_in?).and_return(true)
end

I get this error:

NoMethodError:
        undefined method `stub' for #<MyController

Since, all of the many branching paths of logic should be tested at a lower level (ie the controller spec) rather than the feature spec, how do I get the controller specs to pass?

How do I configure valid_session or what other method can I use to pass authorization in my controller specs?

1
  • can't seem to post code sample here so posting answer. Commented Oct 5, 2016 at 20:00

2 Answers 2

3

Ok, with the help of this blog I was able to get my controller tests to pass after adding authorization to the controllers.

In spec/support/helpers/controller_macros.rb I defined these methods:

module ControllerMacros
  def login_admin
    user = FactoryGirl.create(:admin)
    allow(controller).to receive(:current_user).and_return(user)
  end
  def login_member
    user = FactoryGirl.create(:member)
    allow(controller).to receive(:current_user).and_return(user)
  end
  def login_visitor
    allow(controller).to receive(:current_user).and_return(nil)
  end
end

To activate those methods in spec/support/helpers.rb:

RSpec.configure do |config|
  config.include ControllerMacros, type: :controller
end

And then implement it in the controller spec, spec/controllers/topics_controller_spec.rb:

require 'rails_helper'
RSpec.describe TopicsController, type: :controller do
  let(:valid_attributes) {
    { :name => "MyTopic" }
  }
  let(:invalid_attributes) {
    { :name => nil }
  }
  before(:each) do
    login_admin
  end
  describe "GET #index" do
    it "assigns all topics as @topics" do
      login_visitor
      topic = Topic.create! valid_attributes
      get :index, {}
      expect(assigns(:topics)).to eq([topic])
    end
  end
  describe "GET #show" do
    it "assigns the requested topic as @topic" do
      login_visitor
      topic = Topic.create! valid_attributes
      get :show, {:id => topic.to_param}
      expect(assigns(:topic)).to eq(topic)
    end
  end
  describe "GET #new" do
    it "assigns a new topic as @topic" do
      get :new, {}
      expect(assigns(:topic)).to be_a_new(Topic)
    end
  end
[...]
end

This will login as admin before each test. Note that you should test each action at the lowest level that has permission, so show and index are tested as a visitor (not-logged in). If all actions need admin permission then you can use before do instead of before(:each) do to save a little time in the tests.

Finally you must remove all mention of valid_session from the spec.

Sign up to request clarification or add additional context in comments.

Comments

0

You could just factory a user.

module ControllerMacros
  def login_user(user = nil, options = {})
    before(:each) do
    @request.env["devise.mapping"] = Devise.mappings[:user]
    @user = user || FactoryGirl.create(options[:user] || :user)
    sign_in @user
  end
end

7 Comments

Thank you Jason, but I am not using Devise, so I don't have the sign_in function available to me. Also, where would I use the code you provided? How would I call it from the controller spec?
The code would be added to a support folder in a class in your spec folder. You could create this then just ensure it is being loaded in. If you aren't using devise then you should be able to macro whatever means you use for logging in the user anyways.
"should be able to macro" not really sure what this means. Could you point to an example>
I would have to see what you are doing for the actual authentication to be able to give you some sort of example.
I put the relevant files in this Gist: gist.github.com/mattmartini/45ed2056c5703c0ef6498cfbf6f19714 I included the controllers for application, users, sessions, and ranks. Ranks are a simple resouce with just a few fields that I am trying to get to have the controller specs pass. Also I have included the permisson model: permission loader, and permission files for each role: admin, captain, student, guest, visitor (visitors have not signed in, all other have) Finally, I included the ranks controller spec.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.