I'm using Rails 6 to work through the Hartl Tutorial, using mostly the online version. I'm in Chapter 10 (which doesn't correspond to the book version chapter numbering)...
https://www.railstutorial.org/book/updating_and_deleting_users
In Section 10.2.2, after Listing 10.25, the Rails Test should be green, but I get these 2 FAIL messages:
FAIL["test_should_redirect_edit_when_not_logged_in", #, 11.729448000027332]
test_should_redirect_edit_when_not_logged_in#UsersControllerTest (11.73s)
Expected true to be nil or false
test/controllers/users_controller_test.rb:18:in `block in '
FAIL["test_should_redirect_update_when_not_logged_in", #, 1.2034909999929368]
test_should_redirect_update_when_not_logged_in#UsersControllerTest (1.20s)
Expected true to be nil or false
test/controllers/users_controller_test.rb:26:in `block in '
The related code is this:
test "should redirect edit when not logged in" do
log_in_as(#other_user)
get edit_user_path(#user)
assert_not flash.empty?
assert_redirected_to login_url
end
test "should redirect update when not logged in" do
log_in_as(#other_user)
patch user_path(#user), params: { user: { name: #user.name,
email: #user.email } }
assert_not flash.empty?
assert_redirected_to login_url
end
It's the log_in_as(#other_user) that appears to be the problem, but it could be elsewhere. I can't see why this section has a problem when the similar one in users_edit_test.rb does not.
Related
I'm trying to follow Mike Hartl's tutorial with RSpec. I've reached the password reset integration test, and so far I was doing well. Then I got to the line that said user = assigns(:user)
I searched for an answer so here is what I have and my error.
Failures:
PasswordResets Password resets email input valid email sends password and redirects to root
Failure/Error: expect(assigns(:user)).to eq([user])
NameError:
undefined local variable or method `user' for #<RSpec::ExampleGroups::PasswordResets::PasswordResets::EmailInput:0x007fc5d16b0ca8>
# ./spec/requests/password_resets_spec.rb:26:in `block (4 levels) in <top (required)>'
require 'rails_helper'
RSpec.describe "PasswordResets", type: :request do
describe "Password resets" do
before do
ActionMailer::Base.deliveries.clear
#valid_user = create(:user)
end
describe "unsuccessful password reset" do
it "flashes danger when email is blank" do
get new_password_reset_path(#valid_user.id)
post password_resets_path, params: { password_reset: { email: " " } }
expect(flash[:danger]).to be_present
expect(page).to render_template(:new)
end
end
describe "email input" do
it "valid email sends password and redirects to root" do
post password_resets_path, params: { password_reset: { email: #valid_user.email } }
expect(#valid_user.reset_digest).not_to match (#valid_user.reload.reset_digest)
expect(ActionMailer::Base.deliveries.size).to eq(1)
expect(flash[:info]).to be_present
expect(page).to redirect_to root_url
expect(assigns(:user)).to eq([user])
end
end
end
end`
The tutorial I'm following https://www.railstutorial.org/book/password_reset 12.18
I'm not sure what else to do.
Your test is erroring because you haven't defined a user variable at that point in your test. You have defined #valid_user. My guess is your test would pass if you change:
expect(assigns(:user)).to eq([user])
to
expect(assigns(:user)).to eq(#valid_user)
I have the following errors:
1) Failure:
UsersLoginTest#test_login_with_invalid_information [/REDACTED/users_login_test.rb:32]:
expecting <"session/new"> but rendering with <["sessions/new", "layouts/application"]>
2) Failure:
UsersEditTest#test_unsuccessful_edit [/REDACTED/test/integration/users_edit_test.rb:11]:
expecting <"users/edit"> but rendering with <[]>
3) Failure:
UsersEditTest#test_successful_edit [/REDACTED/test/integration/users_edit_test.rb:22]:
expecting <"users/edit"> but rendering with <[]>
Relevant code from user_login_test.rb:
test "login with invalid information" do
get login_path
assert_template 'session/new'
post login_path, session: { email: "", password: "" }
assert_template 'session/new'
assert_not flash.empty?
get root_path
assert flash.empty?
end
users_edit_test.rb:
require 'test_helper'
class UsersEditTest < ActionDispatch::IntegrationTest
def setup
#user = User.find_by_name(:testuser)
end
test "unsuccessful edit" do
log_in_as(#user)
get edit_user_path(#user)
assert_template 'users/edit'
patch user_path(#user), user: { name: "",
email: "foo#invalid",
password: "foo",
password_confirmation: "bar" }
assert_template 'users/edit'
end
test "successful edit" do
log_in_as(#user)
get edit_user_path(#user)
assert_template 'users/edit'
name = "Foo Bar"
email = "foo#bar.com"
patch user_path(#user), user: { name: name,
email: email,
password: "",
password_confirmation: "" }
assert_not flash.empty?
assert_redirected_to #user
#user.reload
assert_equal name, #user.name
assert_equal email, #user.email
end
end
After several grueling hours of trying to hunt down the problem, I am still unable to find it. Tracing through the several problems, I feel like it might be a problem with the following test login code:
def log_in_as(user, options = {})
password = options[:password] || 'password'
remember_me = options[:remember_me] || '1'
if integration_test?
get login_path
post login_path, session: { email: user.name,
password: password,
remember_me: remember_me
}
else
session[:user_id] = user.id
end
end
I'm happy to update with more information as needed, but I'm pretty much at a loss.
It seems you redirected instead of rendering. Try that:
expect(response).to redirect_to root_path
to make sure you're redirected
I'm currently working through chapter 9 of the same Rails tutorial, and I ran into pretty much the same issue. After playing around in the console for a while I decided to just test it manually in the browser and was indeed unable to get to my edit page even though I was logged in. Which got me thinking that it might not be a problem with my tests but instead with the authorization in the users_controller.
Turns out I had completely forgotten to put the redirect_to login_url (in the logged_in_user filter) within an unless block so it was always just redirecting to the login page no matter what. The correct code is:
def logged_in_user
unless logged_in?
flash[:danger] = 'Please log in.'
redirect_to login_url
end
end
Now my tests are passing. Perhaps you've run into a similar issue. Either way I've often found it useful to just return to the browser and try to replicate the integration tests manually, just to figure out if it's a problem with my code or I've just written a dodgy test.
Working through the Rails Tutorial and in chapter 8 I can't get one of my tests to pass. Been checking around for hours... any help would be greatly appreciated.
ERROR["test_login_with_valid_information", UsersLoginTest, 2015-09-07 00:25:37 -0700]
test_login_with_valid_information#UsersLoginTest (1441610737.31s)
BCrypt::Errors::InvalidHash:
BCrypt::Errors::InvalidHash: invalid hash
app/controllers/sessions_controller.rb:8:in `create'
test/integration/users_login_test.rb:22:in `block in <class:UsersLoginTest>'
app/controllers/sessions_controller.rb:8:in `create'
test/integration/users_login_test.rb:22:in `block in <class:UsersLoginTest>'
22/22: [============] 100% Time: 00:00:00, Time: 00:00:00
Finished in 0.46288s
22 tests, 44 assertions, 0 failures, 1 errors, 0 skips
users_login_test.rb
require 'test_helper'
class UsersLoginTest < ActionDispatch::IntegrationTest
def setup
#user = users(:michael)
end
test "login with invalid information" do
get login_path
assert_template 'sessions/new'
post login_path, session: { email: "", password: "" }
assert_template 'sessions/new'
assert_not flash.empty?
get root_path
assert flash.empty?
end
test "login with valid information" do
get login_path
post login_path, session: { email: #user.email, password: 'password' }
assert_redirected_to #user
follow_redirect!
assert_template 'users/show'
assert_select "a[href=?]", login_path, count: 0
assert_select "a[href=?]", logout_path
assert_select "a[href=?]", user_path(#user)
end
end
sessions_controller.rb
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
redirect_to user
else
flash.now[:danger] = 'Invalid email/password combination'
render 'new'
end
end
def destroy
end
end
I know it's been a while since originally posted, but I had exactly the same error and my problem was a typo (missing =) in
users.yml
michael:
name: Michael Example
email: michael#example.com
password_digest: <% User.digest('password') %>
where it should have been
michael:
name: Michael Example
email: michael#example.com
password_digest: <%= User.digest('password') %>
#PraveenGeorge is correct - you need to back track and review your code at least since the last time the tests passed. Based on the fact that the content of the two files you've shared match to the tutorial, the problem lies elsewhere (and, unfortunately, out of sight from us on SO).
Perhaps it's in user.rb where you def User.digest(string) or in sessions_helper.rb?
Dear #Travislogan : As the ruby on rails tutorial itself is self explanatory in most possible way, you might have missed some of the steps/code before you reached into the section 8.2. So please cross check all tests and your project code from at least the previous chapter to the current one , one more time.It will help you to find out the error in your code.
I'm trying to ensure proper user access is maintained with Devise in Rails 4, and I'm having a hard time logging a user in in the test suite.
The simplest case:
require 'test_helper'
include Devise::TestHelpers
class SiteLayoutTest < ActionDispatch::IntegrationTest
def setup
#user = users(:test1)
end
test "logged in should get index" do
sign_in #user
get users_path
assert_response :success
assert_select "title", "User Index"
end
end
So far I've not done more really than just implement Devise and a Users controller with the appropriate actions.
I consistently get: NoMethodError: undefined method 'env' for nil:NilClass, referring specifically to the line containing sign_in #user and I can find other instances of people getting the same error, but never seem to find an actual solution to the problem I'm attempting to solve.
How do I log a user in with Devise in Rails 4 for testing purposes? Thanks.
EDIT:
fixtures/users.yml
test1:
id: '1'
email: 'test1#example.com'
encrypted_password: <%= Devise::Encryptor.digest(User, "password") %>
created_at: <%= Time.now - 6.minutes %>
updated_at: <%= Time.now - 4.minutes %>
SOLUTION IN SITU:
test "logged in should get index" do
post user_session_path, 'user[email]' => #user.email, 'user[password]' => 'password'
get users_path
assert_response :success
assert_select "title", "User Index"
end
This is from their docs:
"Do not use Devise::TestHelpers in integration tests."
You have to sign in manually. This is an example of a test for a website that does not allow users to get to the root path unless signed in. You can create a method in a support file that signs in the user manually and then call it whenever you want to sign in the user, so that you don't have to use this code every time you need to sign in a user.
require 'test_helper'
class UserFlowsTest < ActionDispatch::IntegrationTest
test "signed in user is redirected to root_path" do
get user_session_path
assert_equal 200, status
#david = User.create(email: "david#mail.com", password: Devise::Encryptor.digest(User, "helloworld"))
post user_session_path, 'user[email]' => #david.email, 'user[password]' => #david.password
follow_redirect!
assert_equal 200, status
assert_equal "/", path
end
test "user is redirected to sign in page when visiting home page" do
get "/"
assert_equal 302, status
follow_redirect!
assert_equal "/users/sign_in", path
assert_equal 200, status
end
end
EDIT: Just in case it's helpful in the future. You can use Warden Test Helpers for integration tests but the way above is a better test. This is a working example:
require 'test_helper'
include Warden::Test::Helpers
class UserFlowsTest < ActionDispatch::IntegrationTest
test "user can see home page after login" do
#david = User.create(email: "david#mail.com", password: Devise::Encryptor.digest(User, "helloworld"))
login_as(#david)
get "/"
assert_equal 200, status # User gets root_path because he loged in
assert_equal "/", path
logout
get "/"
assert_equal 302, status # User is redirected because he loged out
Warden.test_reset! #reset Warden after each example
end
end
Here is my test, similar to the mailer test from the Hartl tutorial:
test "valid signup information with account activation" do
get new_user_path
assert_difference 'User.count', 1 do
post users_path, user: { username: "Jwan622",
first_name: "Jeffrey",
last_name: "Wan",
email: "Jwan622#yahoo.com",
password: "password",
password_confirmation: "password",
city: "New York City",
state: "New York",
country: "United States"
}
end
assert_equal 1, ActionMailer::Base.deliveries.size
user = assigns(:user)
assert_not user.activated?
log_in_as(user)
assert_not is_logged_in?
# Invalid activation token
get edit_account_activation_path("invalid token")
assert_not is_logged_in?
# Valid token, wrong email
get edit_account_activation_path(user.activation_token, email: 'wrong')
assert_not is_logged_in?
# Valid activation token
get edit_account_activation_path(user.activation_token, email: user.email)
assert user.reload.activated?
follow_redirect!
assert_template 'root_path'
assert is_logged_in?
end
Here is my error message:
1) Failure:
UserSignupTest#test_valid_signup_information_with_account_activation [/Users/Jwan/Dropbox/Turing/projects/FlyAwayFromHere/test/integration/user_signup_test.rb:94]:
expecting <"root_path"> but rendering with <["layouts/_praise_bar", "layouts/_city_change", "planners/new", "layouts/_nav_bar", "layouts/_footer_bar", "layouts/application"]>
Questions:
1) What kind of test is assert_template? Is it minitest? capybara?
2) What kind of method is get? Is it a rack method that works in rails?
3) What does "assigns" do?
4) What am I doing wrong with this assert_template?
Change it to assert_template :new to make it work; this is testing that the new.html.erb was rendered.
See http://guides.rubyonrails.org/testing.html#testing-templates-and-layouts for more about assert_template and testing views in general.