I'm working my way through Chapter 9 of https://www.railstutorial.org/ and am running into trouble with an integration test.
The test looks like this:
class UsersLoginTest < ActionDispatch::IntegrationTest
...
test "login with remembering" do
log_in_as(#user, remember_me: '1')
assert_not_empty cookies['remember_token']
end
...
end
The call to log_in_as is a function added to ActionDispatch::IntegrationTest in my test_helper, and appears to be working as expected. One of the side effects of this function is that a cookie named 'remember_token' gets set. However, the assertion fails with the message:
FAIL["test_login_with_remembering", UsersLoginTest, 14.115229932998773]
test_login_with_remembering#UsersLoginTest (14.12s)
Expected nil (NilClass) to respond to #empty?.
test/integration/users_login_test.rb:48:in `block in <class:UsersLoginTest>'
Any idea what's going on here? Running the test in the debugger seems to suggest that the cookies object doesn't contain anything that looks like I would expect (there are a couple of cookies that I'm setting in the app, and none of them are appearing). All google turns up is a bunch of people suggesting that it's a bad idea to access cookies in integration tests. I'm running Rails 5.1.2 if that helps.
Rails earlier versions change the behavior, the Rails tutorial seems to be deprecated due to an older version Rails.
To pass tests you can forget helper like:
class UsersLoginTest < ActionDispatch::IntegrationTest
...
test "remember if checked in login" do
post login_path, params: { session: { email: #user.email, password: "password", remember_me: '1'}}
assert_not_empty cookies[:remember_token]
end
test "no remember if not checked in login" do
post login_path, params: { session: { email: #user.email, password: "password", remember_me: '1'}}
post login_path, params: { session: { email: #user.email, password: "password", remember_me: '0'}}
assert_empty cookies[:remember_token]
end
...
end
Related
So I am trying to create a simple integration test in Rails. I want to test my login form. I just can't really figure out how to pass my params correctly. My .yml file is called agents.yml. My fixture file is:
one:
first_name: firstNameTest
last_name: lastNameTest
email: test#test.com
encrypted_password: <%= Devise::Encryptor.digest(Agent, '123456') %>
that should be ok.
Two tests I tried which both give me an error. The first one, following the Ruby.docs:
class FlowsTest < ActionDispatch::IntegrationTest
test "Login and navigate" do
get "/agents/sign_in"
post "/agents/sign_in", email: agents(:one).email, password:
agents(:one).password
follow_redirect!
end
end
the second version:
class FlowsTest < ActionDispatch::IntegrationTest
test "Login and navigate" do
get "/agents/sign_in"
post "/agents/sign_in", agent: {email: agents(:one).email, password: '123456'}
follow_redirect!
end
end
Both throw me an error:
Error:
FlowsTest#test_Login_and_navigate:
ArgumentError: unknown keywords: email, password
test/integration/Flows_test.rb:6:in `block in <class:FlowsTest>'
I guess I'm passing in the params in a wrong way. Because email and password should be taken from the fixtures, or am I wrong? Can anyone help? Would be very much appreciated. Thank you all in advance!
Solved by:
require 'test_helper'
class FlowsTest < ActionDispatch::IntegrationTest
fixtures :agents
def test_login
get "/agents/sign_in"
assert_equal 200, status
post "/agents/sign_in", params: { email: agents(:one).email,
password: agents(:one).password }
follow_redirect!
assert_equal 200, status
assert_equal "/", path
end
end
I recently installed Devise in my app to handle auth, replacing the auth system from Michael Hartl's tutorial. It's working fine in the app itself, but I can't get my tests to auth properly, so they're pretty much all failing, which makes me sad. I'm using Rails 4 with Minitest.
Here's an example of one of my controller tests that fails:
learning_resources_controller_test.rb
require 'test_helper'
class LearningResourcesControllerTest < ActionController::TestCase
def setup
#user = users(:testuser1)
end
test "user can submit new resource" do
sign_in #user # Devise helper
post :create, {:learning_resource => {:name => "My resource"}}
resource = assigns(:learning_resource)
assert_redirected_to topic_path(#topic1, :learning_resource_created => "true")
end
end
test_helper.rb
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
class ActiveSupport::TestCase
fixtures :all
# Return true is test user is signed in
def is_signed_in?
!session[:user_id].nil?
end
def sign_in_as(user, options = {})
password = options[:password] || 'password'
remember_me = options[:remember_me] || '1'
if integration_test?
# Sign in by posting to the sessions path
post signin_path, session: { email: user.email,
password: password,
remember_me: remember_me }
else
# Sign in using the session
session[:user_id] = user.id
end
end
private
def integration_test?
defined?(post_via_redirect)
end
end
class ActionController::TestCase
include Devise::TestHelpers
end
fixtures/users.yml
testuser1:
name: Test User 1
email: testuser1#mydumbdomain.com
password_digest: <%= User.digest('password') %>
The assert_redirected_to in the test always fails as the redirect is the sign in page instead of the topic page. All of my other tests fail in similar ways, indicating the user isn't signed in. I have scoured the Devise wiki and docs, but most of them cover testing with Rspec, not Minitest.
I tried using byebug within the test after the sign_in to check out the session, and I get this:
(byebug) session.inspect
{"warden.user.user.key"=>[[336453508], ""]}
If I try to call the :create, I get this error:
DEPRECATION WARNING: ActionDispatch::Response#to_ary no longer
performs implicit conversion to an array. Please use response.to_a
instead, or a splat like status, headers, body = *response. (called
from puts at
/Users/me/.rbenv/versions/2.2.2/lib/ruby/2.2.0/forwardable.rb:183)
302 {"X-Frame-Options"=>"SAMEORIGIN", "X-XSS-Protection"=>"1;
mode=block", "X-Content-Type-Options"=>"nosniff",
"Location"=>"http://test.host/signup",
"Set-Cookie"=>"request_method=POST; path=/",
"Content-Type"=>"text/html; charset=utf-8"}
Any ideas what I'm missing here?
The error is with hash
post :create, {:learning_resource => {:name => "My resource"}}
Try
post :create, :learning_resource => {:name => "My resource"}
When I have assert user_signed_in? in an integration test it says the method is undefined. Is there a way I can use this method in my testing? I am using rails 4 and the latest version of devise. Here is my test file:
require 'test_helper'
class UsersSignupTest < ActionDispatch::IntegrationTest
test "valid signup information" do
get new_user_registration_path
assert_difference 'User.count', 1 do
post_via_redirect user_registration_path,
user: { first_name: "Example",
last_name: "User",
email: "user#example.org",
password: "password",
password_confirmation: "password" }
end
assert_template 'activities/index'
assert user_signed_in?
end
The user_signed_in? method is included in Devise::Controllers::Helpers module which isn't available in your integration tests so you can't use it.
You have the option of either mocking this method (which won't really meet your testing needs) or testing that a user is signed in by looking for page content that will only render when the user is signed in like Logout link for example or Signed in successfully message.
For your controller tests you can use devise test helpers include Devise::TestHelpers which exposes a sign_in and sign_out methods for you, more on that in the Gem's home page https://github.com/plataformatec/devise
you can't use user_signed_in? inside integration tests as mentioned here before me, but you can write a simple helper method to help you mimic this behavior
what i did is ,inside the test_helper.rb :
def is_logged_in?
request.env['warden'].authenticated?(:user)
end
it's a pretty hacky solution but it does the trick
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.
I'm creating a Ruby on Rails application, and am trying to run a test involving my User model to see if the "Remember me" feature works. I'm using Rails' inbuilt cookies hash to store the cookies, and the session hash to store the current session. I've run various tests (integration, model, and controller) where I use the session variable, but for some reason in this particular case it isn't being recognized.
NameError: undefined local variable or method `session' for #<UserTest:0x0000000658b5c8>
The error happens in the else block in the log_in_as method below:
test_helper.rb
...
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
I call log_in_as in my User test; both of these tests fail.
user_test.rb
require 'test_helper'
...
test "login with remembering" do
log_in_as(#user, remember_me: '1')
assert_not_nil cookies['remember_token']
end
test "login without remembering" do
log_in_as(#user, remember_me: '0')
assert_nil cookies['remember_token']
end
...
And when I remove that line of code from the helper, an error is thrown saying that cookies isn't recognized. What is the issue here?
The session hash isn't available in models, only in controllers and views and controller and view tests.