Rspec tests failing after switching to user-scoped finders - ruby-on-rails

So I started learning rails by writing a small task tracking app. Now I'm trying to refactor to be a little more secure. For example, before updating or destroying, I'm now using a scope to make sure you're looking at your own task.
After doing this though, three tests are no longer passing and I'm not sure how to fix them. What am I doing wrong? Do I need to change the tests or did I forget to do something with the factory?
Thanks!
**Task#controller**
def update
#task = current_user.tasks.where(id: params[:id])
authorize #task
if #task.update_attributes(task_params)
else
flash[:error] = "There was an error updating the todo."
end
respond_with(#task) do |format|
format.html { redirect_to tasks_path }
end
end
def destroy
#task = current_user.tasks.where(id: params[:id])
authorize #task
if #task.destroy
flash[:notice] = "Todo was deleted successfully."
else
flash[:error] = "There was an error deleting the todo."
end
respond_with(#task) do |format|
format.html { redirect_to tasks_path }
end
end
Test 1 and 2
**task_controller_spec**
require 'rails_helper'
describe TasksController do
include Devise::TestHelpers
before do
#user = create(:user)
sign_in #user
end
describe '#update-completed' do
it "updates a task to be completed" do
task = create(:task, user: #user)
expect( task.completed ).to eq(false)
patch :update, id: task.id, task:{completed: true}
task.reload
expect( task.completed ).to eq(true)
end
end
describe '#destroy' do
it "deletes a task" do
task = create(:task, user: #user)
delete :destroy, id: task.id
expect( #user.tasks.count ).to eq(0)
end
end
end
Test 3
**feature_spec**
require 'rails_helper'
feature "Task" do
include Warden::Test::Helpers
Warden.test_mode!
before do
#user = create(:user)
login_as(#user, :scope => :user)
end
feature "completes", js: true do
scenario "a task using a checkbox" do
task = create(:task, user: #user)
visit tasks_path
check("task[completed]")
expect( page ).to have_content('Todo completed!')
end
end
after do
Warden.test_reset!
end
end
which result in...
1) TasksController#update-completed updates a task to be completed
Failure/Error: patch :update, id: task.id, task:{completed: true}
NoMethodError:
undefined method `user' for # <ActiveRecord::AssociationRelation::ActiveRecord_AssociationRelation_Task:0xc1e4450>
# /home/vagrant/.rvm/gems/ruby-2.0.0-p481/gems/activerecord-4.0.9/lib/active_record/relation/delegation.rb:121:in `method_missing'
# /home/vagrant/.rvm/gems/ruby-2.0.0-p481/gems/activerecord-4.0.9/lib/active_record/relation/delegation.rb:68:in `method_missing'
# ./app/policies/application_policy.rb:26:in `update?'
# /home/vagrant/.rvm/gems/ruby-2.0.0-p481/gems/pundit-0.3.0/lib/pundit.rb:70:in `public_send'
# /home/vagrant/.rvm/gems/ruby-2.0.0-p481/gems/pundit-0.3.0/lib/pundit.rb:70:in `authorize'
# ./app/controllers/tasks_controller.rb:28:in `update'
2) TasksController#destroy deletes a task
Failure/Error: delete :destroy, id: task.id
NoMethodError:
undefined method `user' for #<ActiveRecord::AssociationRelation::ActiveRecord_AssociationRelation_Task:0xc51965c>
# /home/vagrant/.rvm/gems/ruby-2.0.0-p481/gems/activerecord-4.0.9/lib/active_record/relation/delegation.rb:121:in `method_missing'
# /home/vagrant/.rvm/gems/ruby-2.0.0-p481/gems/activerecord-4.0.9/lib/active_record/relation/delegation.rb:68:in `method_missing'
# ./app/policies/application_policy.rb:26:in `update?'
# ./app/policies/application_policy.rb:34:in `destroy?'
# /home/vagrant/.rvm/gems/ruby-2.0.0-p481/gems/pundit-0.3.0/lib/pundit.rb:70:in `public_send'
# /home/vagrant/.rvm/gems/ruby-2.0.0-p481/gems/pundit-0.3.0/lib/pundit.rb:70:in `authorize'
# ./app/controllers/tasks_controller.rb:42:in `destroy'
3) Task completes a task with a checkbox
Failure/Error: Unable to find matching line from backtrace
NoMethodError:
undefined method `user' for #<ActiveRecord::AssociationRelation::ActiveRecord_AssociationRelation_Task:0xbe5fb04>
# /home/vagrant/.rvm/gems/ruby-2.0.0-p481/gems/activerecord-4.0.9/lib/active_record/relation/delegation.rb:121:in `method_missing'
# /home/vagrant/.rvm/gems/ruby-2.0.0-p481/gems/activerecord-4.0.9/lib/active_record/relation/delegation.rb:68:in `method_missing'
# ./app/policies/application_policy.rb:26:in `update?'
# /home/vagrant/.rvm/gems/ruby-2.0.0-p481/gems/pundit-0.3.0/lib/pundit.rb:70:in `public_send'
# /home/vagrant/.rvm/gems/ruby-2.0.0-p481/gems/pundit-0.3.0/lib/pundit.rb:70:in `authorize'
# ./app/controllers/tasks_controller.rb:28:in `update'
Task factory
**task factory**
FactoryGirl.define do
factory :task do
description "MyText"
user nil
completed false
end
end

Change
# Returns an ActiveRecord::AssociationRelation
#task = current_user.tasks.where(id: params[:id])
to
# Returns a single Task instance
#task = current_user.tasks.find(params[:id])
find docs: http://api.rubyonrails.org/classes/ActiveRecord/FinderMethods.html#method-i-find

Related

rspec for the controller without factory girl

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)>'

Rails Rspec - undefined method `session'

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

RSpec test redirect

please help check the redirect. i have controller:
def create
#poll = current_user.polls.build(poll_params)
if #poll.save
flash[:success] = 'Голосование создано'
redirect_to user_polls_path(current_user)
else
flash.now[:error] = 'Голосование не создано'
#user = User.find(params[:user_id])
render 'new'
end
end
spec/requests/polls_spec.rb:
require 'rails_helper'
RSpec.describe "Polls", type: :request do
describe "return check" do
it "#create" do
#user = FactoryGirl.create(:user)
#poll = FactoryGirl.create(:poll, user: #user)
# binding.pry ##user OK, #poll OK
expect(#poll).to redirect_to(user_polls_path #user)
end
end
end
but after run in console i get folloew error message:
$ rspec spec/requests
...F
Failures:
1) Polls return 200 status code for GET /polls #create
Failure/Error: expect(#poll.save).to redirect_to(user_polls_path #user)
NoMethodError:
undefined method `response_code' for nil:NilClass
Use
expect(response).to redirect_to(user_polls_path #user)
What redirect_to does behind the scenes is to check the response_code property of the object used in expect.
This is why you are getting the undefined method 'response_code' for nil:NilClass error.

Test not passing: undefined method `authenticate!' for nil:NilClass?

I have the following failure:
Failures:
1) RelationshipsController creating a relationship with Ajax should increment the Relationship count
Failure/Error: xhr :post, :create, relationship: { followed_id: other_user.id }
NoMethodError:
undefined method `authenticate!' for nil:NilClass
# ./spec/controllers/relationships_controller_spec.rb:14:in `block (4 levels) in <top (required)>'
# ./spec/controllers/relationships_controller_spec.rb:13:in `block (3 levels) in <top (required)>'
But it is very strange, if I visit the site, the thing works (the followers counter does increment if I click the Follow button:
And the weirdest thing is that there isn't any authenticate! method in relationships_controller_spec.rb:
require 'spec_helper'
describe RelationshipsController do
let(:user) { FactoryGirl.create(:user) }
let(:other_user) { FactoryGirl.create(:user) }
before { sign_in user }
describe "creating a relationship with Ajax" do
it "should increment the Relationship count" do
expect do
xhr :post, :create, relationship: { followed_id: other_user.id }
end.to change(Relationship, :count).by(1)
end
it "should respond with success" do
xhr :post, :create, relationship: { followed_id: other_user.id }
response.should be_success
end
end
describe "destroying a relationship with Ajax" do
before { user.follow!(other_user) }
let(:relationship) { user.relationships.find_by_followed_id(other_user) }
it "should decrement the Relationship count" do
expect do
xhr :delete, :destroy, id: relationship.id
end.to change(Relationship, :count).by(-1)
end
it "should respond with success" do
xhr :delete, :destroy, id: relationship.id
response.should be_success
end
end
end
Neither in the controller:
class RelationshipsController < ApplicationController
before_filter :authenticate_user!
def create
#user = User.find(params[:relationship][:followed_id])
current_user.follow!(#user)
respond_to do |format|
format.html { redirect_to #user }
format.js
end
end
def destroy
#user = Relationship.find(params[:id]).followed
current_user.unfollow!(#user)
respond_to do |format|
format.html { redirect_to #user }
format.js
end
end
end
What could be the problem?
(By the way, these test were made following the Ruby on Rails Tutorial. After that, I removed all the authentication system because I wanted to use Devise.)
Setting config.include Devise::TestHelpers, :type => :controller no longer works in later versions of Devise. What you need to do is log out an anonymous user to set up the proper variables:
before :each do
sign_out :user
end
I had to add this:
spec_helpers.rb:
RSpec.configure do |config|
config.include Devise::TestHelpers, :type => :controller
end

Ruby on Rails Tutorial Chapter 10 Exercise RSpec Failures

I'm working on the exercises from Chapter 10 of the Rails Tutorial and ran in to a snag with the exercise that has me ensure that an admin user can't delete themselves. My initial idea was to simply check the id of the current user and compare it against params[:id] to make sure that they're not equal. My destroy action in my Users controller looked like this:
def destroy
if current_user.id == params[:id].to_i
flash[:notice] = "You cannot delete yourself."
else
User.find(params[:id]).destroy
flash[:success] = "User destroyed."
end
redirect_to users_path
end
This works perfectly when I test it manually in the app but 3 of my RSpec tests fail with the same "undefined method 'to_i'" error (as seen below):
1) UsersController DELETE 'destroy' as an admin user should destory the user
Failure/Error: delete :destroy, :id => #user
NoMethodError:
undefined method `to_i' for #<User:0x000001032de188>
# ./app/controllers/users_controller.rb:48:in `destroy'
# ./spec/controllers/users_controller_spec.rb:310:in `block (5 levels) in <top (required)>'
# ./spec/controllers/users_controller_spec.rb:309:in `block (4 levels) in <top (required)>'
2) UsersController DELETE 'destroy' as an admin user should redirect to the users page
Failure/Error: delete :destroy, :id => #user
NoMethodError:
undefined method `to_i' for #<User:0x000001032b5850>
# ./app/controllers/users_controller.rb:48:in `destroy'
# ./spec/controllers/users_controller_spec.rb:315:in `block (4 levels) in <top (required)>'
3) UsersController DELETE 'destroy' as an admin user should not allow you to destroy self
Failure/Error: delete :destroy, :id => #admin
NoMethodError:
undefined method `to_i' for #<User:0x0000010327e350>
# ./app/controllers/users_controller.rb:48:in `destroy'
# ./spec/controllers/users_controller_spec.rb:321:in `block (5 levels) in <top (required)>'
# ./spec/controllers/users_controller_spec.rb:320:in `block (4 levels) in <top (required)>'
If I use the params[:id] to find the user and compare it to the current_user like I have below then it works both in the app and in RSpec.
def destroy
if current_user == User.find(params[:id])
flash[:notice] = "You cannot delete yourself."
else
User.find(params[:id]).destroy
flash[:success] = "User destroyed."
end
redirect_to users_path
end
Why would there be a problem in RSpec with the "to_i" method? If anyone is wondering I was leaning toward that approach because I thought it would best to simply compare the current user id to the id of the user targeted for deletion (via the params[:id]) instead of hitting the db to "find" the user.
For reference this is my RSpec test:
describe "DELETE 'destroy'" do
before(:each) do
#user = Factory(:user)
end
...
describe "as an admin user" do
before(:each) do
#admin = Factory(:user, :email => "admin#example.com", :admin => true)
test_sign_in(#admin)
end
it "should destory the user" do
lambda do
delete :destroy, :id => #user
end.should change(User, :count).by(-1)
end
it "should redirect to the users page" do
delete :destroy, :id => #user
response.should redirect_to(users_path)
end
it "should not allow you to destroy self" do
lambda do
delete :destroy, :id => #admin
end.should change(User, :count).by(0)
response.should redirect_to(users_path)
flash[:notice].should =~ /cannot delete yourself/
end
end
end
Any help would be appreciated!
In your specs, try using #user.id instead of #user on your :id parameter (I realize the Tutorial says to just use #user, but something may be going on where the id isn't being properly extracted):
delete :destroy, :id => #user.id
But you may consider restructuring to something like this:
#user = User.find(params[:id])
if current_user == #user
flash[:notice] = "You cannot delete yourself."
else
#user.destroy
flash[:success] = "User destroyed."
end

Resources