Created

Embed URL

HTTPS clone URL

SSH clone URL

You can clone with HTTPS or SSH.

Download Gist

Test Omniauth Facebook Callback Controllers in Devise with rspec

View gist:792715
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
require 'spec_helper'
 
describe Users::OauthCallbacksController, "handle facebook authentication callback" do
describe "#annonymous user" do
context "when facebook email doesn't exist in the system" do
before(:each) do
stub_env_for_omniauth
 
get :facebook
@user = User.where(:email => "ghost@nobody.com").first
end
 
it { @user.should_not be_nil }
 
it "should create authentication with facebook id" do
authentication = @user.authentications.where(:provider => "facebook", :uid => "1234").first
authentication.should_not be_nil
end
 
it { should be_user_signed_in }
 
it { response.should redirect_to tasks_path }
end
context "when facebook email already exist in the system" do
before(:each) do
stub_env_for_omniauth
User.create!(:email => "ghost@nobody.com", :password => "my_secret")
get :facebook
end
it { flash[:notice].should == "Your email ghost@nobody.com is already exist in the system. You need to sign in first."}
it { response.should redirect_to new_user_session_path }
end
end
describe "#logged in user" do
context "when user don't have facebook authentication" do
before(:each) do
stub_env_for_omniauth
 
user = User.create!(:email => "user@example.com", :password => "my_secret")
sign_in user
 
get :facebook
end
 
it "should add facebook authentication to current user" do
user = User.where(:email => "user@example.com").first
user.should_not be_nil
fb_authentication = user.authentications.where(:provider => "facebook").first
fb_authentication.should_not be_nil
fb_authentication.uid.should == "1234"
end
 
it { should be_user_signed_in }
 
it { response.should redirect_to authentications_path }
it { flash[:notice].should == "Facebook is connected with your account."}
end
context "when user already connect with facebook" do
before(:each) do
stub_env_for_omniauth
user = User.create!(:email => "ghost@nobody.com", :password => "my_secret")
user.authentications.create!(:provider => "facebook", :uid => "1234")
sign_in user
 
get :facebook
end
it "should not add new facebook authentication" do
user = User.where(:email => "ghost@nobody.com").first
user.should_not be_nil
fb_authentications = user.authentications.where(:provider => "facebook")
fb_authentications.count.should == 1
end
it { should be_user_signed_in }
it { flash[:notice].should == "Signed in successfully." }
it { response.should redirect_to tasks_path }
end
end
end
 
def stub_env_for_omniauth
# This a Devise specific thing for functional tests. See https://github.com/plataformatec/devise/issues/closed#issue/608
request.env["devise.mapping"] = Devise.mappings[:user]
env = { "omniauth.auth" => { "provider" => "facebook", "uid" => "1234", "extra" => { "user_hash" => { "email" => "ghost@nobody.com" } } } }
@controller.stub!(:env).and_return(env)
end

Why do you stub in the ominauth.auth field when you don't stub in Devise's hash as well?
You might as well just set in and shorten the call stack. Adding to that, the information you set from https://github.com/intridea/omniauth/wiki/Integration-Testing could be taken into play here.

I agree with @jalcine.
A safer approach would be request.env["omniauth.auth"] = env["omniauth.auth"] and so the stub_env_for_omniauth will be:

def stub_env_for_omniauth
  # This a Devise specific thing for functional tests. See https://github.com/plataformatec/devise/issues/closed#issue/608
  request.env["devise.mapping"] = Devise.mappings[:user]
  env = { "omniauth.auth" => { "provider" => "facebook", "uid" => "1234", "extra" => { "user_hash" => { "email" => "ghost@nobody.com" } } } }
  request.env["omniauth.auth"] = env["omniauth.auth"]
end
kakipo commented

It would be better to use OmniAuth::AuthHash.new in order to simulate the params; otherwise you could get errors if you accessed params in your code like request.env["omniauth.auth"].provider

def stub_env_for_omniauth
  # This a Devise specific thing for functional tests. See https://github.com/plataformatec/devise/issues/closed#issue/608
  request.env["devise.mapping"] = Devise.mappings[:user]

  request.env["omniauth.auth"] = OmniAuth::AuthHash.new({
    "provider"=>"facebook",
    "uid"=>uid,
    ...
  })
end
vfonic commented

Great tests! I used them in my project. Thanks!

Couple of tests I'd add would be to test when user rejects facebook authentication.

Also, here's another test I added, which is not necessarily needed, but I like to have it around:

it "should alias #facebook to #auth_all" do
  expect(Users::OauthCallbacksController.instance_method(:facebook)).to eq(Users::OauthCallbacksController.instance_method(:auth_all))
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.