Search code examples
ruby-on-railsrubyomniauthminitest

Using Omniauth for Rails I can't get current_user set when running my test


I'm trying to build an integration test for my application to perform the "sign in" function for a user. I'm currently using the omniauth-google-oauth2 gem. Everything seems to perform fine, except that I never get my "current_user" object set from the sign_in. The sign_in executes and returns a 302 message, and never goes through the sessions_controller#create action. Can anyone point me in the right direction, or let me know if perhaps I'm setting up my OmniAuth testing incorrectly?

test/integration/blog_flow_test.rb

require 'test_helper'

class BlogFlowTest < ActionDispatch::IntegrationTest
  include SignInHelper

  test "user can see the welcome page" do
    get "/"
    assert_select "h1#title", "Donut with my Coffee"
    assert_select "a#sign_in", "Sign in with Google"
  end

  test "author can create an article" do
    sign_in(admin=true)
    get "/posts/new"
    assert_response :success
  end

end

test/controllers/sessions_controller_test.rb

require 'test_helper'

class SessionsControllerTest < ActionDispatch::IntegrationTest

  setup do
    Rails.application.env_config["omniauth.auth"] = OmniAuth.config.mock_auth[:google_oauth2]
  end

  test "should get create" do
    get sessions_create_url
    assert_response :success
  end

  test "should get destroy" do
    get sessions_destroy_url
    assert_response :success
  end

end

app/controllers/sessions_controller.rb

class SessionsController < ApplicationController
  def create
    user = User.from_omniauth(request.env["omniauth.auth"])
    session[:user_id] = user.id
    redirect_to root_path
  end

  def destroy
    session[:user_id] = nil
    redirect_to root_path
  end
end

test/test_helper.rb

require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'

class ActiveSupport::TestCase

  fixtures :all
  OmniAuth.config.test_mode = true

  module SignInHelper

      def sign_in(admin=true)
        set_mock_auth(admin)        
        post "/auth/google_oauth2"
      end

      def set_mock_auth(admin)
        if admin
            OmniAuth.config.mock_auth[:google_oauth2] = 
                OmniAuth::AuthHash.new(auth_object_for_existing_user)
        else
            OmniAuth.config.mock_auth[:google_oauth2] = 
                OmniAuth::AuthHash.new(auth_object_for_new_user)
        end
      end

      private

        def auth_object_for_existing_user
            auth = {
              provider: "google_oauth2",
              uid: "123456789",
              info: {
                email: "papasmurf@example.com",
                first_name: "Papa",
                last_name: "Smurf"
              },
              credentials: {
                token: "abcdefg12345",
                refresh_token: "12345abcdefg",
                oauth_expires_at: DateTime.now
              }
            }
          end

          def auth_object_for_new_user
            auth = {
              provider: "google_oauth2",
              uid: "1337",
              info: {
                email: "drjones@example.com",
                first_name: "Indiana",
                last_name: "Jones"
              },
              credentials: {
                token: "abc123",
                refresh_token: "123abc",
                oauth_expires_at: DateTime.now
              }
            }
          end
    end
end

app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
  helper_method :current_user

  def current_user
    if session[:user_id]
        @current_user ||= User.find(session[:user_id])
    end
  end
end

Solution

  • You can stub the authenticated user as given below :

    before do
      let(:user) { build(:user) }
      allow(controller).to receive_messages(current_user: user)
    end