Undefined local variable or method params in Rspec - ruby-on-rails

Hi I am implementing a method to delete a user account in my web application. My controller:
class UsersController < ApplicationController
before_filter :set_current_user
def user_params
params.require(:user).permit(:user_id, :first_name, :last_name, :email, :password, :password_confirmation)
end
def delete_account
#user = User.find_by_id(params[:id])
if #user.present?
#user.destroy
flash[:notice] = "User Account Deleted."
end
redirect_to root_path
end
def destroy
User.delete(:user_id)
redirect_to root_path
end
end
My rspec:
require 'spec_helper'
require 'rails_helper'
require'factory_girl'
describe UsersController do
describe "delete account" do
before :each do
#fake_results = FactoryGirl.create(:user)
end
it "should call the model method that find the user" do
expect(User).to receive(:find).with(params[:id]).and_return (#fake_results)
end
it "should destroy the user account from the database" do
expect{delete :destroy, id: #fake_results}.to change(User, :count).by(-1)
end
it "should redirect_to the home page" do
expect(response).to render_template(:home)
end
end
end
The first error is
Failure/Error: expect(User).to receive(:find).with(params[:id]).and_return (#fake_results)
NameError:undefined local variable or method `params' for #<RSpec::ExampleGroups::UsersController::DeleteAccount:0x00000007032e18>
I know what this error means but I don't know how to correct it. How can I pass the user id from the controller to rspec?
The second error is:
Failure/Error: expect(response).to render_template(:home)
expecting <"home"> but rendering with <[]>
I think there is something wrong with my controller method. It should redirect to the home page but it doesn't.

params is not available in your tests, it's available in your controller.
Looks like you create a test user in your test:
#fake_results = FactoryGirl.create(:user)
Then, you can use the id of this test user (#fake_results.id) instead of trying to use params[:id]:
expect(User).to receive(:find).with(#fake_results.id).and_return (#fake_results)
Although, you may want to change the name from #fake_results to something more meaningful e.g. test_user or so.
However, this should fix both of your problems as your second problem is there because of the first problem. As it's failing to delete the user in the first place, it's not being redirected to the root path and hence the home template is not rendering.

Related

Login as a specific user with RSpec

I am trying to spec the following.
I need to return all entities that are linked to the logged in user. Subsequently I need to create the user before the fact and then ensure that the specific user is logged in. I am struggling to achieve this with controller macros. My specs are failing as follows
1) Yougov::Surveys::ProfilesController GET :index returns all profiles linked to the loged in user with the same country and client as the linked survey
Failure/Error: sign_in user
RuntimeError:
Could not find a valid mapping for nil
# /Users/donovan.thomson/.rvm/gems/ruby-2.2.2#insight-app/gems/devise-2.2.8/lib/devise/mapping.rb:42:in `find_scope!'
# /Users/donovan.thomson/.rvm/gems/ruby-2.2.2#insight-app/gems/devise-2.2.8/lib/devise/test_helpers.rb:46:in `sign_in'
# ./spec/support/controller_macros.rb:17:in `block in login_specific_user'
So a basic scaffolding of my controller looks as follows :
class ProfilesController < ApplicationController
def index
render json: Profile.where(user_id: current_user.id)
end
end
I assume this means the user is not being logged in as I would expect
My spec is as follows
require 'spec_helper'
describe ProfilesController, type: :controller do
before do
#user = FactoryGirl.create :user
#profile = FactoryGirl.create :profile, user: #user
FactoryGirl.create :profile
end
describe "GET :index" do
login_specific_user(#user)
it "returns all profiles linked to the loged in user with the same country and client as the linked survey" do
get :index
expect(response.body).to eq(#profile.to_json)
end
end
end
My controller macro's are as follows:
module ControllerMacros
def login_admin
before :each do
sign_in ControllerMacros.get_user(#request, :admin, :admin_user)
end
end
def login_user
before :each do
sign_in ControllerMacros.get_user(#request, :user)
end
end
def login_specific_user(user)
before :each do
sign_in user
end
end
class << self
def get_user(req, mapping, type=mapping)
req.env["devise.mapping"] = Devise.mappings[mapping]
user = FactoryGirl.create(type)
user.confirm!
user
end
end
end
I solved this by not using controller macros and just adding the following to my before block
before do
#user = FactoryGirl.create :user
#user.confirm!
sign_in #user
end

Controller spec does not work

Im writing a simple rspec for a controller. The sign_in function does not seem to work however (although I included the rails_helper).
Any thoughts on what goes wrong here?
require 'rails_helper'
describe WikisController do
include Devise::TestHelpers
before do
#user = build(:user)
#wiki = build(:wiki)
sign_in #user
end
describe "#create" do
expect(#user.votes).to be_nil
post :create, {wiki_id: #wiki.id}
expect {#user.wikis}.to be (1)
end
end
You need to create the user, not build it, change
#user = build(:user)
to
#user = create(:user)

Count; find User with id= Minitest

I am following Michael Hartl's Ruby on Rails tutorial and I am not sure why I am getting this Error when according to the tutorial everything should pass:
1) Error:
UsersControllerTest#test_should_get_show:
ActiveRecord::RecordNotFound: Couldn't find User with 'id'=
app/controllers/users_controller.rb:7:in `show'
test/controllers/users_controller_test.rb:10:in `block in <class:UsersControllerTest>'
My minitest:
require 'test_helper'
class UsersSignupTest < ActionDispatch::IntegrationTest
# add invalid information and test that the User.count never changes
# also test that the sign up path is visited after invalid sign up
test "invalid signup information" do
# visit the signup path using get
get signup_path
assert_no_difference "User.count" do
post users_path, user: { name: "", email: "user#invalid", password: "foo", password_confirmation: "bar"}
end
assert_template "users/new"
end
end
I compared my users_controller to the official github tutorial and it looks the same
Users controller:
class UsersController < ApplicationController
def new
#user = User.new
end
def show
#user = User.find(params[:id])
end
def create
# strong parameters
#user = User.new(user_params)
if #user.save
# handle save
else
render 'new'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
end
I dont really understand why id is being searched for as well. My database is empty with no users. I am currently testing that inputing invalid parameters for sign up will not add another user.
my UserControllerTest:
require 'test_helper'
class UsersControllerTest < ActionController::TestCase
test "should get new" do
get :new
assert_response :success
end
test "should get show" do
get :show
assert_response :success
end
end
Show renders a page for specific user, so you need to pass it the id param. Change the test to:
test "should get show" do
user = User.create
get :show, id: user.id
assert_response :success
end
FYI, A small breakdown of the error message:
1) Error:
Error
UsersControllerTest#test_should_get_show:
In test test_should_get_show in class UserControllerTest
ActiveRecord::RecordNotFound: Couldn't find User with 'id'=
Database doesn't contain User object with empty id
app/controllers/users_controller.rb:7:in `show'
File and line that directly caused the error
test/controllers/users_controller_test.rb:10:in `block in <class:UsersControllerTest>'
File and line where the action originated from.

testing a redirect in rspec and devise

i want to to write a controler test to check that on a successful sign in, a user is redirected to a certain page. the current test I have at the moment is returning a 200.
require 'rails_helper'
RSpec.describe Admin::EntriesController, :type => :controller do
setup_factories
describe "after login" do
it "should redirect to pending after logged in" do
sign_in admin
expect(response).to redirect_to('admin/entries/pending')
end
end
end
which returns
Failure/Error: expect(response).to redirect_to('admin/entries/pending')
Expected response to be a <redirect>, but was <200>
the relevant controller
class AdminController < Devise::RegistrationsController
before_filter :authenticate_admin!
protected
def after_sign_in_path_for(admin)
pending_admin_entries_path
end
end
am I attempting this is in the right way, where am i going wrong?
thanks
sign_in user in RSpec doesn't make a request so you cannot test the redirection.
For after_sign_in_path, you can test like this:
it 'redirects user to pending admin entries path' do
expect(controller.after_sign_in_path(user)).to eq pending_admin_entries_path
end

Testing a rails controller method that is designed to change data of a variable

I have the following code in the controller:
# guest to user sign up view. Method that prepares a guest to become a user by emptying it's generic
#e-mail address.
def guest_signup
if !current_user.guest
redirect_to root_url
end
#user = current_user
#user.email = ""
end
This controller just makes sure that the outcome (a form) doesn't have a generic e-mail address in an input field that the user gets assigned when he is using the application as guest.
I am trying to write an rspec test for it and I have no idea how to properly do it... I know this may sound like development-driven testing rather than the opposite but I need an idea.
Currently I have this that doesn't work:
require 'spec_helper'
describe UsersController do
describe "Guest Signup" do
it "should prepare guest with random e-mail user for signup form, emptying the e-mail" do
current_user = User.create(:email => "guest_#{Time.now.to_i}#{rand(99)}#example.com", :password => "#{Time.now.to_i}#{rand(99999999)}", :guest => true)
get :guest_signup, :user => #user.id
expect(#user.email).to eq ('')
end
end
end
How is #user assigned here? Presumably after the guest_signup method is called. Since #user is referenced in the call to guest_signup, you have an order of operations problem here.
Maybe you should be calling:
get :guest_signup, :user => current_user.id
describe UsersController do
describe 'Guest Signup' do
let(:user) { mock.as_null_object }
before(:each) { controller.stub(:current_user) { user } }
context 'when guest does not exist' do
before(:each) { user.stub(:guest) { false } }
it 'redirects to root path' do
get :guest_signup
response.should redirect_to root_path
end
end
context 'when guest exists' do
before(:each) { user.stub(:guest) { true } }
it 'should prepare guest with random e-mail user for signup form, emptying the e-mail' do
get :guest_signup
assigns(#user).should == user
assigns(#email).should be_empty
end
end
end
end

Resources