NoMethodError error in Rails - ruby-on-rails

I'm going through Michael Hartl's Ruby tutorial and have been stuck for a day on a failing test
I get this when I run:
Error:
UsersControllerTest#test_should_redirect_edit_when_logged_in_as_wrong_user:
NoMethodError: undefined method `session' for nil:NilClass
test/test_helper.rb:19:in `log_in_as'
test/controllers/users_controller_test.rb:37:in `block in <class:UsersControllerTest>'
Here is the calling code:
require 'test_helper'
class UsersControllerTest < ActionDispatch::IntegrationTest
def setup
#user = users(:michael)
#otheruser = users(:archer)
end
test "should redirect update when logged in as wrong user" do
log_in_as(#other_user)
patch user_path(#user), params: { user: { name: #user.name,
email: #user.email } }
assert flash.empty?
assert_redirected_to root_url
end
*And here is the method I'm trying to call from the **test_helper** class:*
# Log in as a particular user
def log_in_as(user)
session[:user_id] = user.id
end

I was missing a part in my test_helper.rb class:
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
Thank you for taking a look!

Did you include this line of code: include SessionsHelper in your application_controller.rb?
You have typo in setup method from the code above: #otheruser = users(:archer) should be #other_user = users(:archer)
Check again the code from the test file: test / controllers / users_controller_test.rb
especially this part of the code:
test "should redirect edit when logged in as wrong user" do
log_in_as(#other_user)
get edit_user_path(#user)
assert flash.empty?
assert_redirected_to root_url
end
Hope it helps!

Related

How do I log in a user with Devise for Rails controller/integration unit tests?

All the other answers are wrong or out of date. I've tried several things. This is what I have:
require 'test_helper'
class DealsControllerTest < ActionDispatch::IntegrationTest
include Devise::Test::IntegrationHelpers
setup do
#deal = deals(:one)
#user = users(:one)
# https://github.com/plataformatec/devise/wiki/How-To:-Test-controllers-with-Rails-3-and-4-(and-RSpec)
##request.env["devise.mapping"] = Devise.mappings[:one]
#sign_in #user
#log_in_as #user
ApplicationController.allow_forgery_protection = false
post user_session_path, params: {user: {email: #user.email, password: #user.password}}
assert_select "p", "Invalid Email or password."
assert_response :redirect ############ line 16
#assert_text "Invalid Email or password."
assert_redirected_to root_url
end
Failure:
DealsControllerTest#test_should_destroy_deal [C:/Users/Chloe/workspace/fortuneempire/test/controllers/deals_controller_test.rb:16]:
Expected response to be a <3XX: redirect>, but was a <200: OK>
Since it passes the "Invalid email/password" test, that means the user is NOT logging in!
I tried these answers:
How to sign in a user using Devise from a Rails console?
How to sign_in for Devise to Test Controller with Minitest
https://github.com/plataformatec/devise/wiki/How-To:-Test-controllers-with-Rails-3-and-4-(and-RSpec)
Rails: Capybara can't log in user with Devise fixture data
This worked
require 'test_helper'
class DealsControllerTest < ActionDispatch::IntegrationTest
include Warden::Test::Helpers
setup do
#deal = deals(:one)
#user = users(:one)
# https://github.com/plataformatec/devise/wiki/How-To:-Test-with-Capybara
#user.confirmed_at = Time.now
#user.save
login_as(#user, :scope => :user)
end
teardown do
Warden.test_reset!
end

Controller testing with rpec and factorygirl in Rails 5

I'm attempting to create some controller specs in my Rails 5 app using rspec, but the code keeps throwing the following error:
1) SessionsController Log in and log out logs in with valid user
Failure/Error: user = User.find_by(email: params[:session][:email].downcase)
NoMethodError:
undefined method `[]' for nil:NilClass
My spec is pretty straightforward. The user instance variable uses factory-girl to create a user with the email "user#example.com" and password as "password." When I call puts on these variables, I can see that they are set correctly.:
require 'rails_helper'
RSpec.describe SessionsController, type: :controller do
before :each do
#user = create(:user)
end
describe "Log in and log out" do
before :each do
post :create, { session: { email: #user.email,
password: #user.password }}
end
it "logs in with valid user" do
puts #user.email + " " + #user.password
expect(is_logged_in?).to be_truthy
end
end
end
Finally, the code from the sessions controller is below:
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
log_in user
remember user
redirect_to user
else
flash.now[:danger] = 'Invalid email/password combination'
render 'new'
end
end
end
Am I misunderstanding the way params are sent to the controller in rspec? Is there any other reason for this error to be returned?
Changes were made in Rails 5 to the way you send params in controller tests.
Instead of:
before :each do
post :create, { session: { email: #user.email,
password: #user.password }}
end
You need to provide the params key in post request attribute hash. Like so...
before :each do
post :create, params: { session: { email: #user.email,
password: #user.password }}
end
It's subtle, but it's different. Let me know if that works.

Ruby on rails test error

I am learning to make tests for a ruby on rails application, and I appear to have run into an issue. I am trying to login a user as I do not have access to the session[:user_id] inside these two tests. So I have made a method inside the test_helper that defines these methods in my create_categories_test, and they run, but when I set a login for them, it returns this error:
(byebug) post login_path session: [{username: user.username, password: password}]
*** NoMethodError Exception: undefined method `[]' for nil:NilClass
This is my helper method in test_helper.rb
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
class ActiveSupport::TestCase
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
fixtures :all
# Add more helper methods to be used by all tests here...
def sign_in_as(user, password)
post login_path, session: {username: user.username, password: password}
end
end
Note: I put a debugger inside my method and ran the same line of code which returned nil(for some reason)
Here's my code for my create_categories_test.rb
def setup
#user = User.create(username: "John", email: "john#doe.com", password: "password", admin: true)
end
test "get new category form and create category" do
sign_in_as(#user, "password")
get new_category_path
assert_template 'categories/new'
assert_difference 'Category.count' do
post_via_redirect categories_path, category: {name: "sports"}
end
assert_template 'categories/index'
assert_match "sports", response.body
end
test "invalid category submission results in failure" do
sign_in_as(#user, "password")
get new_category_path
assert_template 'categories/new'
assert_no_difference 'Category.count', 1 do
post categories_path, category: {name: " "}
end
assert_template 'categories/new'
assert_select 'h2.panel-title'
assert_select 'div.panel-body'
end
My login controller:
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by(username: params[:sessions][:username])
if user && user.authenticate(params[:sessions][:password])
session[:user_id] = user.id
flash[:success] = "You have successfully logged in"
redirect_to user_path(user)
else
flash.now[:danger] = "There was something wrong with your login details"
render 'new'
end
end
def destroy
session[:user_id] = nil
flash[:success] = "You have successfully logged out"
redirect_to root_path
end
end
I assume the problem in your params in the post method:
post login_path session: [{username: user.username, password: password}]
You post an array [{username: user.username, password: password}], but controller expect an hash:
post login_path session: {username: user.username, password: password}
Also your login helper:
#session: {}
post login_path, session: {username: user.username, password: password}
^^^^^^^
But controller expect:
#sessions: {}
user = User.find_by(username: params[:sessions][:username])
^^^^^^^^
Probably this is off-topic question, because it's about a simple typo in the code.

Been stuck on a test error on Ruby on Rails tutorial- Error: UsersControllerTest#test_should_redirect_update_when_logged_in_as_wrong_user:

I've been stuck on this one for a while and keep getting 2 errors when I rake test. Referencing Listing 9.23 testing point. Any help would be much appreciated.
Test Error:
1) Error:
UsersControllerTest#test_should_redirect_update_when_logged_in_as_wrong_user:
NameError: undefined local variable or method `user_id' for #<UsersControllerTest:0x007fbff6be3120>
test/test_helper.rb:24:in `log_in_as'
test/controllers/users_controller_test.rb:35:in `block in <class:UsersControllerTest>'
2) Error:
UsersControllerTest#test_should_redirect_edit_when_logged_in_as_wrong_user:
NameError: undefined local variable or method `user_id' for #<UsersControllerTest:0x007fbff6c01850>
test/test_helper.rb:24:in `log_in_as'
test/controllers/users_controller_test.rb:28:in `block in <class:UsersControllerTest>'
29 runs, 66 assertions, 0 failures, 2 errors, 0 skips
User_Controller_Test file:
require 'test_helper'
class UsersControllerTest < ActionController::TestCase
def setup
#user = users(:michael)
#other_user = users(:archer)
end
test "should get new" do
get :new
assert_response :success
end
test "should redirect edit when not logged in" do
get :edit, id: #user
assert_not flash.empty?
assert_redirected_to login_url
end
test "should redirect update when not logged in" do
patch :update, id: #user, user: { name: #user.name, email: #user.email }
assert_not flash.empty?
assert_redirected_to login_url
end
test "should redirect edit when logged in as wrong user" do
log_in_as(#other_user)
get :edit, id: #user
assert flash.empty?
assert_redirected_to root_url
end
Test_Helper.rb:
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
class ActiveSupport::TestCase
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
fixtures :all
def is_logged_in?
!session[:user_id].nil?
end
#logs in a test user
def log_in_as(user, options = {})
password = options[:password] || 'password'
remember_me = options[:remember_me] || '1'
if integration_test?
post login_path, session: { email: user.email,
password: password,
remember_me: remember_me}
else
session[:user_id] = user_id
end
end
private
#returns true inside an int. test
def integration_test?
defined?(post_via_redirect)
end
end
And where does user_id come from here?
def log_in_as(user, options = {})
...
if integration_test?
...
else
session[:user_id] = user_id
end
end
Seems it should be:
session[:user_id] = user.id

How to test if devise is signing users in with login, not email?

I'm trying to confirm whether devise is using login, not email for sign in. That's what I have so far:
test/controllers/sessions_controller_test.rb:
require 'test_helper'
class Devise::SessionsControllerTest < ActionController::TestCase
test "should sign in using login" do
#request.env["devise.mapping"] = Devise.mappings[:user]
post :create, user: {login: 'login', password: 'password'}
assert_response :success
end
end
And now it says:
1) Error:
Devise::SessionsControllerTest#test_should_sign_in_using_login:
NoMethodError: undefined method `authenticate?' for nil:NilClass
test/controllers/sessions_controller_test.rb:7:in `block in <class:SessionsControllerTest>'
Why doesn't it work? What am I doing wrong?
The error disappeared after I added include Devise::TestHelpers in test/test_helper.rb as documentation suggests:
class ActiveSupport::TestCase
...
include Devise::TestHelpers
end
And now my tests look this way:
test/controllers/sessions_controller_test.rb:
require 'test_helper'
class Devise::SessionsControllerTest < ActionController::TestCase
test "should have login field" do
#request.env["devise.mapping"] = Devise.mappings[:user]
get :new
assert_select '[name="user[login]"]'
end
test "should sign in using login" do
#request.env["devise.mapping"] = Devise.mappings[:user]
post :create, user: {login: 'login', password: 'password'}
assert_redirected_to root_url
end
end
test/fixtures/users.yml (how to put password in a fixture):
one:
login: login
encrypted_password: <%= Devise.bcrypt(User, 'password') %>

Resources