NoMethodError running Integration Test, RailsTutorial Ch9 - ruby-on-rails-5

I'm having an issue where my integration tests do not seem to find the log_in_as method from my test_helper.rb
I have been following Michael Hart's Rails tutorial, so I was hoping not to massively refactor my code to try and get this to work. I would like to continue on through the book without having to exclude the tests, since it is pretty test heavy afterall.
Error:
UsersLoginTest#test_login_with_remembering:
NoMethodError: undefined method `log_in_as' for #<UsersLoginTest:0x00000005b18460>
test/integration/users_login_test.rb:43:in `block in <class:UsersLoginTest>'
User_login_test.rb:
require 'test_helper.rb'
class UsersLoginTest < ActionDispatch::IntegrationTest
.
.
.
test "login with remembering" do
log_in_as(#user, remember_me: '1')
assert_not_empty cookies['remember_token']
end
test "login without remembering" do
# Log in to set the cookie.
log_in_as(#user, remember_me: '1')
# Log in again and verify that the cookie is deleted.
log_in_as(#user, remember_me: '0')
assert_empty cookies['remember_token']
end
end
test_helper.rb:
ENV['RAILS_ENV'] ||= 'test'
class ActiveSupport::TestCase
fixtures :all
# Returns true if a test user is logged in.
def is_logged_in?
!session[:user_id].nil?
end
# Log in as a particular user.
def log_in_as(user)
session[:user_id] = user.id
end
end
class ActionDispatch::IntegrationTest
# Log in as a particular user.
def log_in_as(user, password: 'password', remember_me: '1')
post login_path, params: { session: { email: user.email,
password: password,
remember_me: remember_me } }
end
end

I had this same issue. There are two problems I had to fix:
Make sure there is only one test_helper.rb file, and
test_helper.rb is in the right folder
Hope this helps!

Related

Devise & Rspec: User requires account activation in requests spec even after confirmed

I have the following code in my requests spec:
describe 'Poll' do
subject { page }
context 'as system admin' do
let(:user) { Fabricate(:system_admin) }
before { login user}
it 'is accessible' do
visit '/admin/poll'
current_path.should == '/admin/poll'
end
describe 'sending poll' do
it 'sends to all users' do
save_and_open_page
end
end
end
end
The login user doesn't seem to work even if the method seems to be working fine. I tried using login user inside the it 'is accessible' do block and that specs works fine if I do it that way. If I remove it from there and put it in a before block like above. The user doesn't stay signed in. I put in a save_and_open_page to debug and I get this notification in the page:
Your account was not activated yet. If a reset password link was sent to you, use that link to change your password.
I'm using Devise, RSpec, Capybara and Rails 3. I've also set user to confirm! in my Fabrication file. Below is how it looks:
Fabricator(:system_admin) do
first_name { sequence(:first_name) { |n| "Person#{n}"} }
last_name { sequence(:last_name) {|n| "#{n}" } }
email { sequence(:email) { |n| "person_#{n}#example.com"} }
password "foobar"
password_confirmation "foobar"
company_name { sequence(:company_name) { |n| "google#{n}" } }
role "system_admin"
after_create do |user|
user.confirm!
user.create_company
end
end
Question: What could be the problem? How come the user isn't staying logged in and why do I get that message saying that I should activate my account? Isn't user.confirm! enough?
could this be the problem?
Fabricate(:system_admin) != Fabricator(:system_admin)
So if you debug your save_and_open_page and it tells you that the account is not activated it seemes your fabricate is not working properly. have you tried and debug that?
what does your save_and_open_page do? does it try to use the user for something? because I have experienced when defined with a let, if not touched the variable(user in this case) then it does no exist on that context. besides. whats the error when you run the specs like this on it "is acessible"? just says there is no user logged in?
so you can either stub your methods for login(for example if you have method called current_user that gives you the logged in user or something) or instead of using let, instiate like:
user = Fabricate(:system_admin)
but hey there is a lot of good advices here:
http://betterspecs.org/
it seems like your blocks context and describe are too complex. I am also not following this guidelines 100% but I think I should and you too would benefit from this.
let me know if you found out another reason why its not working!
I think before(:each) should resolve the problem
Add this Devise method:
confirmed_at { Time.now }
So your after_create method should looks like:
after_create do |user|
user.confirm!
user.confirmed_at { Time.now }
user.create_company
end

Can't create a user factory in factory girl when using rspec, devise, guard, and spork

I've seen this issue several places, but none of the solutions seem to work.
I have a Rails 3.1 app with the latest versions of guard, spork, factory girl, rspec, and devise.
Whenever I try to create a user factory (the user model is a devise model) then I get this error:
Could not find a valid mapping for #<User...model attributes...>
I'm not sure what the problem is.
I ran rake db:test:prepare. I followed the instructions in this stackoverflow question: "Could not find a valid mapping for #<User ...>" only on second and successive tests
ALso, I attempted the solution in this answer from google groups:
https://groups.google.com/forum/?fromgroups#!topic/plataformatec-devise/StpbEsDCec0[1-25]
And, here's all the relevant code:
Guardfile
# A sample Guardfile
# More info at https://github.com/guard/guard#readme
require 'capybara/rspec'
guard 'spork', :cucumber_env => { 'RAILS_ENV' => 'test' }, :rspec_env => { 'RAILS_ENV' => 'test' } do
watch('config/application.rb')
watch('config/environment.rb')
watch('config/environments/test.rb')
watch(%r{^config/initializers/.+\.rb$})
watch('Gemfile')
watch('Gemfile.lock')
watch('spec/spec_helper.rb') { :rspec }
watch('test/test_helper.rb') { :test_unit }
watch(%r{features/support/}) { :cucumber }
end
guard 'rspec', :version => 2, :cli => '--drb' do
watch(%r{^spec/.+_spec\.rb$})
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
watch('spec/spec_helper.rb') { "spec" }
# Rails example
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
watch('config/routes.rb') { "spec/routing" }
watch('app/controllers/application_controller.rb') { "spec/controllers" }
# Capybara request specs
watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
# Turnip features and steps
watch(%r{^spec/acceptance/(.+)\.feature$})
watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
end
</code>
This is in my spec/factories.rb
FactoryGirl.define do
load "#{Rails.root}/app/models/user.rb"
factory :user, class: User do |user|
email 'owner#example.com'
password '12345678'
password_confirmation '12345678'
companyid 'example_company'
end
end
This is my spec/controllers/api_controller_spec.rb
require 'spec_helper'
describe ApiController do
it 'verifies company_id through POST to api/company_id' do
load "#{Rails.root}/app/models/user.rb"
debugger
user = FactoryGirl.create(:user)
post(:get_company_id, {:company_id => 'example_company'})
response.body.should include('true')
end
end
And I have this at the end of my config/application.rb
ActionDispatch::Callbacks.after do
# Reload the factories
return unless (Rails.env.development? || Rails.env.test?)
unless FactoryGirl.factories.blank? # first init will load factories, this should only run on subsequent reloads
FactoryGirl.factories.clear
FactoryGirl.find_definitions
end
end
I'm really desperate for an answer here because otherwise I won't be able to test my User model (which is the most important model I have).
Feel free to comment and ask any questions.
EDIT: code looked funny in places, so I edited it for clarity
UPDATE:
So I tried simplifying everything to get to the core of the problem, and I'm pretty sure that devise and factory girl don't "like" each other. I'm still getting the exact same error whenever I try and create a user factory.
This is my new setup (I reverted to a previous git commit and I no longer have guard or spork).
My factories.rb is exactly the same as Michael Durant's except I have an extra line:
companyid 'example'
That's just a requirement for my app.
My spec_helper.rb requires rubygems and capybara/rspec and that's it.
And this is my spec/models/user_spec.rb
require 'spec_helper'
describe 'User associations' do
it 'tests creation of user' do
debugger
user = FactoryGirl.create(:user)
User.count.should be(1)
end
end
Also, this is interesting: When I hit that debugger statement and type in
eval User
It shows the mapping of a valid User.
UPDATE:
So, it's not factory girl that's the problem. It's devise.
This is the new api_controller_spec.rb file and it comes up with the same error of not having a valid mapping of the user.
require 'spec_helper'
describe ApiController do
it 'verifies company_id through POST to api/company_id' do
load "#{Rails.root}/app/models/user.rb"
debugger
user = User.new
user.email = 'owner#example.com'
user.password = '12345678'
user.password_confirmation = '12345678'
user.company_id = 'company'
user.save
post(:get_company_id, {:company_id => 'example_company'})
response.body.should include('true')
end
end
THere isn't a problem with any other environment as I can create users fine through the console, while a local server is running, or when the code is pushed up to Heroku. It might be rspec or something else, but I'm just not sure at this point.
I would recommend you simplify things to find the issue. Currently I feel you have too much going on / too many variable factors.
I would recommend the following:
1 Make a new branch. I assume you are using git, if not use it (git init) and make a fork.
2 Remove all the spork and guard stuff. They are helpful in speeding up your tests and running tests in a CI (Continuous Integration), but they are certainly not 'needed' and removing them will help uncover what the real problems are.
3 Set up your user factory correctly. We use this:
FactoryGirl.define do
sequence :email do |n|
"email#{n}#factory.com"
end
factory :user do
email
first_name { 'First' }
last_name { 'Last' }
password { "password" }
password_confirmation { "password" }
association :area
role { 'super_user' }
end
end
4 Set up your spec_help correctly.
We use these requires in our spec_helper.rb:
require 'rubygems'
require 'capybara/rspec'
5 Try to get one user test to pass using spec/models/user_spec.rb, something like:
require 'spec_helper'
describe 'User associations' do
subject { User.new }
it { should validate_presence_of :area }
...
So, the answer had nothing to do with guard, spork, rspec, or factory_girl.
The problem was that I had my devise_for :users routes commented out since I've been doing a huge overhaul of my rails app.
It's always something stupidly simple >.<

Rails Sorcery Bug? Creates Duplicate User Accounts

The example sorcery code shown on github appears to me to create duplicate accounts if it is extended to allow for multiple sign in methods (which is the whole point of oauth). You can see in the snipit here that create_from() will be called if login_from() does not succeed.
GITHUB AT at https://github.com/NoamB/sorcery-example-app/blob/master/app/controllers/oauths_controller.rb
def callback
provider = params[:provider]
begin
if #user = login_from(provider)
redirect_to root_path, :notice => "Logged in from #{provider.titleize}!"
else
begin
#user = create_from(provider)
Investigating the source code for create_from in all cases a new User Account record will be created. This would not be correct, if a User account record already exists.
My question: What sorcery methods should be called on the first facebook connect, if a User account has been created by some means other than facebook. login_from will fail, and create_from will generate a duplicate usser record?
You can use def create_and_validate_from(provider).
It will validate if the users email/username already exist. If its true, that he will store infos into a session and can be rendered into registration form.
And if you wish to add some provider to your account you can use def add_provider_to_user(provider).
Several requests have come through for an answer to this question, so I am providing the answer that Andy Mejia part of my team eventually arrived at for this question. We used the source within sorcery to adapt the following functions:
# Returns the hash that contains the information that was passed back from Facebook.
# It only makes sense to call this method on the callback action.
#
# Example hash:
# {:user_info=>{:id=>"562515238", :name=>"Andrés Mejía-Posada", :first_name=>"Andrés", :last_name=>"Mejía-Posada", :link=>"http://www.facebook.com/andmej", :username=>"andmej", :gender=>"male", :email=>"andmej#gmail.com", :timezone=>-5, :locale=>"en_US", :verified=>true, :updated_time=>"2011-12-31T21:39:24+0000"}, :uid=>"562515238"}
def get_facebook_hash
provider = Rails.application.config.sorcery.facebook
access_token = provider.process_callback(params, session)
hash = provider.get_user_hash
hash.merge!(:access_token => access_token.token)
hash.each { |k, v| v.symbolize_keys! if v.is_a?(Hash) }
end
# Method added to the User Account model class
def update_attributes_from_facebook!(facebook_hash)
self.first_name = facebook_hash[:user_info][:first_name] if self.first_name.blank?
self.last_name = facebook_hash[:user_info][:last_name] if self.last_name.blank?
self.facebook_access_token = facebook_hash[:access_token]
self.email ||= facebook_hash[:user_info][:email]
unless facebook_authentication?
authentications.create!(:provider => "facebook", :uid => facebook_hash[:uid])
end
self.build_facebook_profile if facebook_profile.blank?
save!
self.facebook_profile.delay.fetch_from_facebook! # Get API data
end
To show these code in context, I am also including logic from our controller:
def callback
provider = params[:provider]
old_session = session.clone # The session gets reset when we login, so let's backup the data we need
begin
if #user = login_from(provider) # User had already logged in through Facebook before
restore_session(old_session) # Cleared during login
else
# If there's already an user with this email, just hook this Facebook account into it.
#user = UserAccount.with_insensitive_email(get_facebook_hash[:user_info][:email]).first
# If there's no existing user, let's create a new account from scratch.
#user ||= create_from(provider) # Be careful, validation is turned off because Sorcery is a bitch!
login_without_authentication(#user)
end
#user.update_attributes_from_facebook!(get_facebook_hash)
rescue ::OAuth2::Error => e
p e
puts e.message
puts e.backtrace
redirect_to after_login_url_for(#user), :alert => "Failed to login from #{provider.titleize}!"
return
end
redirect_to after_login_url_for(#user)
end
I hope this solution is helpful to others.
I came across the same problem. While I have not found a direct solution via Sorcery, I did the following which seems to work:
#user = create_from(params[:provider]) do |user|
User.where(:twitter_id => user.twitter_id).first.blank?
end
This teqnique requires that you have twitter_id in the User model. You can also do it the other way around with the Authentication model instead. Such as:
#user = create_from(params[:provider]) do |user|
Authentication.where(:uid => user.twitter_id).first.blank?
end
If the block returns false, then it doesn't create the user. Avoiding any duplicates.
Note, the block for create_from does not work with 0.7.12. It works with 0.7.13.

Testing Email w/ Pony and RSpec in Rails 3.1

I tried using this How do I test Pony emailing in a Sinatra app, using rspec? to test a Rails 3.1 app sending emails. The sending works fine, but I'm having a hard time getting the tests to work. Here's what I have so far ...
spec/spec_helper.rb
config.before(:each) do
do_not_send_email
end
.
.
.
def do_not_send_email
Pony.stub!(:deliver) # Hijack to not send email.
end
and in my users_controller_spec.rb
it "should send a greeting email" do
post :create, :user => #attr
Pony.should_receive(:mail) do |params|
params[:to].should == "nuser#gmail.com"
params[:body].should include("Congratulations")
end
end
and I get this ...
Failures:
1) UsersController POST 'create' success should send a greeting email
Failure/Error: Pony.should_receive(:mail) do |params|
(Pony).mail(any args)
expected: 1 time
received: 0 times
# ./spec/controllers/users_controller_spec.rb:121:in `block (4 levels) in '
It looks like Pony's not getting an email, but I know the real email is getting sent out.
Any ideas?
Here's what I finally ended up with for the test ...
it "should send a greeting email" do
Pony.should_receive(:deliver) do |mail|
mail.to.should == [ 'nuser#gmail.com' ]
mail.body.should =~ /congratulations/i
end
post :create, :user => #attr
end
The Pony.should_rececieve needs :deliver (not :mail), the do/end was changed a bit, and the post was done after the setup.
Hope this helps someone else.
I know this is an old question but there is another way to test this. Version 1.10 of Pony added override_options. Pony uses Mail to send email. override_options lets you use the TestMailer functionality that is built into Mail. So you can set up your test like this:
In spec_helper
require 'pony'
Pony.override_options = { :via => :test }
In your test
before do
Mail::TestMailer.deliveries.clear
end
it 'some test' do
# some code that generates an email
mail = Mail::TestMailer.deliveries.last
expect(mail.to).to eql 'some#email.com'
end

railstutorial.org NoMethodError in SessionsController#create

undefined method `current_user=' for #<SessionsController:0x1044926b8>
Rails.root: /Users/Bulow/ruby/sample_app
Application Trace | Framework Trace | Full Trace
app/helpers/sessions_helper.rb:4:in `sign_in'
app/controllers/sessions_controller.rb:20:in `create'
Request
Parameters:
{"commit"=>"Sign in",
"session"=>{"password"=>"[FILTERED]",
"email"=>"kennyvonbulow#gmail.com"},
"authenticity_token"=>"/fWZncGEWuhQLIYMxRPXBcBJ37vzLoVrIz1QHU28u6w=",
"utf8"=>"✓"}
Show session dump
Show env dump
Response
Headers:
None
unable to log in simply - and i have no clue how to correct it. been all over the guide back and forth and can't seem to find the error that's causeing this
The online tutorial has the following definitions in sessions_helper.rb
def sign_in(user)
cookies.permanent.signed[:remember_token] = [user.id, user.salt]
self.current_user = user
end
.
.
.
def sign_out
cookies.delete(:remember_token)
self.current_user = nil
end
I changed them to the following and was able to login/logout without any errors.
def sign_in(user)
cookies.permanent.signed[:remember_token] = [user.id, user.salt]
#current_user = user
end
.
.
.
def sign_out
cookies.delete(:remember_token)
#current_user = nil
end
Also, to confirm it's you that's logged in, change the URL localhost:3000/users/(your user ID) to another user ID. It'll show that users info. Click on the profile link at the top and it'll go back to your profile. The app is set up so that this link will got to the logged in user's profile.
Where I found the solution.
http://getsatisfaction.com/railstutorial/topics/undefined_method_current_user_for_sessionscontroller