简体   繁体   中英

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

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

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

I am experiencing problem for writhing RSpec for OmniauthCallbacksController , do some research on this and it working for me. Here is my codes, if anyone found necessary. Tests are for happy path and it should work for news version of RSpec eg. 3.x RSpec eg. 3.x

   require 'spec_helper'

    describe OmniauthCallbacksController, type: :controller do
      describe "#linkedin" do
        let(:current_user) { Fabricate(:user) }

        before(:each) do
          OmniAuth.config.test_mode = true
          OmniAuth.config.mock_auth[:linkedin] = OmniAuth::AuthHash.new({provider: :linkedin, uid: '12345', credentials: {token: 'linkedin-token', secret: 'linkedin-secret'}})
          request.env["devise.mapping"] = Devise.mappings[:user]

          @controller.stub!(:env).and_return({"omniauth.auth" => OmniAuth.config.mock_auth[:linkedin]})
          User.stub(:from_auth).and_return(current_user)
        end

        describe "#linkedin" do
          context "with a new linkedin user" do
            before { get :linkedin }

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

            it "set current_user" do
              expect(subject.current_user).not_to be_nil
            end

            it "redirect to root_path" do
              expect(response).to redirect_to(root_path)
            end
          end
        end

      end
    end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM