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
Related
I've been trying to use FactoryGirl for tests on my Rails application, but I'm running into difficulty with it.
I feel as if there must be something fairly obvious I'm doing wrong, but after much searching I haven't been able to figure out the cause.
I'm trying to run a test to confirm the 'show' action is successful on one of my controllers.
Here's the error message I'm getting:
Failure/Error: get 'show'
ActionController::UrlGenerationError:
No route matches {:action=>"show", :controller=>"simple_requests"}
Below are the relevant code snippets leading to this outcome.
/spec/controllers/simple_requests_controller_spec.rb
require 'spec_helper'
describe SimpleRequestsController do
describe "GET 'show'" do
before do
#simple_request = build(:simple_request)
end
it "should be successful" do
get 'show'
expect(response).to be_success
end
end
end
/factories/simple_requests_controller_spec.rb
FactoryGirl.define do
factory :simple_request do
id 123
full_name "Testie McTesterson"
company "Test Company"
role "Analyst"
email "foobar#foobs.com"
phone "000888"
message "Test question?"
end
end
/controllers/simple_requests_controller.rb
def show
authorize SimpleRequest #For pundit
#simple_request = SimpleRequest.find(params[:id])
end
I have two hypotheses as to why this may be happening:
1) Rspec is looking for an id for the 'show' action, but somehow can't find it. (Although there is one in the Factory, and I've yet to figure out how it wouldn't be flowing through.)
2) Pundit is causing issues, since the show action may require authorization (although commenting out the 'authorize' line makes no difference at present)
Any and all thoughts welcome :)
EDIT
Pasting below the output of rake routes | grep simple_requests
simple_requests GET /simple_requests(.:format) simple_requests#index
POST /simple_requests(.:format) simple_requests#create
new_simple_request GET /simple_requests/new(.:format) simple_requests#new
edit_simple_request GET /simple_requests/:id/edit(.:format) simple_requests#edit
simple_request GET /simple_requests/:id(.:format) simple_requests#show
PATCH /simple_requests/:id(.:format) simple_requests#update
PUT /simple_requests/:id(.:format) simple_requests#update
DELETE /simple_requests/:id(.:format) simple_requests#destroy
Edit 2 - Adding ID parameter
I have now also attempted to add an id as follows:
it "should be successful" do
get 'show', id: #simple_request.id
expect(response).to be_success
end
This time I received the following error message
ActiveRecord::RecordNotFound: Couldn't find SimpleRequest with 'id'=123
'123' is the ID in my /factories - I think I must be missing something to get this working, but can't figure out what yet.
Your SimpleRequest does not have an Id. You need to use create instead of build
before do
#simple_request = create(:simple_request)
end
it "should be successful" do
get 'show', id: #simple_request.id
expect(response).to be_success
end
Try this:
before do
#simple_request = create :simple_request
end
it "should be successful" do
get 'show', id: #simple_request.id
expect(response).to be_success
end
It's a show view, so you'll have to supply your request with an ID and you'll have to actually create a record with create instead of build in your before block.
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'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
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
I'm new to rails and I'm trying to test a controller with rspec. My first test is when the show action is invoked, it should lookup a Category by url.
The problem is when I add the stubbing code, I get the following error:
undefined method `find' for #
my test looks like this:
require 'spec_helper'
describe CategoriesController do
describe "GET /category-name/" do
before(:each) do
#category = mock_model(Category)
Category.stub!(:find).with(:first, :conditions => ["url = :url", {:url => "category-name"}]).and_return(#category)
end
it "should find the category by url" do
controller.show
Category.should_receive(:find).with(:first, :conditions => ["url = :url", {:url => "category-name"}]).and_return(#category)
end
end
end
Your call to the request should be after any should_receive. It's a tense thing. So it kind of reads like this, "Category should receive something, when this happens". "This happens" refers to the request.
it "should find the category by url" do
Category.should_receive(:find).with...
get "show", { your params, if you're sending some in }
end
Also, you want to go the way of a request vs calling the controller method itself, for this particular test at least.
So
post "action_name"
get "action_name"
update "action_name"
delete "action_name"
instead of
controller.action_name