I've got the following spec in spec/views/users/new.html.erb_spec.rb:
require 'spec_helper'
describe "users/new.html.erb" do
it "displays the text attribute of the message" do
render
response.should contain("Register")
end
end
But when I run the test it fails with:
ActionView::TemplateError in 'users/new.html.erb displays the text attribute of the message'
Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
The line it is failing on is:
<% form_for #user, :url => account_path do |f| %>
In my Users controller for the new method, I have this:
#user = User.new
Any ideas why I'm getting that error?
UPDATE: Per request, here's my routes file...
ActionController::Routing::Routes.draw do |map|
map.resource :account, :controller => "users"
map.resources :users
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
end
The view specification is run in complete isolation from the Users controller. Thus, you have to initialize the variables needed in the view yourself, as described here. The result would be something like this:
require 'spec_helper'
require 'path/to/user.rb'
describe "users/new.html.erb" do
it "displays the text attribute of the message" do
assigns[:user] = User.new
render
response.should contain("Register")
end
end
If you want to test your view together with your controller, I would suggest looking into integration testing with Cucumber.
Just a more updated answer.
require 'spec_helper'
describe "users/new.html.erb" do
it "displays the text attribute of the message" do
assign(:user, stub_model(User))
render
expect(rendered).to include("Register")
end
end
This should work on rails 3.2.13 and rspec 2.13.0
Related
Writing some controller tests, using render_views to check some partial rendering....
describe PromoCodeController do
render_views
describe "GET 'show" do
... a bunch of tests
it "renders 'used' partial when promo code has already been used" do
#promo_code = create(:promo_code)
#user.stub(:promo_used?).and_return(true)
get 'show', :slug => #promo_code.slug
expect(response).to render_template(:partial => 'promo_code/_used')
end
which loads in the _used partial
<article>
<p><%= #promo.description.html_safe %></p>
<p>Sorry, it appears this promo code has already been used. Please try again or contact us directly.</p>
<%= link_to "View Order", orders_path(#order), class: "box-button-black", data: { bypass: true } %>
</article>
but breaks with:
undefined method `orders_path' for #<#<Class:0x007fd4069d06e8>:0x007fd401e3e518>
Any ideas on how to either
(a) ignore the Rails link, it's irrelevant to the test
(b) include something in the test to recognize that link
(c) stub it (last resort i think)
Everything I've tried so far doesn't get past the error.
EDIT:
orders_path was wrong, it should be order_path. After changing that I get:
ActionView::Template::Error:
No route matches {:controller=>"order", :action=>"show", :id=>nil}
So the partial is looking for #order. I tried setting it with controller.instance_variable_set(:#order, create(:order)), but in the partial it comes back as nil.
A quick test by adding<% #order = Order.last %> in the view partial passes green. How to pass the var #order into the _used partial is now the question.
Instead of manually setting the spec type you can set it based off file location
# spec_helper.rb
RSpec.configure do |config|
config.infer_spec_type_from_file_location!
end
describe 'GET SHOW' do
run this in a before block
before do
controller.instance_variable_set(:#order, create(:order))
end
it "renders 'used' partial when promo code has already been used" do
promo_code = create(:promo_code)
#user.stub(:promo_used?).and_return(true)
# check if #order variable is assigned in the controller
expect(assigns(:order).to eq order
get 'show', slug: promo_code.slug
expect(response).to render_template(:partial => 'promo_code/_used')
end
end
First off, I needed to change it to order_path, orders_path was wrong. Doh.
Than I needed to stub some methods to get around the error
ActionView::Template::Error:
No route matches {:controller=>"order", :action=>"show", :id=>nil}
Ultimately, stubbing the method assign_promo_to_users_order which assigns a complete order to the current_user did the trick:
it "renders 'used' partial when promo code has already been used" do
#promo_code = create(:promo_code)
#user.stub(:promo_used?).and_return(true)
User.any_instance.stub(:assign_promo_to_users_order).and_return(create(:order, :complete))
get 'show', :slug => #promo_code.slug
expect(response).to render_template(:partial => 'promo_code/_used')
end
Try adding the spec's type.
I believe that the action controller URL helpers are included into the spec type.
Try:
describe SomeController, type: :controller do
I have a rails 3.2.13 app running rspec-rails 2.14.0 and am trying to confirm that a view renders a particular partial in my test. It actually does work, but I need to add this test. Here's what I have so far:
require 'spec_helper'
describe 'users/items/index.html.haml' do
let(:current_user) { mock_model(User) }
context 'when there are no items for this user' do
items = nil
it 'should render empty inventory partial' do
response.should render_template(:partial => "_empty_inventory")
end
end
end
This runs without error, but does not pass. The failure is:
Failure/Error: response.should render_template(:partial => "_empty_inventory")
expecting partial <"_empty_inventory"> but action rendered <[]>
Thanks for any ideas.
EDIT
This works for me, but Peter's solution is better...
context 'when there are no items for this user' do
before do
view.stub(current_user: current_user)
items = nil
render
end
it 'should render empty inventory partial' do
view.should render_template(:partial => "_empty_inventory")
end
end
For some reason it was counter-intuitive to me to have to call render on a view, but there you go...
So the way one usually tests whether a particular partial is rendered in a view spec is by testing the actual content of the partial. For example, assume that your _empty_inventory parial has the message 'There is no inventory'. Then you might have a spec like:
it "displays the empty inventory message" do
render
rendered.should_not have_content('There is no inventory')
end
Alternately, you could use a controller spec, in which case you need to call the 'render_views' method when setting up the spec. Then you can do something similar to
it 'should render empty inventory partial' do
get :index, :user_id => user.id
response.should render_template(:partial => "_empty_inventory")
end
Assuming you've set up the state for the contoller spec.
I have 2 simple RSpec tests i've written for a small rails app i've done to learn rails. I originally had a mock setup for my Link class but was getting the same issue.
This is my test code:
require 'spec_helper'
describe LinksController do
render_views
before(:each) do
link = Link.new
link.stub!(:title).and_return("Reddit")
link.stub!(:url).and_return("http://www.reddit.com")
link.stub!(:created_at).and_return(Time.now)
link.stub!(:updated_at).and_return(Time.now)
link.stub!(:user_id).and_return("1")
link.stub!(:id).and_return("1")
link.save
user = User.new
user.save
end
it "renders the index view" do
get :index
response.should render_template('links/index')
response.should render_template('shared/_nav')
response.should render_template('layouts/application')
end
it "renders the show view" do
get :show, :id => 1
response.should render_template('links/show')
response.should render_template('shared/_nav')
response.should render_template('layouts/application')
end
end
I'm new to both rails and RSpec, not sure what I should be doing to get this to work. What is the best way to test this show method from my LinksController when you need data? I tried mock_model too but maybe I was using it wrong.
You can see all the app code on Github
The problem is that you are stubbing a model, so it's not stored in the database. That means that when you call get :show, :id => 1 the query to the database returns nothing and your tests fail. Stubbing is great when you want to fake a response or an object without using the database, but if you are depending on actual Rails code that uses the database you can't use this method because nothing exists in the database. To fix this I would drop the stubbed models entirely and actually create them.
require 'spec_helper'
describe LinksController do
render_views
before(:each) do
user = User.create
#link = Link.create :title => "Reddit",
:url => "http://www.reddit.com",
:user => user
end
it "renders the index view" do
get :index
response.should render_template('links/index')
response.should render_template('shared/_nav')
response.should render_template('layouts/application')
end
it "renders the show view" do
get :show, :id => #link.id
response.should render_template('links/show')
response.should render_template('shared/_nav')
response.should render_template('layouts/application')
end
end
You should also eventually look into Factory gems like Sham and Factory Girl to simplify the creation of test data.
i am working in Rspec of ROR..
I am trying to test my controllers using RSpec.i am having a Users controller with functions like new , tags, etc..
i created a file under spec/users_controller_spec.rb
and added the test cases as.
require 'spec_helper'
describe UsersController do
integrate_views
it "should use UsersController" do
controller.should be_an_instance_of(UsersController)
end
describe "GET 'new'" do
it "should be successful" do
get 'new'
response.should be_success
end
it "should have the title" do
get 'new'
response.should have_tag("title", "First app" )
end
end
end
which gets pass.
But when i add a test case for tags ..
like
describe "GET 'tags'" do
it "should be successful" do
get 'tags'
response.should be_success
end
end
this results in an error as
F...
1)
'UsersController GET 'tags' should be successful' FAILED
expected success? to return true, got false
why it is coming like this ?? i am very new to ROR and cant find the reason of why i am getting this error..
How to make this pass .
Also i tried the Url
http://localhost:3000/users/tags which is running for me .. But on testing using $spec spec/ i am getting the error ..
Your test may be failing for any number of reasons. Does the route require an ID in the parameter hash? Is the controller action redirecting? Is the controller raising an error?
You'll need to look at the controller code /and/or routes.rb to discover the cause of the failure. Take note of before filters in the controller, which may not allow the action to be reachable at all.
You need to add custom routes that are not within the default 7 routes. Assuming you have resources :users within your routes you will need to modify it. I'm also assuming that your tags route is unique to individual users.
resources :users do
member do
# creates /users/:user_id/tags
get :tags
end
end
And in your RSpec test you would call it like
describe '#tags' do
user = create :user
get :tags, user_id: user.id
end
If the route is not to be unique per user the other option is a collection route, something like:
resources :users do
collection do
# creates /users/tags
get :tags
end
end
Given I have a named route:
map.some_route '/some_routes/:id', :controller => 'some', :action => 'other'
How do I use the routing spec file 'spec/routing/some_routing_spec.rb' to test for that named route?
I've tried this after the "describe SomeRouteController" block and it doesn't work, I get 'undefined method "helper":
describe SomeRouteHelper, 'some routes named routes' do
it 'should recognize some_route' do
helper.some_route_path(23).should == '/some_routes/23'
end
end
If this is in a controller spec, you can call the routing method directly, no helper needed.
describe SomeController do
it 'should recognize ma routes!' do
thing_path(23).should == '/things/23'
end
end
In RSpec-Rails 2.7+ you can create a spec/routing directory and put your routing specs in there. See the rspec-rails docs for more info.
there's a nice shoulda matcher for this too:
it { should route(:get, "/users/23").to(:action => "show", :id => 23)
more information on using shoulda matchers with rspec:
https://github.com/thoughtbot/shoulda-matchers
You can do this in your controller specs with the assert_routing method, like so:
describe UsersController do
it "should recognize a specific users#show route" do
assert_routing("/users/23", {:controller => "users", :action => "show", :id => 23})
end
end
More documentation is here.
This is how I write the specs using RSpec2, Shoulda, and Capybara. You would save this example file in #{Rails.root}/spec/routing/thingz_routing_spec.rb or my preference #{Rails.root}/spec/routing/thingz_controller_spec.rb
require "spec_helper"
describe ThingzController do
describe "routing" do
it "routes to #index" do
get("/thingz").should route_to("thingz#index")
end
end
end