Question: undefined method `provider' for nil:NilClass, RSpec, OmniAuth

Question

undefined method `provider' for nil:NilClass, RSpec, OmniAuth

Answers 1
Added at 2017-01-04 23:01
Tags
Question

I'm trying to test an authenticated controller with RSpec and OmniAuth. I've followed the integration testing guide on their wiki. When I run the test, I get the following error:

Failure/Error:
       where(provider: auth.provider, uid: auth.uid).first_or_initialize.tap 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.picture = auth.info.image
        user.save!
       end

     NoMethodError:
       undefined method `provider' for nil:NilClass

All relevant code is provided in this gist. My hunch is that the mock auth hash isn't being set somehow but I have no way of verifying that. I configure OmniAuth in config/environments/test.rb as shown in the Gist, and I'm pretty sure that file is ran when the application boots.

Answers to

undefined method `provider' for nil:NilClass, RSpec, OmniAuth

nr: #1 dodano: 2017-01-05 04:01

There are a couple issues that I see. For one, you're not testing the action of signing-in. You're hitting a controller action with oauth data in the request and expecting it to pass authentication. Oauth data isn't like an API key and won't let you auto sign-in like that. You have to hit the specific signin action provided by omniauth which then sets-up your user's session. This should be tested on its own to confirm that your whole oauth sign-in strategy works as expected. If you're testing controller actions that are not directly related to the act of oauth signins, then you should be using the devise test helpers to sign-in users before running tests that would require authentication.

Also, you don't want to be setting the OmniAuth configuration in an environment initialiser. The documentation suggests, and what I do myself, is set the configuration down in the tests. For one thing, this allows you to test different kinds of scenarios. For example, this is how I test that my omniauth callback controllers are working and doing what I want:

context 'with valid google credentials' do
  # this should actually be created in a factory
  let(:provider) { :google_oauth2 }
  let(:oauth) { OmniAuth::AuthHash.new provider: provider, uid: '1234' }
  before do
    OmniAuth.config.test_mode = true
    OmniAuth.config.mock_auth[provider] = oauth
  end

  it 'creates a new user' do
    expect { visit "/users/auth/#{provider}" }.to change(User, :count).by(1)
  end
end 
Source Show
◀ Wstecz