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