Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rspec: Test redirects in Devise::OmniauthCallbacksController subclass

Following the Railscast on Devise and OmniAuth I have implemented an OmniauthCallbacksController < Devise::OmniauthCallbacksController which contains a single method to handle an OmniAuth callback:

def all
  user = User.from_omniauth(request.env["omniauth.auth"])
  if user.persisted?
    sign_in_and_redirect user
  else
    session["devise.user_attributes"] = user.attributes
    redirect_to new_user_registration_url
  end
end
alias_method :facebook, :all

routes.rb:

devise_for :users, controllers: {omniauth_callbacks: "omniauth_callbacks", :sessions => "sessions" }

I would like to customise this, so I'm trying to test it using RSpec. The question is how do I test this method and the redirects?

If in the spec I put user_omniauth_callback_path(:facebook) it doesn't complain about the route not existing, but doesn't seem to actually call the method.

According to this answer "controller tests use the four HTTP verbs (GET, POST, PUT, DELETE), regardless of whether your controller is RESTful." I tried get user_... etc. but here it does complain that the route doesn't exist. And indeed if I do rake routes it shows there is no HTTP verb for this route:

user_omniauth_callback [BLANK] /users/auth/:action/callback(.:format) omniauth_callbacks#(?-mix:facebook)

Can you see what I'm missing?

EDIT

So following this question one way of calling the method is:

controller.send(:all)

However I then run into the same error that the questioner ran into:

ActionController::RackDelegation#content_type delegated to @_response.content_type, but @_response is nil
like image 211
Derek Hill Avatar asked May 08 '13 20:05

Derek Hill


2 Answers

You will need to do three things to get this accomplished.

  • enter OmniAuth test environment
  • create an OmniAuth test mock
  • stub out your from_omniauth method to return a user

Here is a possible solution, entered in the spec itself (spec/feature/login_spec.rb for example) . . .

let(:current_user) { FactoryGirl.create(:user) }

before do
  OmniAuth.config.test_mode = true
  OmniAuth.config.mock_auth[:facebook] = OmniAuth::AuthHash.new({
    provider: :facebook,
    uid:'12345',
    info: {
      name: "Joe"
    }
  })
  User.stub(:from_omniauth).and_return(current_user)
end

I adapted this from a google authentication, so facebook may require more fields, but those are the only ones required by omniauth docs. You should be able to find the correct fields by looking at your database schema and finding fields that match the documentation.

In my case, the minimum was enough to pass the request phase and move onto the stubbed out method returning my user.

This example also uses FactoryGirl.

It may not be perfect, but I hope it helps. Good luck!

-Dan

like image 100
Dan Williams Avatar answered Oct 22 '22 12:10

Dan Williams


If you hit this and you are running rspec 3.4 this example should work for you:

describe Users::OmniauthCallbacksController, type: :controller do
  let(:current_user) { FactoryGirl.create(:user) }

  before do
    OmniAuth.config.test_mode = true
    OmniAuth.config.mock_auth[:your_oauth_provider_here] = OmniAuth::AuthHash.new(
      provider: :your_oauth_provider_here,
      uid: rand(5**10),
      credentials: { token: ENV['CLIENT_ID'], secret: ENV['CLIENT_SECRET'] }
    )
    request.env['devise.mapping'] = Devise.mappings[:user]
    allow(@controller).to receive(:env) { { 'omniauth.auth' => OmniAuth.config.mock_auth[:your_oauth_provider_here] } }
    allow(User).to receive(:from_omniauth) { current_user }
  end

  describe '#your_oauth_provider_here' do
    context 'new user' do
      before { get :your_oauth_provider_here }

      it 'authenticate user' do
        expect(warden.authenticated?(:user)).to be_truthy
      end

      it 'set current_user' do
        expect(current_user).not_to be_nil
      end

      it 'redirect to root_path' do
        expect(response).to redirect_to(root_path)
      end
    end
  end
end
like image 3
Chris Hough Avatar answered Oct 22 '22 13:10

Chris Hough