How to stub model method for rspec controller test - ruby-on-rails-3

I'm trying to stub the model method which I'm using in my controller, but it never seems to be working. Can someone let me know the proper way to do it
User Controller
if current_user.user_token
#user = #account.users.find(params[:id])
#user.revoke_seat(:admin, current_user)
render :template => "/admin/users/revoke_seat"
else
render :js => "window.location.href='#{server_url}/oauth/authorize?response_type=code&client_id=#{client_id}&state=#{request.referrer}?auto_revoke_seat=true&redirect_uri=#{auth_service_callback_url}";
end
Rspec
before do
users(:admin).stub(:internal_admin?).and_return(true)
login_as :admin
user.stub(:user_token).and_return("123123")# THIS IS NOT WORKING
end
it "should redirect to authentication service to generate access token" do
expect(user).to receive(:user_token).and_return(true)
xhr :put, :revoke_seat, account_id: account.id, id: user.id
expect(response).to render_template('admin/users/revoke_seat')
expect(assigns(:account)).to eq(account)
expect(assigns(:user)).to eq(user)
end

You might try the allow approach instead of stub. E.g., allow(:admin).to receive(:internal_admin?).and_return(true)

Related

Stubbing out save methodin rails with rspec

I have the following action in my controller:
def create
#user = current_user
#vin = #user.vins.new(params[:vin])
if #vin.save
# waiting for implementation
logger.debug("here we are")
else
redirect_to(vins_path)
end
end
I'd like to test with with rspec. However, I want to stub out the save operation to simulate a failure:
it "should send user to vins_path if there is a problem creating the VIN" do
#vin.stub!(:save).and_return(false)
post 'create', :vin => { :name => "Test 1", :vin => "test" }
response.should redirect_to(vins_path)
end
However, the stub doesn't seem to work as the save operation is always successful. What am I doing wrong?
Thanks
Try this:
Vin.any_instance.stub(:save).and_return(false)

Rails testing, how to specify path for post? (No route matches error)

I try to test one of my REST api controllers which is placed at "controllers/api/v1/bookings_controller.rb". The controller only responds_to json at the moment as you can see here:
class Api::V1::BookingsController < ApplicationController
respond_to :json
before_filter :authenticate_user!
before_filter :get_user
def create
...
end
end
My functional test is located at "test/functional/api/v1/bookings_controller_test.rb" and looks like following:
require 'test_helper'
class Api::V1::BookingsControllerTest < ActionController::TestCase
include Devise::TestHelpers
setup do
#booking = bookings(:one)
#user = users(:one)
sign_in #user
end
test "should return a bad request" do
post :create, :booking => { }, :format => 'json'
assert_response :bad_request
end
end
The post path for creating a booking looks like this (and works, tested with HTTP Client):
api_v1_user_bookings
GET /api/v1/users/:user_id/bookings(.:format) api/v1/bookings#index
POST /api/v1/users/:user_id/bookings(.:format) api/v1/bookings#create
However when I run the test it seems that it uses some default route (see error message below), how can i specify the correct route in my test? Or is there some other mistake I do not see here?
test_should_return_a_bad_request(Api::V1::BookingsControllerTest):
ActionController::RoutingError: No route matches {:booking=>{}, :format=>"js
on", :controller=>"api/v1/bookings", :action=>"create"}
Your route expects a user_id parameter. Add it to your post:
post :create, :user_id => #user.id, :booking => {}, :format => :json
Ok, I think I figured it out now. I just had to add the user-id, otherwise it seems that rails does not select the right route. So the correct test method looks like this:
test "should return a bad request" do
post :create, :user_id => #user.id, :booking => { }, :format => 'json'
assert_response :bad_request
end

TDD with RSpec and Rails: testing controller actions with no view

As I continue to learn my way around TDD with RSpec 2 and Rails 3.1, I can't seem to find a solution to this problem.
I have a Users controller with a new and create action. In my UsersController spec, I have
users_controller_spec.rb
describe "POST 'create'" do
before(:each) do
#attr = Factory.attributes_for(:user)
end
it "should assign an #user variable" do
post :create, :user => #attr
assigns[:user].should_not be_nil
assigns[:user].should be_kind_of(User)
end
end
and in my UsersController,
users_controller.rb
def create
#user = User.new(params[:user])
end
This spec is failing with
1) UsersController POST 'create' should assign an #user variable
Failure/Error: post :create, :user => #attr
ActionView::MissingTemplate:
I can continue to implement application code to get this test to pass, but I feel like this test should be passing as it is.
Any suggestions?
Your create method needs to do something. Either render a template or redirect. Since you're not telling it to redirect it's assuming that you want it to render a template but when it can't find a create.html.erb file it throws an error.
You're best bet is to do either this:
def create
#user = User.new(params[:user])
redirect_to root_url
end
or this:
def create
#user = User.new(params[:user])
render :nothing => true
end
To test rendering nothing you'll want:
expect(response).to render_template(nil)
I've come across this recently myself. It seems one possibility would be to rescue the error in your test.
it "should assign an #user variable" do
begin
post :create, :user => #attr
rescue ActionView::MissingTemplate
# This is okay because(/as long as) we test the render/redirect
# in a separate spec where we don't rescue this exception.
end
assigns[:user].should_not be_nil
assigns[:user].should be_kind_of(User)
end
I don't know how "correct" this solution is. On one hand, it definitely emphasizes the "testing one thing at a time" mentality, on the other, it seems kind of ugly.
Edit
I suppose you could make some nice wrappers in your spec helper, something like
def post?(action, params = {})
post action, params
rescue ActionView::MissingTemplate
end

