Rails: How To Test Omniauth In Your Sessions Controller
In my current project, I’ve implemented a Sign in with Github button using the Omniauth Github gem, which creates or finds the user and creates a user session. My sessions controller is currently very basic:
# sessions_controller.rb class SessionsController < ApplicationController def create auth = request.env["omniauth.auth"] user = User.find_by_provider_and_uid(auth["provider"], auth["uid"]) || User.create_with_omniauth(auth) session[:user_id] = user.id redirect_to root_url, :notice => "Signed in!" end def destroy session[:user_id] = nil redirect_to root_url, :notice => "Signed out!" end end
To see more details from my code, check out my Omniauth Github tutorial.
However, testing the sessions controller gets complicated, since you need to mock omniauth and add the “omniauth.auth” hash to the test request environment.
After doing some digging around, I found that Omniauth has a wiki page dedicated specifically to testing.
In your spec helper, just add the following code (with your own omniauth hash, which only has information you’re saving in your user model) :
OmniAuth.config.test_mode = true omniauth_hash = { 'provider' => 'github', 'uid' => '12345', 'info' => { 'name' => 'natasha', 'email' => 'hi@natashatherobot.com', 'nickname' => 'NatashaTheRobot' }, 'extra' => {'raw_info' => { 'location' => 'San Francisco', 'gravatar_id' => '123456789' } } } OmniAuth.config.add_mock(:github, omniauth_hash)
So your spec helper should look something like this:
# spec_helper.rb require 'rubygems' # This file is copied to spec/ when you run 'rails generate rspec:install' ENV["RAILS_ENV"] ||= 'test' require File.expand_path("../../config/environment", __FILE__) require 'rspec/rails' require 'rspec/autorun' OmniAuth.config.test_mode = true omniauth_hash = { 'provider' => 'github', 'uid' => '12345', 'info' => { 'name' => 'natasha', 'email' => 'hi@natashatherobot.com', 'nickname' => 'NatashaTheRobot' }, 'extra' => {'raw_info' => { 'location' => 'San Francisco', 'gravatar_id' => '123456789' } } } OmniAuth.config.add_mock(:github, omniauth_hash) # Requires supporting ruby files with custom matchers and macros, etc, # in spec/support/ and its subdirectories. Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f } # Checks for pending migrations before tests are run. # If you are not using ActiveRecord, you can remove this line. ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration) RSpec.configure do |config| # Add Factory Girl config.include FactoryGirl::Syntax::Methods # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures config.fixture_path = "#{::Rails.root}/spec/fixtures" # If you're not using ActiveRecord, or you'd prefer not to run each of your # examples within a transaction, remove the following line or assign false # instead of true. config.use_transactional_fixtures = true # If true, the base class of anonymous controllers will be inferred # automatically. This will be the default behavior in future versions of # rspec-rails. config.infer_base_class_for_anonymous_controllers = false # Run specs in random order to surface order dependencies. If you find an # order dependency and want to debug it, you can fix the order by providing # the seed, which is printed after each run. # --seed 1234 config.order = "random" end
Finally, whenever you need the Omniauth response hash, you can just use OmniAuth.config.mock_auth[:github] – I used this both in my sessions controller and in my user model specs. If you have the rspec-rails gem installed, your session controller spec file will look something like this:
# sessions_controller_spec.rb require 'spec_helper' describe SessionsController do before do request.env['omniauth.auth'] = OmniAuth.config.mock_auth[:github] end describe "#create" do it "should successfully create a user" do expect { post :create, provider: :github }.to change{ User.count }.by(1) end it "should successfully create a session" do session[:user_id].should be_nil post :create, provider: :github session[:user_id].should_not be_nil end it "should redirect the user to the root url" do post :create, provider: :github response.should redirect_to root_url end end describe "#destroy" do before do post :create, provider: :github end it "should clear the session" do session[:user_id].should_not be_nil delete :destroy session[:user_id].should be_nil end it "should redirect to the home page" do delete :destroy response.should redirect_to root_url end end end
Happy testing!