RSpec functional test is redirecting to the wrong place - testing

I need some help guys, trying to make this test to pass but with no luck.
describe 'PUT posts/:id' do
describe 'with valid attributes' do
let(:mock_post) { mock_model('Post', title: 'hey! iam a mock!', description: 'a sexy model', location: 'everywhere') }
login_user
it 'should update the object and redirect to the post' do
Post.stub!(:find).with(mock_post.id).and_return(mock_post)
Post.any_instance.should_receive(:update_attributes).with({"these" => "params"}).and_return(true)
response.should redirect_to post_path(mock_post)
put :update, id: mock_post.id, post: { these: 'params' }
end
it 'should have a current_user' do
subject.current_user.should_not be_nil
end
end
For now, I have something like the above test and getting the following error:
1) PostsController PUT posts/:id with valid attributes should update the object and redirect to the post
Failure/Error: response.should redirect_to post_path(mock_post)
Expected response to be a <:redirect>, but was <200>
# ./spec/controllers/posts_controller_spec.rb:200:in `block (4 levels) in <top (required)>'
PostsController:
class PostsController < ApplicationController
load_and_authorize_resource except: [:index, :show]
before_filter :authenticate_user!, except: [:index, :show, :tags]
before_filter :find_post, only: [:show, :edit, :update, :suspend, :suspend_alert]
def update
if #post.update_attributes(params[:post])
flash[:success] = 'Cool.'
redirect_to post_path(#post)
else
render :edit
end
end
protected
def find_post
#post = Post.find(params[:id])
end
end
Also, how should I write the test for the render :edit part?

Your spec never calls the controller action. Try adding:
Post.any_instance.
should_receive(:update_attributes).
with({"these" => "params"})
put :update, :id => "1", :post => {"these" => "params"}
To test the two paths that result from the call to update_attributes, substitute the value in the expectation:
it "should redirect when successful" do
Post.any_instance.
should_receive(:update_attributes).
with({"these" => "params"}).
and_return(true)`
response.should_redirect_to(post_path(#mock_post))
put :update, :id => "1", :post => {"these" => "params"}
end
it "should render the edit page when unsuccessful" do
Post.any_instance.
should_receive(:update_attributes).
with({"these" => "params"}).
and_return(false)`
response.should render_template("edit")
put :update, :id => "1", :post => {"these" => "params"}
end

Related

how to pass id of the controller

How to pass id. my controller is:
class AttachementsController < ApplicationController
def index
#pdf = Attachement.find(params[:resume_id])
# send_file(#pdf.file.url, :type => 'application/pdf', :disposition => 'inline',:stream => false)
redirect_to #pdf.file.url
end
end
and my test case of the controller is:
require 'spec_helper'
describe AttachementsController do
describe "GET 'index'" do
it "should be successful" do
get 'index', :id => "#attachements.id"
response.should be_success
end
end
end
and my error is:
AttachementsController GET 'index' should be successful
Failure/Error: get 'index', :id => "#attachements.id"
ActiveRecord::RecordNotFound:
Couldn't find Attachement without an ID
# ./app/controllers/attachements_controller.rb:3:in `index'
# ./spec/controllers/attachements_controller_spec.rb:7:in `block (3 levels) in <top (required)>'
You don't need the quotes around #attachements.id.
get 'index', :id => #attachements.id

rails if else check fails then rescue

I have 2 methods in my controller for finding the user (notice the enabled_only scope):
before_filter :find_user, :only => :show
before_filter :find_any_user, :only => [:edit, :update, :destroy]
def find_user
#user = User.enabled_only.find(params[:id])
rescue ActiveRecord::RecordNotFound
flash[:alert] = "The user you were looking for could not be found"
redirect_to root_path
end
def find_any_user
#user = User.find(params[:id])
rescue ActiveRecord::RecordNotFound
flash[:alert] = "The user you were looking for could not be found"
redirect_to root_path
end
Surely these could be merged into one method that checks whether :action == 'show' but I couldn't get the rescue to catch the error. I tried something like the following but it didn't work:
before_filter :find_user, :only => [:show, :edit, :update, :destroy]
def find_user
#user = if :action == 'show'
User.enabled_only.find(params[:id])
else
User.find(params[:id])
end
rescue ActiveRecord::RecordNotFound
flash[:alert] = "The user you were looking for could not be found"
redirect_to root_path
end
Please advise on how this can be done.
Thanks
You need to wrap the code you want to 'protect' between a beginand a rescue
before_filter :find_user, :only => [:show, :edit, :update, :destroy]
def find_user
begin
#user = if :action == 'show'
User.enabled_only.find(params[:id])
else
User.find(params[:id])
end
rescue ActiveRecord::RecordNotFound
flash[:alert] = "The user you were looking for could not be found"
redirect_to root_path
end
end
and by the way your test :action == 'show' can never be true. :action is a symbol which value is :action, its value will never change, same for 'show', its value will never change. I'm not sure what's the best way to achieve this but you could do but you could do if params[:action] == "show"

Ruby Problemewith filter and RSpec

I can't figure out why this RSpec test fails. Any advice?
I try to handle the destruction of post. Only users who create posts can delete them.
class PostsController < ApplicationController
before_filter :authorized_user, :only => :destroy
def destroy
post = Post.find(params[:id])
post.destroy
redirect_to posts_path, notice: 'Post successfully destroyed'
end
private
def authorized_user
redirect_to posts_path, notice: 'Access Denied' if current_user.posts.find_by_id(params[:id]).nil?
end
Test :
describe "DELETE destroy" do
before(:each) do
#post = stub_model(Post, :id => 23)
#post.stub(:destroy){true}
Post.stub(:find){#post}
end
it "should search the post" do
Post.should_receive(:find).with(#post.id.to_s).and_return(#post)
delete :destroy, {:id => #post.id }
end
it "should destroy the post" do
#post.should_receive(:destroy)
delete :destroy, {:id => #post.id }
end
it "should redirect to the posts list" do
delete :destroy, {:id => #post.id }
response.should redirect_to posts_path
end
end
And errors :
1) PostsController DELETE destroy should search the post
Failure/Error: Post.should_receive(:find).with(#post.id.to_s).and_return(#post)
(<Post(id: integer, title: string, body: text, created_at: datetime, updated_at: datetime, user_id: integer) (class)>).find("23")
expected: 1 time
received: 0 times
# ./spec/controllers/posts_controller_spec.rb:67:in `block (3 levels) in <top (required)>'
I think it is because in the before(:each) block you have to log in a user. You have before_filter and this filter is only for :destroy. So when you don't have a logged in user then your tests will fail because it is actually a user without permissions that "runs the test". So you should put this code in before(:each):
user = way_to_make_user - I do it with: FactoryGirl.create(:user,role=>"client")
controller.sign_in user
I could help you more if you tell me what do you use for authentication. I use cancan gem. So the main point is that you have to log in user before each test.

rspec controller test with devise authentication

I am having problem with rspec testing controller the devise authentication.
I have a following setup
I have included
config.include Devise::TestHelpers, :type => :controller
in my spec_helper.rb
In my merchants_controller_spec.rb
describe MerchantsController do
before :each do
#user = Factory(:user)
#merchant = Factory(:merchant, :user_id => #user.id,:is_approved => false, :is_blacklisted => false)
controller.stub!(:current_user).and_return(#user)
end
describe "GET index" do
it "assigns all merchants as #merchants" do
merchant = Factory(:merchant,:is_approved => true, :is_blacklisted => false)
get :index
assigns(:merchants).should eq([merchant])
end
end
end
My merchants_controller.rb
class MerchantsController < ApplicationController
before_filter :authenticate_user!
def index
#merchants = Merchant.approved
debugger
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #merchants }
end
end
end
I have a scope approved in merchant model
scope :approved, where(:is_approved => true, :is_blacklisted => false)
Now my problem is even though i stubbed current_user and returned #user as current_user, My merchants_controller index spec is failing. But if i comment out authenticate_user! then the spec passes,
without authenticate_user! the debugger of index action is caught but with authenticate_user! debugger is not caught.
I think there is problem in subbing current_user and i am not able to figure it out.
Help me out..
Have you read through the docs on github?:
Devise includes some tests helpers for functional specs. To use them, you just need to include Devise::TestHelpers in your test class and use the sign_in and sign_out methods. Such methods have the same signature as in controllers:
sign_in :user, #user # sign_in(scope, resource)
sign_in #user # sign_in(resource)
sign_out :user # sign_out(scope)
sign_out #user # sign_out(resource)
Another alternative
RSpec.describe YourController, :type => :controller do
before do
user = FactoryGirl.create(:user)
allow(controller).to receive(:authenticate_user!).and_return(true)
allow(controller).to receive(:current_user).and_return(user)
end
# rest of the code
end

Rspec, CanCan and Devise

I am starting a project and i would like to be able to test everything :)
And i have some problems with CanCan and devise.
For exemple, I have a controller Contacts. Everybody can view and everybody (excepts banned people) can create contact.
#app/controllers/contacts_controller.rb
class ContactsController < ApplicationController
load_and_authorize_resource
def index
#contact = Contact.new
end
def create
#contact = Contact.new(params[:contact])
if #contact.save
respond_to do |f|
f.html { redirect_to root_path, :notice => 'Thanks'}
end
else
respond_to do |f|
f.html { render :action => :index }
end
end
end
end
The code work, but I don't how to test the controller.
I tried this. This works if I comment the load_and_authorize_resource line.
#spec/controllers/contacts_controller_spec.rb
require 'spec_helper'
describe ContactsController do
def mock_contact(stubs={})
(#mock_ak_config ||= mock_model(Contact).as_null_object).tap do |contact|
contact.stub(stubs) unless stubs.empty?
end
end
before (:each) do
# #user = Factory.create(:user)
# sign_in #user
# #ability = Ability.new(#user)
#ability = Object.new
#ability.extend(CanCan::Ability)
#controller.stubs(:current_ability).returns(#ability)
end
describe "GET index" do
it "assigns a new contact as #contact" do
#ability.can :read, Contact
Contact.stub(:new) { mock_contact }
get :index
assigns(:contact).should be(mock_contact)
end
end
describe "POST create" do
describe "with valid params" do
it "assigns a newly created contact as #contact" do
#ability.can :create, Contact
Contact.stub(:new).with({'these' => 'params'}) { mock_contact(:save => true) }
post :create, :contact => {'these' => 'params'}
assigns(:contact).should be(mock_contact)
end
it "redirects to the index of contacts" do
#ability.can :create, Contact
Contact.stub(:new) { mock_contact(:save => true) }
post :create, :contact => {}
response.should redirect_to(root_url)
end
end
describe "with invalid params" do
it "assigns a newly created but unsaved contact as #contact" do
#ability.can :create, Contact
Contact.stub(:new).with({'these' => 'params'}) { mock_contact(:save => false) }
post :create, :contact => {'these' => 'params'}
assigns(:contact).should be(mock_contact)
end
it "re-renders the 'new' template" do
#ability.can :create, Contact
Contact.stub(:new) { mock_contact(:save => false) }
post :create, :contact => {}
response.should render_template("index")
end
end
end
end
But these tests totally failed ....
I saw nothing on the web ... :(
So, if you can advise me on the way i have to follow, i would be glad to ear you :)
CanCan does not call Contact.new(params[:contact]). Instead it calls contact.attributes = params[:contact] later after it has applied some initial attributes based on the current ability permissions.
See Issue #176 for details on this and an alternative solution. I plan to get this fixed in CanCan version 1.5 if not sooner.