I have an interesting situation. I am testing the following simple create action:
# will only be accessed via Ajax
def create
click = Click.new(params[:click])
click.save # don't really care whether its success or failure
end
Then I have the following very simple controller spec:
require 'spec_helper'
describe ClicksController, "creating a click" do
it "should create a click for event" do
xhr :post, :create, :click => {:event_id => 1}
# more test to come...
end
end
Seems trivial, yet I get the following:
Missing template clicks/create
Any tips would be appreciated.
Add to the controller action:
render :nothing => true
This one will automatically create the appropriate server's respone. More here
You will get this error if your controller renders only JSON or XML, yet you don't specify a format in the spec; your request then defaults to unsupported HTML. In that case, simply specify the supported format when you invoke the controller method from your spec. For example, change this:
post :create, registration: #user_hash
to this:
post :create, registration: #user_hash, format: :json
If you do not render anything in a controller action, rails will attempt to default to rendering a template (in this case clicks/create). I'd suggest rendering back at least a success message like so:
render :json => {:success => true}
Building on megas's answer, if you're looking to test a controller action that's only accessed via a UJS link and only has a .js.erb template, I'd put this in the controller to avoid breaking your UJS functionality:
respond_to do |f|
f.html { render nothing: true } # prevents rendering a nonexistent template file
f.js # still renders the JavaScript template
end
This will enable you to call the controller action by simply calling ActionController::TestCase::Behavior's get/post/put/delete methods instead of needing to call xhr, because it will successfully call the method, render nothing, and continue on, while leaving your UJS behavior intact.
Related
I have controller action like
def get_status
status_name = current_user.status
status_updated_time = current_user.updated_at
render :partial => 'show_status', :locals => {status_name: status_name, status_updated_time: status_updated_time}
end
here I am planning to test local variable values which are passing via render partial. i.e
status_name, status_updated_time.
Could you please let me know how to write rspecs for render partial with locals in controller.
I would move variable logic into a separate method:
def get_status
render partial: 'show_status', locals: get_status_from(current_user)
end
protected
def get_status_from(user)
{ status_name: user.status, status_updated_time: user.updated_at }
end
and test that method instead.
I would say that to test the controller, what you're after is a basic feature/integration spec wherein you can simply look for the content held by your partial.
feature 'SomeController' do
background do
# setup data
# and anything else you need for authentication, etc. as your site dictates
end
scenario 'viewing the get status page' do
visit some_controller_get_status_path
expect(page).to have_text('WHATEVER IS IN THE LOCAL VAR')
end
end
I prefer to use feature specs over controller specs as I seek (but often fail!) to keep my controllers so simple that there is not really much to test in them. With feature specs, I feel like I'm getting more from the test in terms of how my app works, etc.
EDIT: sorry ... hit enter too early :).
For a controller, you could directly test the var value along the lines of:
describe "Your Controller", :type => :controller do
describe "GET get_stuff" do
it "assigns a value to status_name" do
get :get_status
expect(assigns(:status_name)).to eq(['VALUE'])
end
end
end
That may not be 100% spot-on for a controller spec (again, I don't use them a lot) but I think it should get you on your way should you go controller spec over feature/integration spec.
you could do something like
it "should render correct partial for get_status" do
controller.should_receive(:render).with({
:partial => '_show_status', #here you will have to give the full path like <controller_name>/_show_status
:locals => {status_name: <name>, status_update_time: <time>}
})
get 'get_status'
end
I have a rails project with the following route:
get 'login', to: 'user_sessions#new', as: :login
In my UserSessionsController I have
def create
#user_session = UserSession.new(params[:user_session])
respond_to do |format|
if #user_session.save
# Do all the happy stuff
else
format.html { render :action => 'new' }
format.xml { render xml: #user_session.errors, status: :unprocessable_entity }
end
end
end
That's working ok, except that when the user enters incorrect parameters the route is via /user_sessions instead of /login, which is untidy (and means my test assertions are confusing).
Obviously I could just redirect_to login_path, but then my #user_session.errors don't seem to be available so by page doesn't show what was wrong.
How do I redirect back to /login and still have the errors show?
Edit:
It looks as if Rails makes this difficult because it's something I shouldn't try to do. The RESTful path isn't really something the user cares about so I shouldn't be using it as part of my UI testing. Instead, I am looking at the actual content of the rendered page, which the user does care about. Thanks all.
You can add
post 'login', to: 'user_sessions#create', as: :post_login
and change the form action accordingly.
This is happening because when you get validation errors in your form then you are on create action and not new action. Your create action simply render your new actions template with errors, it doesn't send a request to server and hence your url remains same so to fix it you can simply change the route for your create action to this:
post 'login', to: 'user_sessions#create', as: :login
Update:
You'll just have to change your route for create action and then make changes in your form, something like this:
<%= from_for #resource, url: login_path do |f| %>
// form fields
<% end %>
If you'll inspect your form you'll see that its method is POST so when you'll submit it, your form will send a POST request and when you hit /login in your browsers address bar it'll send a GET request so in first case you'll go to create action and in second one you'll go to new action
RESTful resource, default type routes. Creating an event is supposed to work as follows:
def create
#event = current_user.events.build(params[:event])
if #event.save
redirect_to #event, :flash => { :success => "Event created!" }
else
render :action => "new" # new_event_path
end
end
When invalid data is entered, it does render the "new" view/form again, but it renders this view at the "localhost:3000/events" URL, where the "index" action/view should be on.
My event routes seem like they ought to be pretty predictable:
resources :events
I just updated to Capybara 2, began using DatabaseCleaner, and set transactional_fixtures to false in preparation for testing some JS-enabled functionality but can't think of any other way I might have stuffed this up.
Is there some simple thing I'm missing that could cause a weird routing muck up like this?
Ideas, anyone, on where to start troubleshooting it?
This is the correct behavior. What is happening is that it is using the POST method for that URL when issuing the create action. Using a GET at the URL would be the index action. Also note that rendering a different template does not change the URL (that would require a redirect).
Check out section 2.2 in the Rails Routing documentation:
http://guides.rubyonrails.org/routing.html
When you create event from submitting form you using post method to /events route. And when data becomes invalid rails render events/new for your /events(POST) request at /events address.
But you can
redirect_to action: "new", event: #event.attributes
and add to new action
#item = Item.new(params[:item].except('protected attributes','created_at', 'updated_at', 'id'))
I haven't been able to find any useful resources online on how to do this. Basically what I'm trying to do is run a simple jQuery $('#test-div').show(); when my def show_div controller action is complete.
I've tried the following and it doesn't work. It actually renders HTML which is confusing to me. when I explicitly state that the method respond with js.
users_controller.rb
def show_div
#user = User.first
respond_to do |format|
format.js {}
end
# also tried
# render :js => "$('#test-div').show();"
end
show_div.js.erb
$('#test-div').show();
render :text should do what you are asking for -- just return raw text (which in your case happens to be JavaScript code) without doing anything to it.
I am currently trying to add some parsing methods to a controller method in a Rails 3 application.
I have a controller action as follows:
def control
#device = Device.find(params[:id])
<do things>
parse_return(#returned_data)
end
and I added a custom method to the controller as below (this method would not have any routes and would only be accessible to controller actions):
def parse_return
<parse data>
end
but this does not appear to allow the parse_return method to be used. Is there somewhere else in the Rails app that I can put re-usable methods?
Thanks!
At a first glance it seems that you fail to render a response. Is it true that control action doesn't have an associated view?
In this case you have to manually call render in your action. For example, to render JSON response you can do this:
def control
# ...
render :json => parse_return(#returned_data),
:content_type => 'application/json',
:layout => false
end
You should include what the errors are.
What happens if you try this?
def parse_return(returned_data)
<parse data>
end
Perhaps the method is not expecting an parameter to be passed along with it.