Unexpected rspec behavior Ruby on Rails Turorial chapter 12 - ruby-on-rails-3

I am seeing an error that is only dependent on the location of the line:
should change(Relationship, :count).by(-1)
For example, with the code:
it "should destroy a relationship using Ajax" do
lambda do
xhr :delete, :destroy, :id => #relationship
response.should be_success
end.should change(Relationship, :count).by(-1) #<<-line is here
I get the rspec error:
1) RelationshipsController DELETE 'destroy' should destroy a relationship using Ajax
Failure/Error: xhr :delete, :destroy, :id => #relationship
ActionView::MissingTemplate:
Missing template relationships/destroy with {:handlers=>[:erb, :rjs, :builder, :rhtml, :rxml], :formats=>[:js, :html], :locale=>[:en, :en]} in view paths "#<RSpec::Rails::ViewRendering::PathSetDelegatorResolver:0x00000100a5b5f8>"
# ./app/controllers/relationships_controller.rb:16:in `destroy'
# ./spec/controllers/relationships_controller_spec.rb:44:in `block (4 levels) in <top (required)>'
# ./spec/controllers/relationships_controller_spec.rb:43:in `block (3 levels) in <top (required)>'
But with the code:
it "should destroy a relationship using Ajax" do
lambda do
xhr :delete, :destroy, :id => #relationship
response.should be_success
should change(Relationship, :count).by(-1) #<<-Line moved to here
end
... the test passes.
I am seeing expected behavior when I use a web browser. Unfollowing a user adjusts totals correctly.
So, are these two rspec tests not equivalent? Am I falsely reassured that the second test passes? If they are functionally equivalent, why does the first one fail?

Seems this was due, in part, to having confused
./app/controllers/relationships_controller.rb
with
./spec/controllers/relationships_controller_spec.rb
Code pasted into the wrong file (appropriately) generated no syntax errors. Fixing my error lead to passing rspec tests.

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

What does mean <top (required)> in rspec?

I have some rspec test. For example
require 'spec_helper'
describe UsersController do
before (:each) do
#user = FactoryGirl.create(:user)
sign_in #user
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
When I run the rspec i get some errors
Failures:
1) UsersController GET 'show' should be successful
Failure/Error: #user = FactoryGirl.create(:user)
ActiveRecord::StatementInvalid:
SQLite3::SQLException: near "SAVEPOINT": syntax error: SAVEPOINT active_record_1
# ./spec/controllers/users_controller_spec.rb:6:in `block (2 levels) in <top (required)>'
2) UsersController GET 'show' should find the right user
Failure/Error: #user = FactoryGirl.create(:user)
ActiveRecord::StatementInvalid:
SQLite3::SQLException: near "SAVEPOINT": syntax error: SAVEPOINT active_record_1
# ./spec/controllers/users_controller_spec.rb:6:in `block (2 levels) in <top (required)>'
rspec ./spec/controllers/users_controller_spec.rb:12 # UsersController GET 'show' should be successful
rspec ./spec/controllers/users_controller_spec.rb:17 # UsersController GET 'show' should find the right user
What does the mean and what could be the problem with that rspec?
Host is CentOS5 and the included SQLite version is old and dont work with the sqlite3 gem.
So i had to config the bundler to use a newer installed sqlite version.
bundle config build.sqlite3 \
--with-sqlite3-include=/package/host/localhost/sqlite-3/include \
--with-sqlite3-lib=/package/host/localhost/sqlite-3/lib
Followed by a bundle install
Problem solved.

RSpec let method gives nil when used in specs

