Wednesday, January 03, 2007

Testing link_to_remote AJAX calls in Rails

I wanted to be able to test ajax methods in a rails controller, but I wasn't able to find good tutorials on this topic...so either no one uses it, or everyone else just got it right away.

let's say I have the following made up method:

def edit_importance
@friend = Friend.find(params[:id])
@friend.update_attributes(:importance => params[:importance]) unless @friend.nil?
render :partial => "shared/stars"
end
That gets called in the view by:
<%= link_to_remote(image_html, :update => "friend_stars_#{@friend.id}",
:url => { :controller => "friends", :action => :edit_importance,
:id => @friend.id, :importance => nth }) %>

How does this get tested? Well, I figured out there was an xml_http_request call in ActiveController::Testprocess, but I had no idea what to put in the parameters.
xml_http_request(request_method, action, parameters = nil, session = nil, flash = nil)
It ends up that reading RFC 2616 (HTTP) helped, and request_method is just :get, :put, :post, :delete, etc.

So to test out this, all you have to do is:
 def test_edit_importance
jon_lee = friends(:jon_lee) # from a fixture
old_importance = jon_lee.importance

xml_http_request :put, :edit_importance, { :id => jon_lee.id, :importance => 3 }
assert_template "_stars"
jon_lee.reload
assert_equal 3, jon_lee.importance
assert_not_equal old_importance, jon_lee.importance
end
Remember to reload the old object, since it will still have the old values. You can also use jon_lee = assign(:friend) after the xml_http_request, if you don't want to reload.

Also note that you can test for returns of partials with assert_template. It just has to be a string with the preceding "_" as per partials convention.

As for testing RJS templates, you'd want to look into the assert_rjs plugin.

1 comment: