Unable to pass session variables to RSpec controller - ruby-on-rails

I'm testing confirmation method from a controller using RSpec, it seems like tests crush because I can't pass session variables when addressing the method.
Here's my spec:
RSpec.describe OauthCallbacksController, type: :controller do
describe 'POST #confirm_email' do
before do
request.env["devise.mapping"] = Devise.mappings[:user]
end
context 'confirms_email' do
let(:email) { 'test-email#test.ru' }
let(:confirm_email) { post :confirm_email, params: { email: email }, session: { auth: { uid: '12345', provider: 'facebook' } } }
it 'redirects to new_user_session_path' do
confirm_email
expect(response).to redirect_to new_user_session_path
end
it 'sends an email' do
expect { confirm_email }.to change{ ActionMailer::Base.deliveries.count }.by(1)
end
end
end
end
Method confirm_email:
def confirm_email
puts params[:email]
pending_user = User.find_or_init_skip_confirmation(params[:email])
if pending_user
aut = Authorization.where(provider: session[:auth]['provider'], uid: session[:auth]['uid'], linked_email: params[:email])
.first_or_initialize do |auth|
auth.user = pending_user
auth.confirmation_token = Devise.friendly_token[0, 20],
auth.confirmation_sent_at = Time.now.utc
end
if aut.save
OauthMailer.send_confirmation_letter(aut).deliver_now
redirect_to root_path, notice: "Great! Now confirm your email, we've sent you a letter!"
else
redirect_to root_path, alert: "Something went wrong. Please try again later or use another sign in method"
end
end
end
When I try to display session variables they are nil, In test.log it's obvious that there should be session variables are NULL-s.
[34mSELECT "authorizations".* FROM "authorizations" WHERE "authorizations"."provider" IS NULL AND "authorizations"."uid" IS NULL AND "authorizations"."linked_email" = $1 ORDER BY "authorizations"."id" ASC LIMIT $2[0m [["linked_email", "test-email#test.ru"], ["LIMIT", 1]]
I use Rails 5.2.2.1 and RSpec 3.8.
I've read that in Rails 5 there's a problem accessing sessions, I've already tried setting it with controller.session[:auth]['uid'] or
request.session[:auth]['uid'] but nothing

Something strange is happening in rails or rack but with a nested session, the keys are available as symbols. This should work
Authorization.where(provider: session[:auth][:provider], uid: session[:auth][:uid], linked_email: params[:email])

I managed to pass session parameters using request.env["omniauth.auth"] = mock_auth_hash(:facebook) and when instead of passing hash I've passed request to the session. It did the job.
Now my spec looks like this.
describe 'POST #confirm_email' do
before do
request.env["devise.mapping"] = Devise.mappings[:user]
request.env["omniauth.auth"] = mock_auth_hash(:facebook)
get :facebook
end
let(:confirm_email) { post :confirm_email, params: { email: 'mockuser#test.com'}, session: { auth: request.env["omniauth.auth"] } }
it 'redirects to root_path' do
confirm_email
expect(response).to redirect_to root_path
end
it 'sends an email' do
request.env["devise.mapping"] = Devise.mappings[:user]
request.env["omniauth.auth"] = mock_auth_hash(:facebook)
get :facebook
expect { confirm_email }.to change{ ActionMailer::Base.deliveries.count }.by(1)
end
end

Related

Google Omniauth2 Rails Giving me "Example User" when testing

I am attempting to stub out an omniauth authentication hash to test my integration with RSpec. For some reason my User model is being fed an "Example User," that does not have all the info a regular signed in Google user would have.
This is the param given to User that is breaking the tests: {"provider"=>"default", "uid"=>"1234", "info"=>{"name"=>"Example User"}}
This is what it should be, and if I step to the next iteration with pry, it works:
{:provider=>"google",
:uid=>"12345678910",
:info=>{:email=>"limsammy1#gmail.com", :first_name=>"Sam", :last_name=>"Lim"},
:credentials=>{:token=>"abcdefg12345", :refresh_token=>"12345abcdefg", :expires_at=>Thu, 16 Nov 2017 15:27:23 -0700}}
Here is my spec:
require 'rails_helper'
def stub_omniauth
OmniAuth.config.test_mode = true
OmniAuth.config.mock_auth[:google] = 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 'omniauth'" do
stub_omniauth
visit root_path
expect(page).to have_link("Sign in with Google")
click_link "Sign in with Google"
expect(page).to have_content("Sam Lim")
expect(page).to have_content("Logout")
end
end
And here is my User model method:
def self.update_or_create(auth)
user = User.find_by(uid: auth[:uid]) || User.new
binding.pry
user.attributes = {
provider: auth[:provider],
uid: auth[:uid],
email: auth[:info][:email],
first_name: auth[:info][:first_name],
last_name: auth[:info][:last_name],
token: auth[:credentials][:token],
refresh_token: auth[:credentials][:refresh_token],
oauth_expires_at: auth[:credentials][:expires_at]
}
user.save!
user
end
I call that method in my sessions controller here:
def create
user = User.update_or_create(request.env["omniauth.auth"])
session[:id] = user.id
redirect_to root_path
end
I came across exactly this issue some days ago.
The problem is in def stub_omniauth.
You should change OmniAuth.config.mock_auth[:google] => OmniAuth.config.mock_auth[:google_oauth2]

Rspec Create Post with nested parameters

I'm trying to fix some tests that I have written in my comments controller. As of now, with my current tests I get this error:
Failure/Error: #outlet = Outlet.find(params[:comment][:outlet_id])
ActiveRecord::RecordNotFound:
Couldn't find Outlet with 'id'=
Here is an example of some of the tests
describe '#create' do
context 'with valid attributes' do
before :each do
#outlet = FactoryGirl.create(:outlet)
#user = FactoryGirl.create(:user)
#comment_params = FactoryGirl.attributes_for(:comment)
end
let(:create) { post :create, params: { outlet_id: #outlet.id, user_id: #user.id, comment: #comment_params } }
it "creates new comment" do
expect { create }.to change { Comment.count }.by(1)
end
it "increases the post comment count by 1" do
expect { create }.to change { #outlet.comments.count }.by(1)
end
it "increases user comment count by 1" do
expect { create }.to change { #user.comments.count }.by(1)
end
end
end
I'm pretty sure this is happening because of my create statement in my tests
let(:create) { post :create, params: { outlet_id: #outlet.id, user_id: #user.id, comment: #comment_params } }
Here is my comments controller create action
def create
#outlet = Outlet.find(params[:comment][:outlet_id])
#comment = #outlet.comments.build(comment_params)
#comment.user_id = current_user.id
if #comment.save
redirect_to(#outlet)
end
end
I'm pretty sure it is not working, because the outlet_id that it is looking for is a nested parameter inside of the comments parameter. How would I fix my rspec test to have it look for a nested parameter?
Just pass your params as arguments to the post call, nesting as necessary, e.g.:
post :create, user_id: #user.id, comment: { outlet_id: #outlet.id }

What could be possible test cases for this controller action and how can i handle if else conditions. Using minitest framework in RubyonRails

I am new to writing test cases and I cant figure out the scenarios of writing tests. For example there are too many if else conditions in controller how would I write cases for these conditions. Below is my registration controller. I am using rails minitest framework for rails 3.2.1 version.
def create
invitation_token = params["invitation_token"]
#Check if the user exists yet based on their e-mail address.
user = User.find_by_email(params[:user][:email])
omni = session[:omniauth] || params[:omniauth]
theme_id = nil
theme_layout_id = nil
theme_style_id = nil
begin
omni = JSON.parse omni if omni
rescue => e
# if we got here, the omni is invalid!!
return redirect_to '/login'
end
#Did we find a user yet? If not, perform the following.
if user.nil? && !invitation_token.present?
client = Client.find_or_create_by_name(name: params[:user][:username])
#p client.errors
if client.present?
user = User.new
app_url = ApplicationUrl.find_by_domain_url(request.host_with_port)
user.apply_omniauth(omni)
user.email = params[:user][:email]
user.username = params[:user][:username]
user.client_id = client.id
#Assign the user/client the Free plan by default.
plan = ClientPlan.find_or_create_by_client_id(client_id: client.id, plan_id: 1, plan_billing_cycle_id: 1, start_date: Date.today, is_paid: 1, isactive: 1)
#Set the client settings to the defaults for a Free (non business plan) user.
ClientSetting.create(client_id: client.id, is_billboard_enabled: 0, is_tweetback_enabled: 0, is_conversations_enabled: 0)
#Set the client environment link.
ClientsEnvironment.create(environment_id: environment.id, client_id: client.id)
unless params[:user][:theme_id].nil?
theme_id = params[:user][:theme_id]
puts "theme id: " + theme_id.to_s
end
unless params[:user][:theme_layout_id].nil?
theme_layout_id = params[:user][:theme_layout_id]
puts "theme layout id: " + theme_layout_id.to_s
end
unless params[:user][:theme_style_id].nil?
theme_style_id = params[:user][:theme_style_id]
puts "theme style id: " + theme_style_id.to_s
end
#Create an application for the client.
Application.find_or_create_by_client_id(
client_id: client.id,
name: params[:user][:username],
callback_url: "#{request.host_with_port}",
application_url_id: app_url.id
)
#Create the default feed for the client.
Feed.find_or_create_by_client_id(
client_id: client.id,
name: 'My Feed',
token: SecureRandom.uuid,
theme_id: theme_id,
theme_style_id: theme_style_id,
theme_layout_id: theme_layout_id
)
if user.save
#Remember me?
if params[:remember_me]
user.remember_me!
end
client = user.client
client.update_attribute(:owner_user_id, user.id)
schedule_reminder_email(user)
#Create the users Profile
Profile.find_or_create_by_user_id(
user_id: user.id,
fullname: params[:user][:fullname],
username: params[:user][:username]
)
record_event_profile(user,params[:user][:fullname],params[:remember_me])
end
end
elsif user.nil? && invitation_token.present?
user = User.new
invite = Invite.find_by_token(invitation_token)
if invite.present?
client = invite.client
user.apply_omniauth(omni)
user.email = params[:user][:email]
user.username = params[:user][:username]
user.client_id = client.id
user.can_curate = false
user.can_publish = false
if user.save
#Remember me?
if params[:remember_me]
user.remember_me!
end
#Create the users Profile
Profile.find_or_create_by_user_id(
user_id: user.id,
fullname: params[:user][:fullname],
username: params[:user][:username]
)
record_event_profile(user,params[:user][:fullname],params[:remember_me])
invite.update_attributes({invite_accepted_at: Time.now, name: user.profile.try(:fullname)})
end
else
return redirect_to root_path
end
else
#If a user already exists for the email address then this must just be a new social network account for this user.
token = omni['credentials']['token']
token_secret = ""
user.relatednoise_authentications.create!(
provider: omni['provider'],
uid: omni['uid'],
token: token,
token_secret: token_secret
) if user.present?
end
#Create an entry in Socialnetworkaccounts for this user to associate them to their social login/account.
create_sna(omni, user)
#SignupNotifier.init_notify(user).deliver
begin
ApiConnector.new("#{API_URL}/notify_us/#{user.id}")
rescue => e
Airbrake.notify_or_ignore(e, {})
end
unless user.new_record?
session[:omniauth] = nil
session[:omniauth_auth] = nil
#reset_invite_token
end
session[:user_id] = user.id
record_event_signup(user)
back_if_coming_from_wix(params[:wix_appid], user)
sign_in_and_redirect user if !params[:wix_appid].present?
end
so far i have written this. Not sure if this is the way to write test cases.
require 'test_helper'
class RegistrationsControllerTest < ActionController::TestCase
fixtures :users
def setup
#params = {"omniauth"=>"{\"provider\":\"twitter\",\"uid\":\"167003011\",\"credentials\":{\"token\":\"167003011-ZqnlBsCZlFjymanQ6gQ2ggD7a2tAESuUVlygw0WN\",\"secret\":\"idVWQgR79HOKmZfuNtVtxvzWzGH5plJlxdEksxyuHgH5S\"}}","user"=>{"fullname"=>"Tommy", "email"=>"Tom#moody.com", "username"=>"tommy", "theme_id"=>"", "theme_style_id"=>"", "theme_layout_id"=>""}}
#invite = invites(:arvind_invite)
end
def test_new
get :new
assert_response :success
end
def test_create_for_client_plan
assert_difference ->{ ClientPlan.count }, +1 do
post :create, #params
end
end
def test_create_for_client_setting
assert_difference ->{ ClientSetting.count }, +1 do
post :create, #params
end
end
def test_create_for_client_environment
assert_difference -> {ClientsEnvironment.count}, +1 do
post :create, #params
end
end
def test_create_for_application
assert_difference -> {Application.count}, +1 do
post :create, #params
end
end
def test_create_for_user
assert_difference -> {User.count}, +1 do
post :create, #params
end
end
def test_create_for_feed
assert_difference -> {Feed.count}, +1 do
post :create, #params
end
end
def test_create_for_profile
assert_difference -> {Profile.count}, +1 do
post :create, #params
end
end
def test_create_for_sna
assert_difference -> {Socialnetworkaccount.count}, +1 do
post :create, #params
end
end
def test_create_for_user_with_invitation
assert_difference -> {User.count}, +1 do
post :create, #params.merge({invitation_token: #invite.token})
end
end
end
This is my test helper file.
ENV["RAILS_ENV"] = "test"
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
class ActiveSupport::TestCase
include Devise::TestHelpers
# Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
#
# Note: You'll currently still have to declare fixtures explicitly in integration tests
# -- they do not yet inherit this setting
fixtures :all
def host_with_port
#request.host_with_port = "localhost:3000"
end
# Add more helper methods to be used by all tests here...
end

How to Test Facebook Login Action with Rails, Omniauth and Rspec

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: "test#example.com"
},
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: "test#example.com"
},
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

<true> expected to be != to <true>. test failure

My test is the following:
test "should post make_admin" do
user = FactoryGirl.create(:user, admin: true)
sign_in(user)
before_value = user.admin
post :make_admin, id: user.id
after_value = user.admin
assert_not_equal before_value, after_value
assert_response :redirect
end
and the controller looks like this:
def make_admin
user = User.find_by_id(params[:id])
user.toggle!(:admin)
redirect_to static_pages_user_index_path
end
and yet I keep getting this error:
Failure:
test_should_post_make_admin(StaticPagesControllerTest) [..../functional/static_pages_controller_test.rb:48]:
<true> expected to be != to
<true>.
Any ideas on what I'm doing wrong?
I'd replace:
after_value = user.admin
with:
after_value = user.reload.admin

Resources