When I run this test
require 'spec_helper'
describe AssignmentsController do
let(:user) { create(:user) }
let(:course) { create(:course) }
describe "GET 'index'" do
it "returns http success" do
assignment = user.assignments.build(name: "Hello 2", start_date: "5/20/2000", due_date: "5/21/2000")
get :index
assigns(:assignment).should eq([assignment])
end
end
end
I get this
Failure:
1) AssignmentsController GET 'index' returns http success
Failure/Error: get :index
NoMethodError:
undefined method `assignments' for nil:NilClass
# ./app/controllers/assignments_controller.rb:5:in `index'
# ./spec/controllers/assignments_controller_spec.rb:29:in `block (3 levels) in <top (required)>'
Why this be since I defined the user variable with lets above
If you look carefully, you'll see that the error originating from your controller on line 5, not the spec file. Everything should be fine with the let statement the way you have it.

Rspec what is wrong with my test for create controller action?

I am trying to learn TDD and this is part of my homework I couldn't figure out how to do it.
I want to test create controller action, and here is my code for test:
require 'spec_helper'
describe MoviesController do
describe 'create' do
it 'should call the model method perform create!' do
Movie.should_receive(:create!).with({"title" => 'Milk', "rating" => 'R'})
post :create, :movie => {:title => 'Milk', :rating => 'R'}
end
end
end
But I got:
Failures:
1) MoviesController create should call the model method performe create!
Failure/Error: post :create, :movie => {:title => 'Milk', :rating => 'R'}
NoMethodError:
undefined method `title' for nil:NilClass
# ./app/controllers/movies_controller.rb:50:in `create'
# ./spec/controllers/movies_controller_spec.rb:7:in `block (3 levels) in <top (required)>'
Finished in 0.21714 seconds
And here is create action I am testing against. Yes, it is TDD, and yes, I am testing a
working code, and it is the testing doesn't working :D
def create
#movie = Movie.create!(params[:movie])
flash[:notice] = "#{#movie.title} was successfully created."
redirect_to movies_path
end
I don't even know why I got the undefined method error message? I have a few other test passed but I deleted in this code snippe for simplicity, so I don't think it is related db/model related config problem. But why it does not working and how to change it?
Cheers
When you do a should_receive like that, it will return nil so the next line (when setting the flash message) attempts to retrieve the title from nil. Change your should_receive to:
Movie.should_receive(:create!).with({"title" => 'Milk', "rating" => 'R'}).and_return(stub_model(Movie))

Getting some unexpected errors while testing a Rails 3 controller

