rspec testing ajax response (should render a partial) - ruby-on-rails

I want to test that my controller action is rendering a partial.
I've poked around and I can't seem to find anything that works.
create action:
def create
#project = Project.new...
respond_to do |format|
if #project.save
format.js { render :partial => "projects/form" }
end
end
end
spec:
it "should save and render partial" do
....
#I expected/hoped this would work
response.should render_partial("projects/form")
#or even hopefully
response.should render_template("projects/form")
#no dice
end

If you're looking for a REAL answer... (i.e. entirely in RSpec and not using Capybara), the RSpec documentation says that render_template is a wrapper on assert_template. assert_template (according to the docs) also indicates that you can check that a partial was rendered by including the :partial key.
Give this a go...
it { should render_template(:partial => '_partialname') }

Update see bluefish's answer below, it seems to be the correct answer
Would you consider using Capybara for your integration testing? I found ajax difficult to test with rspec alone. In your case I'm not even sure you are getting a response back yet. In capybara it waits for the ajax call to finish and you can call the page.has_xxxx to see if it was updated. Here is an example:
it "should flash a successful message" do
visit edit_gallery_path(#gallery)
fill_in "gallery_name", :with => "testvalue"
click_button("Update")
page.has_selector?("div#flash", :text => "Gallery updated.")
page.has_content?("Gallery updated")
click_link "Sign out"
end

another great way to test your ajax controller method is to check the assignments which are later used to render the result. Here is a little example:
Controller
def do_something
#awesome_result = Awesomeness.generete(params)
end
JBuilder
json.(#awesome_result, :foo, :bar)
Rspec Controller Test
describe :do_something do
before do
#valid_params{"foo" => "bar"}
end
it "should assign awesome result" do
xhr :post, :do_something, #valid_params
assigns['awesome_result'].should_not be_nil
end
end

Related

How could several instances UnknownFormat error in controller suddenly appear?

My app's view specs started failing because of a change we introduced to version control and I'm trying to debug.
Essentially, we had a ton of view specs that always passed, and now many, but not all, of them produce ActionController::UnknownFormat errors in the controller. Here is an example of a method that is blowing up:
def show
#user = current_user
FooCountItem.increment_requests
respond_to do |format|
format.html
format.json { render json: #foo }
end
end
Here's an example of spec that just began to fail:
describe "show.html.erb", type: :feature do
context "as admin" do
let!(:foo) { FactoryGirl.create(:foo) }
let!(:user) { FactoryGirl.create(:admin_user) }
before :each do
page.set_rack_session(user_id: user.id)
visit data_service_path(foo.id)
end
it "displays the foo's name" do
expect(page).to have_content(foo.name)
end
end
end
How is it possible that html is not the expected response? How could the controller react as if it has to produce a different format?
Thanks.
Updated: I'm also seeing NoMethodError: undefined method 'symbolize_keys' for "":String on some lines that are doing the controller requests from the controller_specs. I have no changes in spec_helper.rb when compared to working version of the test suite.
If I add format: :html to a call in the controller spec, it passes. I must have the app globally configured to respond to :js.

Rspec - Test that rails view renders a specific partial

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.

Rspec Test Required parameters

I'm using FactoryGirl and Rspec for my test framework. I have a model that has a validates_presence_of validation on it. The basic Rspec framework includes a test:
describe "with invalid params" do
it "assigns a newly created but unsaved disease as #disease" do
# Trigger the behavior that occurs when invalid params are submitted
Disease.any_instance.stub(:save).and_return(false)
post :create, :disease => {}
assigns(:disease).should be_a_new(Disease)
end
end
Edit:
diseases_controller.rb
# POST /diseases
# POST /diseases.xml
def create
#disease = Disease.new(disease_params)
respond_to do |format|
if #disease.save
format.html { redirect_to(#disease, :notice => 'Disease was successfully created.') }
format.xml { render :xml => #disease, :status => :created, :location => #disease }
else
format.html { render :action => "new" }
format.xml { render :xml => #disease.errors, :status => :unprocessable_entity }
end
end
end
private
def disease_params
params.require(:disease).permit(:name, :omim_id, :description)
end
This test doesn't work with how my application works. Rather than returning a new disease on an incorrect post, it returns an error:
Required parameter missing: disease
Question #1: I don't know how to look at what is being returned with Rspec does the post. The response object doesn't appear to be created in this case? Printing assigns(:disease) doesn't appear to contain anything. I got the error message I posted earlier by submitting a cURL post to the correct URL with empty data (which is what the rspect post should be doing), but I don't know how to get the information of what Rspec is receiving back from the post statement.
Question #2: How do I properly test the response that should be occurring - that it receives an error message saying that a required parameter is missing?
edit:
So my controller seems to indicate that it should render a new disease, but the test fails. If I attempt to submit a disease missing the required parameter on the website, then it does a flash notice that says "Name can't be blank". I'm not sure how to test that in rspec.
edit #2:
Included the code above. disease_params is defined at the bottom of the controller in accordance with recommendations for using the strong_parameters gem.
Thanks!
To answer Question 1 ("I don't know how to look at what is being returned with Rspec does the post")... You can use "puts" statements within your spec (i.e. within the it block). For instance, you can try something like this:
describe "with invalid params" do
it "assigns a newly created but unsaved disease as #disease" do
# Trigger the behavior that occurs when invalid params are submitted
Disease.any_instance.stub(:save).and_return(false)
post :create, :disease => {}
puts :disease
assigns(:disease).should be_a_new(Disease)
end
end
It's a valuable debugging tool. The output will be in the .s and Fs in the terminal when RSpec is running.
For Question 2, I'm not quite sure what you're looking for, but I don't know that you need to (or should) test that the invalid disease is assigned as #disease. I tend to pattern controller specs in the following style (taken from Everyday Rails Testing with RSpec which is where I learned how to write controller specs).
POST create spec example:
context "with invalid attributes" do
it "does not save the new contact" do
expect{
post :create, contact: Factory.attributes_for(:invalid_contact)
}.to_not change(Contact,:count)
end
it "re-renders the new method" do
post :create, contact: Factory.attributes_for(:invalid_contact)
response.should render_template :new
end
end
...
You may have a reason for more thoroughly testing the controller method that I don't know about. In that case, kindly disregard my answer to Question 2 and hopefully my other answer is useful!

Testing mocked model with RSpec2 returning 0 items and no response body

I am attempting to create an API with Rails using BDD with RSpec.
Rails version is 3.1.1, Ruby version is 1.9.2, Devise version is 1.5.3, and rspec version is 2.7.0. I am relatively new to Rails and very new to RSpec.
I have defined a simple RSpec as follows to test a FormsController with essentially no logic.
describe FormsController, " handling GET /forms" do
include Devise::TestHelpers
render_views
before do
user = Factory.create(:user) # Handle Devise authentication
user.confirm!
sign_in user
#form = mock_model(Form)
Form.stub!(:all).and_return([ #form ])
end
it "gets successfully" do
get :index, :format => :json
response.should be_success
end
it "finds all forms" do
Form.should_receive(:all).and_return([#form])
get :index, :format => :json
Rails.logger.info "*** response.body="+response.body
end
end
Form controller code is very simple currently.
class FormsController < ApplicationController
before_filter :authenticate_user!
# GET /forms
# GET /forms.json
def index
#forms = Form.find_all_by_owner_id(current_user.id)
respond_to do |format|
format.html # index.html.erb
format.json { render :json => #forms }
end
end
end
When I run the spec, "finds all forms" always fails with
Failure/Error: Form.should_receive(:all).and_return([#form])
(<Form(id: integer, title: string, owner_id: integer, created_at: datetime, updated_at: datetime) (class)>).all(any args)
expected: 1 time
received: 0 times
The output from log/test.log shows:
*** response.body=[]
Why? I feel that the problem stems from Form.stub!(:all).and_return([ #form ]), but I am not sure how to debug.
Thanks in advance.
It would help to post your controller code (that is being tested). The error says that the declaration Form.should_receive(:all).and_return([#form]) has not been satisfied. The declaration says you should have code like this in your controller's action: Form.all.
find_all_by_owner_id is not the same as Form.all. find_all_by_owner_id ends up doing
Form.where(...).all
which doesn't match the expectations you've set. In your particular case I'd tell should_receive that I'm expecting a call to find_all_by_owner_id rather than all.
After much more trial and error, the following solution worked for me.
I migrated from mocking the Form model to using Factory Girl to create the full model
I then updated the test to use to_json to compare the response against the model.
The spec is as follows.
describe FormsController, " handling GET /forms" do
include Devise::TestHelpers
render_views
before do
user = Factory.create(:user) # Handle Devise authentication
user.confirm!
sign_in user
#form1 = Factory.create(:form)
end
it "gets successfully" do
get :index, :format => :json
response.should be_success
end
it "finds all forms" do
get :index, :format => :json
response.body.should == [ #form1 ].to_json
Rails.logger.info "*** response.body="+response.body
end
end

Rspec testing redirect_to :back

How do you test redirect_to :back in rspec?
I get
ActionController::RedirectBackError:
No HTTP_REFERER was set in the request to this action, so redirect_to :back could not be called successfully. If this is a test, make sure to specify request.env["HTTP_REFERER"].
How do I go about setting the HTTP_REFERER in my test?
Using RSpec, you can set the referer in a before block. When I tried to set the referer directly in the test, it didn't seem to work no matter where I put it, but the before block does the trick.
describe BackController < ApplicationController do
before(:each) do
request.env["HTTP_REFERER"] = "where_i_came_from"
end
describe "GET /goback" do
it "redirects back to the referring page" do
get 'goback'
response.should redirect_to "where_i_came_from"
end
end
end
From the rails guide when requesting the request with the new request style:
describe BackController < ApplicationController do
describe "GET /goback" do
it "redirects back to the referring page" do
get :show,
params: { id: 12 },
headers: { "HTTP_REFERER" => "http://example.com/home" }
expect(response).to redirect_to("http://example.com/home")
end
end
end
If someone stumbles upon this and they're using request specs, you'll need to explicitly set the headers on the request you're making. The format of the test request depends on which version of RSpec you're using and if you can use keyword arguments instead of positional arguments.
let(:headers){ { "HTTP_REFERER" => "/widgets" } }
it "redirects back to widgets" do
post "/widgets", params: {}, headers: headers # keyword (better)
post "/widgets", {}, headers # positional
expect(response).to redirect_to(widgets_path)
end
https://relishapp.com/rspec/rspec-rails/docs/request-specs/request-spec
IMHO the accepted answer is a bit hacky. A better alternative would be to set the HTTP_REFERER to an actual url in your application and then expect to be redirected back:
describe BackController, type: :controller do
before(:each) do
request.env['HTTP_REFERER'] = root_url
end
it 'redirects back' do
get :whatever
response.should redirect_to :back
end
end
Redirecting to a random string constant feels as if it works by accident
You take advantage of rspec's built in functionality to express exactly what you wanted
You don't introduce and repeat magic string values
For newer versions of rspec, you can use expectations instead:
expect(response).to redirect_to :back
In regard to testing :back links in integration tests, I first visit a deadend page, that I think is not likely to be ever used as a link, and then the page I am testing. So my code looks like this
before(:each) do
visit deadend_path
visit testpage_path
end
it "testpage Page should have a Back button going :back" do
response.should have_selector("a",:href => deadend_path,
:content => "Back")
end
However this does have the flaw that if the link is really to the deadend_path, then the test will incorrectly pass.
request.env['HTTP_REFERER'] = '/your_referring_url'

Resources