I have the following RSpec test defined:
test 'invalid signup information' do
get signup_path
assert_no_difference 'User.count' do
post users_path, params: { user: { name: '',
email: 'user#invalid',
password: 'foo',
password_confirmation: 'bar' } }
end
assert_template 'users/new'
end
And the following Controller:
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
redirect_to new_user_path
else
render :new
end
end
def show
#user = User.find(params[:id])
end
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
end
If I execute rake test I get the following error:
ERROR["test_invalid_signup_information", UserSignupTest, 0.35556070700022246]
test_invalid_signup_information#UserSignupTest (0.36s)
ActionController::ParameterMissing: ActionController::ParameterMissing: param is missing or the value is empty: user
app/controllers/users_controller.rb:23:in `user_params'
app/controllers/users_controller.rb:8:in `create'
test/integration/user_signup_test.rb:7:in `block (2 levels) in <class:UserSignupTest>'
test/integration/user_signup_test.rb:6:in `block in <class:UserSignupTest>'
The test runs without problems if i delete the require statement in user_params. But I do send a user - So why does it fail?
I do not if this is right but in my opinion, you created an integration test but should be a test controller.
See this example
# spec/controllers/contacts_controller_spec.rb
# rest of spec omitted ...
describe "POST create" do
context "with valid attributes" do
it "creates a new contact" do
expect{
post :create, contact: {name: 'test'}
}.to change(Contact,:count).by(1)
end
more info for integration test
Related
I am trying to write spec code for my controller it gets failed. And i am not sure where it gets failed.
Controller Code
def index
#users = User.all
end
def update
authorize! :update, #user
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to user_index_path }
else
format.html { render :index }
end
end
end
private
def set_user
#user = User.find(params[:id])
end
def user_params
params.permit(:active)
end
Spec Code for the above controller
RSpec.describe UserController, type: :controller do
describe 'GET #index' do
let(:user) {User.create!(name: "hari")}
context 'with user details'do
it 'loads correct user details' do
get :index
expect(response).to permit(:user)
end
end
context 'without user details' do
it 'doesnot loads correct user details' do
get :index
expect(response).not_to permit(:user)
end
end
end
describe 'Patch #update' do
context 'when valid params' do
let(:attr) do
{active: 'true'}
end
before(:each) do
#user = subject.current_user
put :update, params: { user: attr }
#user.reload
end
it 'redirects to user_index_path ' do
expect(response).redirect_to(user_index_path)
end
it 'sets active state' do
expect(#user.active?('true')).to be true
end
end
context 'when invalid param' do
let(:attr) do
{active: 'nil'}
end
before(:each) do
#user = subject.current_user
put :update, params: { user: attr }
#user.reload
end
it 'render index' do
expect(respone.status).to eq(200)
end
it 'doesnot change active state' do
expect(#user.active?(nil)).to be true
end
end
end
end
I am just a beginner and tried the spec code for my controller by checking https://relishapp.com/rspec/rspec-rails/docs/gettingstarted. Can you help me where my spec goes wrong or could anyone give me a few test examples for these methods or could redirect me to an rspec guide? the index method is getting failed
and my
terminal log is
1) UserController GET #index with user details loads correct user details
Failure/Error: expect(response).to permit(:user)
NoMethodError:
undefined method `permit' for #<RSpec::ExampleGroups::UserController::GETIndex::WithUserDetails:0x00005614152406b0>
Did you mean? print
# ./spec/controllers/user_controller_spec.rb:10:in `block (4 levels) in <top (required)>'
I have run into 4 errors on section 9.2.2.
Errors
ERROR["test_unsuccessful_edit", UsersEditTest, 2015-11-05 04:35:59 -0600]
test_unsuccessful_edit#UsersEditTest (1446719759.23s)
NoMethodError: NoMethodError: undefined method correct_user?' for #<UsersController:0x007fcdf48ad378>
app/controllers/users_controller.rb:58:incorrect_user'
test/integration/users_edit_test.rb:10:in block in <class:UsersEditTest>'
app/controllers/users_controller.rb:58:incorrect_user'
test/integration/users_edit_test.rb:10:in `block in '
ERROR["test_successful_edit", UsersEditTest, 2015-11-05 04:35:59 -0600]
test_successful_edit#UsersEditTest (1446719759.28s)
NoMethodError: NoMethodError: undefined method correct_user?' for #<UsersController:0x007fcdefcea198>
app/controllers/users_controller.rb:58:incorrect_user'
test/integration/users_edit_test.rb:21:in block in <class:UsersEditTest>'
app/controllers/users_controller.rb:58:incorrect_user'
test/integration/users_edit_test.rb:21:in `block in '
ERROR["test_should_redirect_edit_when_logged_in_as_wrong_user", UsersControllerTest, 2015-11-05 04:35:59 -0600]
test_should_redirect_edit_when_logged_in_as_wrong_user#UsersControllerTest (1446719759.42s)
NoMethodError: NoMethodError: undefined method correct_user?' for #<UsersController:0x007fcdf529f778>
app/controllers/users_controller.rb:58:incorrect_user'
test/controllers/users_controller_test.rb:29:in block in <class:UsersControllerTest>'
app/controllers/users_controller.rb:58:incorrect_user'
test/controllers/users_controller_test.rb:29:in `block in '
ERROR["test_should_redirect_update_when_logged_in_as_wrong_user", UsersControllerTest, 2015-11-05 04:35:59 -0600]
test_should_redirect_update_when_logged_in_as_wrong_user#UsersControllerTest (1446719759.44s)
NoMethodError: NoMethodError: undefined method correct_user?' for #<UsersController:0x007fcdf531e118>
app/controllers/users_controller.rb:58:incorrect_user'
test/controllers/users_controller_test.rb:36:in block in <class:UsersControllerTest>'
app/controllers/users_controller.rb:58:incorrect_user'
test/controllers/users_controller_test.rb:36:in `block in '
32/32: [======================] 100% Time: 00:00:01, Time: 00:00:01
Finished in 1.70355s
32 tests, 64 assertions, 0 failures, 4 errors, 0 skips
Users_controller.rb
class UsersController < ApplicationController
before_action :logged_in_user, only: [:edit, :update]
before_action :correct_user, only: [:edit, :update]
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
log_in #user
flash[:success] = "Welcome to the Sample App!"
redirect_to #user
else
render 'new'
end
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params)
flash[:success] = "Profile updated"
redirect_to #user
else
render 'edit'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
# Before Filters
# Confirms a logged-in user.
def logged_in_user
unless logged_in?
flash[:danger] = "Please log in."
redirect_to login_url
end
end
# Confirms the correct user.
def correct_user
#user = User.find(params[:id])
redirect_to(root_url) unless correct_user?(#user)
end
end
User_controller_test
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 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 "should redirect update when logged in as wrong user" do
log_in_as(#other_user)
patch :update, id: #user, user: { name: #user.name, email: #user.email }
assert flash.empty?
assert_redirected_to root_url
end
end
users.yml
michael:
name: Michael Example
email: michael#example.com
password_digest: <%= User.digest('password') %>
archer:
name: Sterling Archer
email: duchess#example.gov
password_digest: <%= User.digest('password') %>
users_edit_test
require 'test_helper'
class UsersEditTest < ActionDispatch::IntegrationTest
def setup
#user = users(:michael)
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
I think that is all that would be needed to help. I have been struggling for some time now. This is my first post, sorry if it isn't easy to read.
correct_user? isn't defined anywhere.
redirect_to(root_url) unless correct_user?(#user)
Rails's syntactic sugar is going to look for a model flag correct_user or a boolean-returning function #correct_user? getter. I'm assuming that you're trying to validate that an update request from a user actually belongs to the correct user. To do this you must have current_user stored in a session, and then check the request param[:id] == current_user.id
Im testing my Session Controller but Im getting this error, the log in feature works, I tested it on the browser but Im new to testing on Rspec and can't get this to work
Failure/Error: expect(response.session[:user_id]).to eq(#user_attr.id)
NoMethodError:
undefined method `session' for #<ActionController::TestResponse:0xd30df10>
# ./spec/controllers/sessions_controller_spec.rb:20:in `block (3 levels) in <top (required)>'
This is the code of my controller:
def new
#user = User.new
end
def create
#user = User.find_by(username: params[:user][:username])
if #user && #user.authenticate(params[:user][:password])
session[:user_id] = #user.id
redirect_to root_path
else
render :new
end
end
Rspec code:
require 'rails_helper'
RSpec.describe SessionsController, type: :controller do
describe "get Login page" do
it "returns http status" do
get :new
expect(response).to have_http_status(:success)
end
end
describe "session" do
before(:each) do
#user = FactoryGirl.create(:user)
#user_attr = FactoryGirl.attributes_for(:user)
end
it "gives session" do
request.session[:user_id] = nil
post :create, user: #user_attr
expect(response.session[:user_id]).to eq(#user_attr.id)
end
end
end
session is a variable that is available without the request/response context as shown in your example. If you want to manipulate it or check the values it contains, you can simply do something like this:
it "gives session" do
session[:user_id] = nil
post :create, user: #user_attr
expect(session[:user_id]).to eq(#user_attr.id)
end
I have this integration test that controls that a logged in user can't edit another user's data.
The code is mostly from Hartl's RoR tutorial.
Those 2 tests fail but when I test myself, the application is behaving as expected (I can't open the edit page of another user)
When I run rake, I get (lines 31 & 38 are assert flash.empty?):
FAIL["test_should_redirect_edit_when_logged_in_as_wrong_user", UsersControllerTest, 2015-07-24 12:15:07 +0800]
test_should_redirect_edit_when_logged_in_as_wrong_user#UsersControllerTest (1437711307.70s)
Failed assertion, no message given.
test/controllers/users_controller_test.rb:31:in `block in <class:UsersControllerTest>'
FAIL["test_should_redirect_update_when_logged_in_as_wrong_user", UsersControllerTest, 2015-07-24 12:15:07 +0800]
test_should_redirect_update_when_logged_in_as_wrong_user#UsersControllerTest (1437711307.71s)
Failed assertion, no message given.
test/controllers/users_controller_test.rb:38:in `block in <class:UsersControllerTest>'
Then, if I comment out assert flash.empty?, I get this (lines 32 & 39 are assert_redirected_to root_url):
FAIL["test_should_redirect_update_when_logged_in_as_wrong_user", UsersControllerTest, 2015-07-24 12:15:08 +0800]
test_should_redirect_update_when_logged_in_as_wrong_user#UsersControllerTest (1437711308.02s)
Expected response to be a redirect to <http://test.host/> but was a redirect to <http://test.host/login>.
Expected "http://test.host/" to be === "http://test.host/login".
test/controllers/users_controller_test.rb:39:in `block in <class:UsersControllerTest>'
FAIL["test_should_redirect_edit_when_logged_in_as_wrong_user", UsersControllerTest, 2015-07-24 12:15:08 +0800]
test_should_redirect_edit_when_logged_in_as_wrong_user#UsersControllerTest (1437711308.03s)
Expected response to be a redirect to <http://test.host/> but was a redirect to <http://test.host/login>.
Expected "http://test.host/" to be === "http://test.host/login".
test/controllers/users_controller_test.rb:32:in `block in <class:UsersControllerTest>'
users_controller_test.rb
require 'test_helper'
class UsersControllerTest < ActionController::TestCase
def setup
#user = users(:guillaume)
#other_user = users(:peter)
end
## other tests ##
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 "should redirect update when logged in as wrong user" do
log_in_as(#other_user)
patch :update, id: #user, user: {name: #user.name, email: #user.email}
assert flash.empty?
assert_redirected_to root_url
end
the lines that fail are the assert and assert_redirect lines
test_helper.rb
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
require 'minitest/reporters'
Minitest::Reporters.use!
class ActiveSupport::TestCase
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
fixtures :all
# Returns true if a test user is logged in
def is_logged_in?
!session[:user_id].nil?
end
# Logs in a test user
def log_in_as(user, options = {})
password = options[:password] || 'password'
if integration_test?
post login_path, session: {email: user.email,
password: password}
else
session[:user] = user.id
end
end
private
# Return true inside an integration test
def integration_test?
defined?(post_via_redirect)
end
end
users_controller.rb
class UsersController < ApplicationController
before_action :logged_in_user, only: [:edit, :update]
before_action :correct_user, only: [:edit, :update]
## new and create methods here ##
def edit
#user = User.find(params[:id])
end
def update
if #user.update_attributes(user_params)
flash[:success] = "Profile updated"
redirect_to #user
else
render 'edit'
end
end
private
def user_params
params.require(:user).permit(:name,
:email,
:club_id,
:access_key,
:password,
:password_confirmation)
end
## Before filters ##
# Confirms a logged-in user
def logged_in_user
unless logged_in?
flash[:danger] = "Please log in."
redirect_to login_url
end
end
# Confirms a correct user
def correct_user
#user = User.find(params[:id])
redirect_to(root_url) unless current_user?(#user)
end
end
users.yml
guillaume:
name: Guillaume
email: guillaume#example.com
password_digest: <%= User.digest('password') %>
peter:
name: Peter
email: peter#example.com
password_digest: <%= User.digest('password') %>
I went though the code several times but I can't find what's missing.
This is also the first app I'm trying to develop on my own, so for this part, I'm working from Hartl's rails tutorial material.
I am trying to write tests and application code to redirect users who are already signed-in to the root_path if they try to CREATE a user or visit the NEW user path.
Here are the tests I have written in user_pages_spec.rb:
describe "for signed in users" do
let(:user) { FactoryGirl.create(:user) }
before { sign_in user }
describe "using a 'new' action" do
before { get new_user_path }
specify { response.should redirect_to(root_path) }
end
describe "using a 'create' action" do
before { post users_path }
specify { response.should redirect_to(root_path) }
end
end
UsersController:
class UsersController < ApplicationController
before_action :unsigned_in_user, only: [:create, :new]
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
sign_in #user
flash[:success] = "Welcome to the Sample App!"
redirect_to #user
else
render 'new'
end
end
private
# Before filters
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
def unsigned_in_user
puts signed_in?
redirect_to root_url, notice: "You are already signed in." unless !signed_in?
end
end
The puts signed_in? returns false. I am assuming this is the problem because I would expect it to return true. Here are the errors after running the tests using rspec. Any help is appreciated.
Failures:
1) User pages for signed in users using a 'create' action
Failure/Error: before { post users_path }
ActionController::ParameterMissing:
param not found: user
# ./app/controllers/users_controller.rb:52:in `user_params'
# ./app/controllers/users_controller.rb:20:in `create'
# ./spec/requests/user_pages_spec.rb:162:in `block (4 levels) in <top (required)>'
2) User pages for signed in users using a 'new' action
Failure/Error: specify { response.should redirect_to(root_path) }
Expected response to be a <redirect>, but was <200>
# ./spec/requests/user_pages_spec.rb:158:in `block (4 levels) in <top (required)>'
Within the sessions_helper.rb file:
def signed_in?
!current_user.nil?
end
In spec/support/utilities.rb:
def sign_in(user, options={})
if options[:no_capybara]
# Sign in when not using Capybara.
remember_token = User.new_remember_token
cookies[:remember_token] = remember_token
user.update_attribute(:remember_token, User.encrypt(remember_token))
else
visit signin_path
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
end
end
Were you able to get your tests to pass?
In case you weren't, I had the same problem as you today, and was able to get the tests to pass by making two changes to the tests - passing a user hash when POSTing, and using the no_capybara option on the sign_in method, since get and post are not capybara methods and I think RSpec doesn't behave as we might expect if we switch from capybara to non-capybara methods within the same test.
describe "for signed-in users" do
let(:user) { FactoryGirl.create(:user) }
before { sign_in user, no_capybara: true }
describe "using a 'new' action" do
before { get new_user_path }
specify { response.should redirect_to(root_path) }
end
describe "using a 'create' action" do
before do
#user_new = {name: "Example User",
email: "user#example.com",
password: "foobar",
password_confirmation: "foobar"}
post users_path, user: #user_new
end
specify { response.should redirect_to(root_path) }
end
end
Same answer as najwa, but I used the FactoryGirl user with the Rails attributes method to avoid duplication:
describe "using a 'create' action" do
before { post users_path, user: user.attributes }
specify { response.should redirect_to(root_path) }
end
Helps to keep the data decoupled from the test code.