Is it possible to access session variables in Rspec with Capybara and Selenium drive?
How would I do something like this (I am using omniauth-facebook)?
require 'spec_helper'
describe 'Api' do
def login_with_oauth
visit "/auth/facebook"
end
it 'get location count for specific user' do
login_with_oauth
#user=User.find(session[:user_id])
#puts "here is response body: #{response.body}"
I see
How to inspect the session hash with Capybara and RSpec? but doesn't get me what I really want.
thx
I suppose to think what you actually don't need the session. I'm sorry if I'm wrong.
That's how you can test omniauth.
# spec/spec_helper.rb
OmniAuth.config.test_mode = true
OmniAuth.config.mock_auth[:facebook] = OmniAuth::AuthHash.new
OmniAuth.config.add_mock(:facebook, {
provider: "facebook",
uid: "123456",
info: {
email: "bruce.wayne#batman.com",
first_name: "Bruce",
last_name: "Wayne"
}
})
# spec/request/api_spec.rb
let!(:user) { create :user, email: "bruce.wayne#batman.com" }
before do
visit "/auth/facebook"
end
it 'get location count for specific user' do
user.id # contains your user id
end
Related
After following tutorials from internet of integration test of Google Login in Rails. I came to this. But it's not working.
# frozen_string_literal: true
require "rails_helper"
def stub_omniauth
OmniAuth.config.test_mode = true
OmniAuth.config.mock_auth[:google_oauth2] = OmniAuth::AuthHash.new({
provider: "google_oauth2",
uid: "12345678910",
info: {
email: "limsammy1#gmail.com",
first_name: "Sam",
last_name: "Lim"
},
credentials: {
token: "abcdefg12345",
refresh_token: "abcdefg12345",
expires_at: DateTime.now,
}
})
end
RSpec.feature "user logs in" do
scenario "using google oauth2" do
visit login_path
stub_omniauth
Rails.application.env_config["omniauth.auth"] = OmniAuth.config.mock_auth[:google_oauth2]
expect(page).to have_css("a.google-login-button")
find("a.google-login-button").click
expect(page.current_path).to eq(dashboard_path)
end
end
I am supposing that after running the test my page content would change but they are same as before.
I set up Pundit to guard a bunch of request paths, and it's working fine. In particular, if I hit /api/users/:id with a PATCH request, passing the relevant parameters, I get a 403 if I'm not authenticated. Then I wrote this spec
context 'When logged out' do
describe 'user update' do
before(:each) do
#new_user = FactoryBot.create(:user, password: 'testpassword')
end
it 'fails with PATCH' do
patch "/api/users/#{#new_user.id}", params: { given_name: 'Testing Alice' }
expect(response).to have_http_status(:forbidden)
end
end
end
but when I run rspec, I get the following failure:
1) When logged out user update fails with PATCH
Failure/Error: authorize #user
Pundit::NotAuthorizedError:
not allowed to update? this #<User id: 24, email: "nolanschinner#schuster.net", given_name: "Deja", family_name: "Schmeler", role: "USER", password_digest: "$2a$04$3lhKjBj2DfLymYnTfhDZV.IrlhPPxsPHIe.hI0lHdb1...", created_at: "2018-12-07 15:08:00", updated_at: "2018-12-07 15:08:00", verification_token: nil, email_verified: false, gender: nil>
# /Users/morpheu5/.rvm/gems/ruby-2.5.1/gems/pundit-2.0.0/lib/pundit.rb:209:in `authorize'
# ./app/controllers/api/v1/users_controller.rb:55:in `update'
# ...
The method being tested is right here.
As far as I can tell, Pundit raises the exception and this throws rspec into despair. How do I write this test so that it actually works?
The subject is a bit old but, for those still searching for the answer, you should write something like:
context 'When logged out' do
describe 'user update' do
before(:each) do
#new_user = FactoryBot.create(:user, password: 'testpassword')
end
it 'fails with PATCH' do
expect{patch "/api/users/#{#new_user.id}", params: { given_name: 'Testing Alice' }}.to raise_error(Pundit::NotAuthorizedError)
end
end
end
I'm using Auth0 for authentication in my rails app. I need to write some feature tests for login and signup. I can't seem to find something concrete on how to do this with rspec and capybara.
Tried doing something along the lines explained in this gist but it still doesn't work. If someone has had experience with rspec feature tests with Auth0 I'd appreciate if you would guide me in the right direction.
Thanks!
My configuration
# in spec/support/omniauth_macros.rb
module OmniauthMacros
def mock_auth_hash
# The mock_auth configuration allows you to set per-provider (or default)
# authentication hashes to return during integration testing.
OmniAuth.config.mock_auth[:auth0] = {
'provider' => 'auth0',
'uid' => '123545',
'user_info' => {
'name' => 'mockuser',
'image' => 'mock_user_thumbnail_url'
},
'credentials' => {
'token' => 'mock_token',
'secret' => 'mock_secret'
}
}
end
end
# in spec/requests/spec_helper.rb
RSpec.configure do |config|
# ...
# include our macro
config.include(OmniauthMacros)
end
OmniAuth.config.test_mode = true
Then in my spec I have
scenario 'Should successfully login user' do
visit login_path
mock_auth_hash
click_link "Sign in"
expect(page).to have_content('Signed in successfully')
expect(page).to have_link("Logout", href: logout_path)
end
This is how I solved it
# in spec/support/omniauth_macros.rb
module OmniauthMacros
def mock_valid_auth_hash(user)
# The mock_auth configuration allows you to set per-provider (or default)
# authentication hashes to return during integration testing.
opts = {
"provider": user.provider,
"uid": user.uid,
"info": {
"email": user.email,
"first_name": user.first_name,
"last_name": user.last_name,
},
"credentials": {
"token": "XKLjnkKJj7hkHKJkk",
"expires": true,
"id_token": "eyJ0eXAiOiJK1VveHkwaTFBNXdTek41dXAiL.Wz8bwniRJLQ4Fqx_omnGDCX1vrhHjzw",
"token_type": "Bearer"
}
}
OmniAuth.config.mock_auth[:auth0] = OmniAuth::AuthHash.new(opts)
end
def mock_invalid_auth_hash
OmniAuth.config.mock_auth[:auth0] = :invalid_credentials
end
end
# in spec/support/features/session_helpers.rb
module Features
module SessionHelpers
def log_in(user, invalid=false, strategy = :auth0)
invalid ? mock_invalid_auth_hash : mock_valid_auth_hash(user)
Rails.application.env_config["omniauth.auth"] = OmniAuth.config.mock_auth[strategy.to_sym]
visit "/auth/#{strategy.to_s}/callback?code=vihipkGaumc5IVgs"
end
end
end
# in spec/support/rails_helper.rb
RSpec.configure do |config|
# ...
# include our macro
config.include(OmniauthMacros)
# include Session helpers
config.include Features::SessionHelpers, type: :feature
end
And finally my feature test to simulate login looks like
# user signin feature test
require 'rails_helper'
feature 'Login with Omniauth' do
given(:user) { create(:user) }
context "With valid credentials" do
scenario 'Should successfully login user' do
log_in(user)
expect(page).to have_content("successfully signed in")
expect(page).to have_link("Logout", href: logout_path)
end
end
context "With invalid credentials" do
scenario "Should not log in user" do
log_in(user, true)
expect(page).to have_content('invalid_credentials')
end
end
end
Hope this helps!
I'm writing RSpec tests for my SessionsController. My tests work fine when testing session#create with valid credentials. However, I want to also write tests for what happens when the users credentials are invalid, such as redirecting back to the sign in page, setting a flash alert, etc. But for any of these tests, I'm getting an error:
1) SessionsController POST #create when password is INCORRECT
Failure/Error: post :create, user: {username: 'Example', password: ''}
ArgumentError:
uncaught throw :warden
# ./spec/support/default_params.rb:7:in `process_with_default_params'
# ./spec/controllers/sessions_controller_spec.rb:24:in `block (4 levels) in <top (required)>'
Here's my sessions_controller_spec.rb code:
require 'spec_helper'
describe SessionsController do
before do
#request.env["devise.mapping"] = Devise.mappings[:user]
end
describe 'POST #create' do
context "when password is INCORRECT" do
let!(:user) { FactoryGirl.create(:user, username: 'Example', password: 'Secr3t&$') }
before(:each) do
post :create, user: { username: 'Example', password: '' }
end
it { should set_the_flash[:alert].to('Invalid username or password.') }
it { should respond_with(:redirect) }
it { should redirect_to(:new_user_session) }
end
end
Here's my spec_helper.rb code:
RSpec.configure do |config|
config.include Devise::TestHelpers, type: :controller
end
Any help would be much appreciated. Thanks!
I know it is too late now but in case this helps someone else: you need to add setup_controller_for_warden to your before block, so it becomes:
before do
#request.env["devise.mapping"] = Devise.mappings[:user]
setup_controller_for_warden
end
Also it would be better to use the translation for you assertion. In rspec 3 format, the assertion should like this:
expect(flash[:alert]).to eq(I18n.t('devise.failure.invalid'))
Following the Railscast on Devise and OmniAuth I have implemented an OmniauthCallbacksController < Devise::OmniauthCallbacksController which contains a single method to handle an OmniAuth callback:
def all
user = User.from_omniauth(request.env["omniauth.auth"])
if user.persisted?
sign_in_and_redirect user
else
session["devise.user_attributes"] = user.attributes
redirect_to new_user_registration_url
end
end
alias_method :facebook, :all
routes.rb:
devise_for :users, controllers: {omniauth_callbacks: "omniauth_callbacks", :sessions => "sessions" }
I would like to customise this, so I'm trying to test it using RSpec. The question is how do I test this method and the redirects?
If in the spec I put user_omniauth_callback_path(:facebook) it doesn't complain about the route not existing, but doesn't seem to actually call the method.
According to this answer "controller tests use the four HTTP verbs (GET, POST, PUT, DELETE), regardless of whether your controller is RESTful." I tried get user_... etc. but here it does complain that the route doesn't exist. And indeed if I do rake routes it shows there is no HTTP verb for this route:
user_omniauth_callback [BLANK] /users/auth/:action/callback(.:format) omniauth_callbacks#(?-mix:facebook)
Can you see what I'm missing?
EDIT
So following this question one way of calling the method is:
controller.send(:all)
However I then run into the same error that the questioner ran into:
ActionController::RackDelegation#content_type delegated to #_response.content_type, but #_response is nil
You will need to do three things to get this accomplished.
enter OmniAuth test environment
create an OmniAuth test mock
stub out your from_omniauth method to return a user
Here is a possible solution, entered in the spec itself
(spec/feature/login_spec.rb for example) . . .
let(:current_user) { FactoryGirl.create(:user) }
before do
OmniAuth.config.test_mode = true
OmniAuth.config.mock_auth[:facebook] = OmniAuth::AuthHash.new({
provider: :facebook,
uid:'12345',
info: {
name: "Joe"
}
})
User.stub(:from_omniauth).and_return(current_user)
end
I adapted this from a google authentication, so facebook may require more fields, but those are the only ones required by omniauth docs. You should be able to find the correct fields by looking at your database schema and finding fields that match the documentation.
In my case, the minimum was enough to pass the request phase and move onto the stubbed out method returning my user.
This example also uses FactoryGirl.
It may not be perfect, but I hope it helps. Good luck!
-Dan
If you hit this and you are running rspec 3.4 this example should work for you:
describe Users::OmniauthCallbacksController, type: :controller do
let(:current_user) { FactoryGirl.create(:user) }
before do
OmniAuth.config.test_mode = true
OmniAuth.config.mock_auth[:your_oauth_provider_here] = OmniAuth::AuthHash.new(
provider: :your_oauth_provider_here,
uid: rand(5**10),
credentials: { token: ENV['CLIENT_ID'], secret: ENV['CLIENT_SECRET'] }
)
request.env['devise.mapping'] = Devise.mappings[:user]
allow(#controller).to receive(:env) { { 'omniauth.auth' => OmniAuth.config.mock_auth[:your_oauth_provider_here] } }
allow(User).to receive(:from_omniauth) { current_user }
end
describe '#your_oauth_provider_here' do
context 'new user' do
before { get :your_oauth_provider_here }
it 'authenticate user' do
expect(warden.authenticated?(:user)).to be_truthy
end
it 'set current_user' do
expect(current_user).not_to be_nil
end
it 'redirect to root_path' do
expect(response).to redirect_to(root_path)
end
end
end
end
I am experiencing problem for writhing RSpec for OmniauthCallbacksController, do some research on this and it working for me. Here is my codes, if anyone found necessary. Tests are for happy path and it should work for news version of RSpec eg. 3.x
require 'spec_helper'
describe OmniauthCallbacksController, type: :controller do
describe "#linkedin" do
let(:current_user) { Fabricate(:user) }
before(:each) do
OmniAuth.config.test_mode = true
OmniAuth.config.mock_auth[:linkedin] = OmniAuth::AuthHash.new({provider: :linkedin, uid: '12345', credentials: {token: 'linkedin-token', secret: 'linkedin-secret'}})
request.env["devise.mapping"] = Devise.mappings[:user]
#controller.stub!(:env).and_return({"omniauth.auth" => OmniAuth.config.mock_auth[:linkedin]})
User.stub(:from_auth).and_return(current_user)
end
describe "#linkedin" do
context "with a new linkedin user" do
before { get :linkedin }
it "authenticate user" do
expect(warden.authenticated?(:user)).to be_truthy
end
it "set current_user" do
expect(subject.current_user).not_to be_nil
end
it "redirect to root_path" do
expect(response).to redirect_to(root_path)
end
end
end
end
end