—UPDATE—
Since writing this post, I’ve put together a gem called ‘responsalizr‘ which is a way better solution than what follows in this post. Read about it here. And now back to the original post…
Testing redirects from a web app is simple enough – make a request and check the response code making sure it’s a 301, 302 or whatever you’re expecting. The test you end up writing isn’t nice idiomatic ruby though. So, I wrote a quick monkey patch… here it is:
class Net::HTTPResponse
#returns true if the response is a 200
def ok?
instance_of?(Net::HTTPOK)
end
#returns true if the response is a 301
def found?
instance_of?(Net::HTTPFound)
end
#returns true if the response is a 302
def moved_permanently?
instance_of?(Net::HTTPMovedPermanently)
end
#returns true for any kind of redirect (301..307)
def redirect?
kind_of?(Net::HTTPRedirection)
end
#returns the url being redirected to if this response is a redirect
def redirect_url
redirect? ? self['location'] : raise("Not a redirect response")
end
end
Basically, it adds the following predicate methods to the Net::HTTPResponse class: “ok?” (returns true if response code is 200), “found?” (returns true if response code is 301), “moved_permanently?” (returns true if response code is 302) and “redirect?” (returns true if the response is a redirect – from 301..307). Because these are predicate methods, they can be used by rspec – your test code suddenly becomes much cleaner! The moneky patch also adds the “redirect_url” method which returns the url to be redirected to if the response is a redirect of some sort. The advantage of this is that your tests become much more idiomatic:
#the urls we're testing with...
@url_initially_navigated_to = "http://mail.google.com"
@expected_redirect_url = "https://www.google.com/.../etc/..."
#make the request
@response= Net::HTTP.get_response(URI.parse(@url_initially_navigated_to))
#nice idiomatic tests! - use the one you're expecting...
@response.should be_ok #expecting a 200
@response.should be_found #expecting a 301
@response.should be_moved_permanently #expecting a 302
@response.should be_a_redirect #expecting anything between 301..307
#testing the url being redirected to
@response.redirect_url.should match(@expected_redirect_url)
There you go! Nice idiomatic redirect tests! Enjoy.