Ruby Problemewith filter and RSpec - testing

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.

Related

*** NoMethodError Exception: undefined method `to_sym' for nil:NilClass in Rails 3.2 with Rspec in controllers spec

I have configured Rspec Ruby 2.0.0-p0 and Rails 3.2.14 configuration is perfect I'm sure on that but when I try to run rake spec:controllers it gaves me below error on every request action written in spec example -
*** NoMethodError Exception: undefined method `to_sym' for nil:NilClass
I have written specs for controllers before but never come across such situation, help me If any one has fixed same issue....
Here is my spec and error stack
describe UsersController do
before (:each) do
#user = FactoryGirl.create(:user)
sign_in #user
end
describe "GET 'index'" do
it "should be successful" do
get 'index'
response.should be_success
end
end
describe "GET 'show'" do
it "should be successful" do
get :show, :id => #user.id
response.should be_success
end
it "should find the right user" do
get :show, :id => #user.id
assigns(:user).should == #user
end
end
end
Here is result -
Failures:
1) UsersController GET 'index' should be successful
Failure/Error: get 'index'
NoMethodError:
undefined method `to_sym' for nil:NilClass
# ./spec/controllers/users_controller_spec.rb:13:in `block (3 levels) in <top (required)>'
2) UsersController GET 'show' should be successful
Failure/Error: get :show, :id => #user.id
NoMethodError:
undefined method `to_sym' for nil:NilClass
# ./spec/controllers/users_controller_spec.rb:21:in `block (3 levels) in <top (required)>'
3) UsersController GET 'show' should find the right user
Failure/Error: get :show, :id => #user.id
NoMethodError:
undefined method `to_sym' for nil:NilClass
# ./spec/controllers/users_controller_spec.rb:26:in `block (3 levels) in <top (required)>'
Finished in 0.4741 seconds
3 examples, 3 failures
Failed examples:
rspec ./spec/controllers/users_controller_spec.rb:12 # UsersController GET 'index' should be successful
rspec ./spec/controllers/users_controller_spec.rb:20 # UsersController GET 'show' should be successful
rspec ./spec/controllers/users_controller_spec.rb:25 # UsersController GET 'show' should find the right user
Randomized with seed 19701
My factory is -
FactoryGirl.define do
factory :user do
first_name 'Test User'
last_name 'Last name'
email 'example#example.com'
password 'changeme'
password_confirmation 'changeme'
company 'RR'
confirmed_at Time.now
end
end
We need company name mandatory to create register user.
class UsersController < ApplicationController
before_filter :authenticate_user!
#authorize_resource
def index
#users = User.all
end
def show
#user = User.find(params[:id])
end
end
here I have added two methods for test in user controller.
Same thing I tried with demo example that works great but not in my project....
Thanks
If you are using devise gem for authentication then you need to specify the devise mapping in controller test cases.
Replace the code in the before(:each) block with below code
#user = FactoryGirl.create(:user)
#request.env['devise.mapping'] = Devise.mappings[:user]
sign_in #user
Finally I fixed issue, it comes due to authenticate_user! method in application controller which inherits to every controllers -
prepend_before_filter :authenticate_user!, :except => [:not_authenticated]
I have added below module to fix issue occurs due to this devise method -(support/controllers_helpers.rb)
module ControllerHelpers
def sign_in(user = double('user'))
if user.nil?
request.env['warden'].stub(:authenticate!).
and_throw(:warden, {:scope => :user})
controller.stub :current_user => nil
else
request.env['warden'].stub :authenticate! => user
controller.stub :current_user => user
end
end
end
finally include above module in spec_helper.rb file
config.include ControllerHelpers, :type => :controller
Got running all controllers specs.
Cheers!!!
more info

RSpec functional test is redirecting to the wrong place

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

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.

Why is capybara/rspec losing the current_user?

The following spec is failing and failing over again. I've tried everything but can't get it to work. If I test it manually all looks fine :( Some help/tips would be really nice!
The join action should add an logged-in user to a guild/group if he/she has the right token (in the URL). If the user isn't logged in, the action redirects to the login page and saves the token and the ID to cookies. After login the user gets redirected to the join page if the cookies are set.
I've found out that the current_user get lost during the test. The session variable is still present. I've a standard Authlogic setup and all other tests are passing so I really don't know what's going wrong. I'm new to RSpec/capybara but the cucumber/capybara test (from which I'm migrating) is also failing so I think it's a capybara issue.
Failing Spec:
describe GuildsController do
fixtures :roles
def login
#user = Factory(:User)
visit login_path
fill_in 'Login', :with => #user.login
fill_in 'Password', :with => 'password'
click 'Login'
page.should have_css(".notice")
end
def assing_user_to_guild_as(role)
role_id = Role.where(:name => role).first.id
#guild.assignments << Assignment.new(:role_id => role_id, :user_id => #user.id, :guild_id => #guild.id)
end
before(:each) do
#guild = Guild.first || Factory(:Guild).build
visit root_path
end
context "a user" do
before(:each) do
login
end
it "should be able to join a guild with a valid token" do
visit "guilds/#{#guild.id}/join/#{#guild.token}"
#guild.members.include?(#user.login).should be_true
page.should have_css(".notice")
end
it "shouldn't be able to join a guild with a invalid token" do
visit "guilds/#{#guild.id}/join/#{#guild.token+"invalid"}"
#guild.members.include?(#user.login).should be_false
page.should have_css(".error")
end
end
end
Controller Action:
def join
#guild = Guild.find(params[:id])
respond_to do |format|
if current_user.nil?
flash[:error] = t("have_to_be_logged_in")
unless params[:token].nil?
cookies[:rguilds_jg_token] = params[:token]
cookies[:rguilds_jg_gid] = params[:id]
end
format.html { redirect_to(login_path) }
else
unless cookies[:rguilds_jg_token].nil? && cookies[:rguilds_jg_gid].nil?
cookies.delete(:rguilds_jg_token)
cookies.delete(:rguilds_jg_gid)
end
if #guild.verified?
if params[:token] == #guild.token
unless #guild.users.include?(current_user)
#guild.assignments << Assignment.create(:user_id => current_user.id, :role_id => Role.find_by_name("member").id)
flash[:notice] = t('guilds.joined')
format.html { redirect_to(#guild) }
else
flash[:error] = t('guilds.already_joined')
format.html { redirect_to(#guild) }
end
else
flash[:error] = t('guilds.invalid_token')
format.html { redirect_to(#guild) }
end
else
flash[:error] = t('guilds.not_verified')
format.html { redirect_to(#guild) }
end
end
end
end
"rake spec" result:
...................FF.....................................................................
Failures:
1) GuildsController a user should be able to join a guild with a valid token
Failure/Error: #guild.members.include?(#user.login).should be_true
expected false to be true
# ./spec/integration/guilds_spec.rb:72:in `block (3 levels) in <top (required)>'
2) GuildsController a user shouldn't be able to join a guild with a invalid token
Failure/Error: page.should have_css(".error")
expected #has_css?(".error") to return true, got false
# ./spec/integration/guilds_spec.rb:79:in `block (3 levels) in <top (required)>'
Finished in 7.87 seconds
90 examples, 2 failures
Gems:
gem 'rails', '3.0.0.rc'
gem "mocha"
gem "rspec-rails", ">= 2.0.0.beta.19"
gem "factory_girl_rails"
gem 'capybara'
gem "authlogic", :git => "http://github.com/odorcicd/authlogic.git", :branch => "rails3"
# In your test_helper.rb / spec_helper.rb
class ActiveRecord::Base
mattr_accessor :shared_connection
##shared_connection = nil
def self.connection
##shared_connection || retrieve_connection
end
end
# Forces all threads to share the same connection. This works on
# Capybara because it starts the web server in a thread.
ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
This is from http://gist.github.com/470808