Webrat looking for an action it does not need

Scenario
I have a controller with two actions only - :create and :delete. Where the create action is defined thus:
def create
# some code...
if #thing.save
redirect_to :back, :notice => "Successfully created."
else
redirect_to :back, :notice => "Successfully deleted."
end
end
I link to the action using...
<%= link_to "Become a friend", things_path(...), :method => :post %>
...in the view.
Problem
This works fine as I interact with the app in my browser. However, I wish to test this functionality using RSpec integration testing using Webrat's helper method - click_link "Become a friend" - which I think is correct. But I get this error
Failure/Error: click_link "I like Person-1's taste"
AbstractController::ActionNotFound:
The action 'index' could not be found for ThingsController
I can create an empty index action in the Things controller but this would violate the KISS Principle.
Questions
How can I workaround/fix this? And are there any best practices for cases like this?
The problem is that :method => :post makes rails create a form which is then submitted when you click the link. This only works with javascript enabled which webrat does not support out of the box. Have a look at https://github.com/brynary/webrat/wiki and try to get the test running with selenium. As selenium actually uses a real browser, your specs should run.

Rspec2: response.should render_template("new") after invalid params fails

I am testing a controller in RSpec2 and for both my create and update actions, when passed invalid params, the controller should render either the "new" or "edit" templates respectively. It is doing that, but my test never passes.
describe "with invalid params" do
before(:each) do
User.stub(:new) { mock_user(:valid? => false, :save => false) }
end
it "re-renders the 'new' template" do
post :create, :company_id => mock_company.id
response.should render_template("new")
end
end
Results in this:
re-renders the 'new' template
expecting <"new"> but rendering with <"">
Here is the controller action:
respond_to do |format|
if #user.save
format.html {
flash[:notice] = "#{#user.full_name} was added to #{#company.name}."
redirect_to company_users_url(#company)
}
else
logger.debug #user.errors
format.html{
render :new
}
end
end
This problem also seems to be isolated to this controller. I have almost identical code running another controller and it is fine. I am not sure where the problem could be.
Update:
Here are the two mock methods
def mock_user(stubs={})
#mock_user ||= mock_model(User, stubs).as_null_object
end
def mock_company(stubs={})
(#mock_company ||= mock_model(Company).as_null_object).tap do |company|
company.stub(stubs) unless stubs.empty?
end
end
Turned out it was a problem with stubbing and CanCan. CanCan was loading the resources and uses some different methods than what I thought.