I have a services model defined as such:
class Service < ActiveRecord::Base
attr_accessible :service_type #, ...
SERVICE_TYPES = {
:restaurant => "restaurant",
:retailer => "retailer"
}
SERVICE_TYPES.values.each do |method|
define_method method.pluralize.to_sym do
where(:service_type => method)
end
end
def domestic
where(:country => 'USA')
end
def international
where("country != 'USA'")
end
end
I decided to not use a traditional STI pattern for the different services because they will all have the same attributes and otherwise behave identically. There is a parent model, but it is used only for normalization purposes and the web user never needs to know about it. As far as the application goes, there are service types, and specific services under those. So basically I want URLs like this:
http://myapp/services # <- Lists all service types
http://myapp/restaurants # <- Lists all restaurant-type services
http://myapp/restaurants/foo # <- Lists a specific restaurant (using friendly_id gem)
http://myapp/retailers # <- Lists all retailer-type services
http://myapp/retailers/bar # <- Lists a specific retailer
So I created a routing pattern like so:
controller :services, :via => [:get] do
match '/services' => :index
match '/:service_type' => :service_index, :as => 'service_type', :constraints => { :service_type => Regexp.new(Service::SERVICE_TYPES.values.map{|s| Regexp.escape(s.pluralize) }.join('|')) }
match '/:service_type/:id' => :show, :as => 'service', :constraints => { :service_type => Regexp.new(Service::SERVICE_TYPES.values.map{|s| Regexp.escape(s.pluralize) }.join('|')) }
end
Which gets me
services GET /services(.:format) {:controller=>"services", :action=>"index"}
service_type GET /:service_type(.:format) {:service_type=>/restaurants|retailers/, :controller=>"services", :action=>"service_index"}
service GET /:service_type/:id(.:format) {:service_type=>/restaurants|retailers/, :controller=>"services", :action=>"show"}
And the controller is defined as
class ServicesController < ApplicationController
def index
#service_types = Service::SERVICE_TYPES.values
#page_title = "Services"
end
def service_index
#service_type = params[:service_type]
#domestic = Service.send(#service_type).domestic
#international = Service.send(#service_type).international
#page_title = #service_type.capitalize
end
def show
#service = Service.find(params[:id])
#page_title = "Services - #{#service.name}"
end
end
This all works as expected when I test it in the browser. But when I try to run an integration test in Rspec2 I'm getting some really unexpected behavior.
require 'spec_helper'
describe ServicesController do
describe "GET 'index'" do
it "should be successful" do
get :index
response.should be_success
end
it "should have the right title" do
get :index
response.should have_selector(
"title",
:content => "#{#base_title}Services"
)
end
it "should have a link to each service" do
get :index
Service::SERVICE_TYPES.values.each do |service_type|
response.should have_selector("a", :href => service_type_path(service_type.pluralize),
:content => service_type.pluralize)
end
end
end
describe "GET 'service_index'" do
Service::SERVICE_TYPES.values.each do |service_type|
context service_type.pluralize do
it "should be successful" do
get :service_index, :service_type => service_type.pluralize
response.should be_success
end
it "should have the right title" do
get :service_index, :service_type => service_type.pluralize
response.should have_selector(
"title",
:content => "#{#base_title}#{service_type.pluralize.capitalize}"
)
end
it "should have a link to each service" do
get :service_index, :service_type => service_type.pluralize
Service.send(service_type.pluralize).each do |service|
response.should have_selector("a", :href => service_path(service_type.pluralize, service),
:content => service.name)
end
end
end
end
end
describe "GET 'show'" do
it "should be successful" do
get 'show'
response.should be_success
end
end
end
The get action appears to run successfully because the "should be successful" tests all pass, but the others fail because it can't find the proper selector(s) on the page. The odd thing is that the dump of HTML that is returned doesn't appear to come from my app.
1) ServicesController GET 'index' should have the right title
Failure/Error: response.should have_selector(
expected following output to contain a <title>Services</title> tag:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
# ./spec/controllers/services_controller_spec.rb:12:in `block (3 levels) in <top (required)>'
2) ServicesController GET 'index' should have a link to each service
Failure/Error: response.should have_selector("a", :href => service_type_path(service_type.pluralize),
expected following output to contain a <a href='/restaurants'>Restaurants</a> tag:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
# ./spec/controllers/services_controller_spec.rb:21:in `block (4 levels) in <top (required)>'
# ./spec/controllers/services_controller_spec.rb:20:in `each'
# ./spec/controllers/services_controller_spec.rb:20:in `block (3 levels) in <top (required)>'
3) ServicesController GET 'service_index' restaurants should have the right title
Failure/Error: response.should have_selector(
expected following output to contain a <title>Restaurants</title> tag:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
# ./spec/controllers/services_controller_spec.rb:37:in `block (5 levels) in <top (required)>'
4) ServicesController GET 'service_index' restaurants should have a link to each service
Failure/Error: response.should have_selector("a", :href => service_path(service_type.pluralize, service),
expected following output to contain a <a href='/restaurants/foo'>Foo</a> tag:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
# ./spec/controllers/services_controller_spec.rb:46:in `block (6 levels) in <top (required)>'
# ./spec/controllers/services_controller_spec.rb:45:in `block (5 levels) in <top (required)>'
What I would expect to see if this was indeed a failure would be the complete dump of my HTML application template which is marked up in HTML 5. Instead I'm getting only the doctype of a page marked up as HTML 4.
Any ideas what would cause that?
As a secondary issue, I can't figure out any way to turn on logging in Webrat to see what HTTP activity is actually happening. How can I do that?
Yeah, never mind. I'm an idiot and forgot to put render_views inside my test which is why it wasn't rendering the view.