I asked a similar question before but I think I've gotten past my original error. Anyway I have a new fun failure that I'm having a blast trying to figure out (note the sarcasm). Here's my failure:
1) SessionsController#facebook_login should be valid
Failure/Error: get :facebook_login
NoMethodError:
undefined method `slice' for nil:NilClass
# ./app/models/user.rb:19:in `from_omniauth'
# ./app/controllers/sessions_controller.rb:22:in `facebook_login'
# ./spec/controllers/sessions_controller_spec.rb:96:in `block (3 levels) in <top (required)>'
sessions_controller_spec.rb
describe '#facebook_login' do
before(:each) do
valid_facebook_login_setup
request.env["omniauth.auth"] = OmniAuth.config.mock_auth[:facebook]
get :facebook_login
end
it "should be valid" do
expect(response).to be_success
end
it "should set user_id" do
expect(session[:user_id]).to be_true
end
end
sessions_controller.rb
def facebook_login
if request.env['omniauth.auth']
user = User.from_omniauth(env['omniauth.auth'])
session[:user_id] = user.id
redirect_back_or root_path
else
redirect_to root_path
end
end
omniauth_test_helper.rb
module OmniAuthTestHelper
def valid_facebook_login_setup
if Rails.env.test?
OmniAuth.config.test_mode = true
OmniAuth.config.mock_auth[:facebook] = OmniAuth::AuthHash.new({
provider: 'facebook',
uid: '123545',
info: {
first_name: "Andrea",
last_name: "Del Rio",
email: "[email protected]"
},
credentials: {
token: "123456",
expires_at: Time.now + 1.week
}
})
end
end
def facebook_login_failure
OmniAuth.config.mock_auth[:facebook] = :invalid_credentials
end
end
spec_helper.rb
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
config.include Capybara::DSL
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
config.infer_base_class_for_anonymous_controllers = false
config.order = "random"
config.include SessionTestHelper, type: :controller
config.include OmniAuthTestHelper, type: :controller
end
user.rb
class User < ActiveRecord::Base
def self.from_omniauth(auth)
where(auth.slice(:provider, :uid)).first_or_create do |user|
user.provider = auth.provider
user.uid = auth.uid
user.first_name = auth.info.first_name
user.last_name = auth.info.last_name
user.email = auth.info.email
user.password = auth.credentials.token
user.password_confirmation = auth.credentials.token
user.oauth_token = auth.credentials.token
user.oauth_expires_at = Time.at(auth.credentials.expires_at)
end
end
end
Any help would be really cool. Thanks guys!
Ok I left these tests pending but I finally came around to figuring this out. First, because it's a callback, it shouldn't be a controller test. It should be a request spec. So we're going to test that "/auth/facebook/callback" when given a mock will login a user.
spec/requests/user_sessions_request_spec.rb
require 'spec_helper'
describe "GET '/auth/facebook/callback'" do
before(:each) do
valid_facebook_login_setup
get "auth/facebook/callback"
request.env["omniauth.auth"] = OmniAuth.config.mock_auth[:facebook]
end
it "should set user_id" do
expect(session[:user_id]).to eq(User.last.id)
end
it "should redirect to root" do
expect(response).to redirect_to root_path
end
end
describe "GET '/auth/failure'" do
it "should redirect to root" do
get "/auth/failure"
expect(response).to redirect_to root_path
end
end
Here's the rspec helper
spec/support/omni_auth_test_helper
module OmniAuthTestHelper
def valid_facebook_login_setup
if Rails.env.test?
OmniAuth.config.test_mode = true
OmniAuth.config.mock_auth[:facebook] = OmniAuth::AuthHash.new({
provider: 'facebook',
uid: '123545',
info: {
first_name: "Gaius",
last_name: "Baltar",
email: "[email protected]"
},
credentials: {
token: "123456",
expires_at: Time.now + 1.week
},
extra: {
raw_info: {
gender: 'male'
}
}
})
end
end
end
Don't forget to include the module in your spec_helper