简体   繁体   中英

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

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.

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 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM