views:

92

answers:

3

In a functional test of my Rails app, I want to test where I am redirected to. The expected URL points to an external resource (that means it's not part of my application).

The URL looks like this: https://my.url.com/foo?bar1=xyz&bar2=123

Unfortunately I can't predict the parameters, because they are generated by an external resource.*
However, the rest of the URL always stays the same: https://my.url.com/foo

I usually use assert_redirected_to for this kind of test, but this expects the whole URL, including the parameters.

Can anyone think of another way to test that redirection but only check for the first part of the URL without the parameters?

(the URL is not in the assigns Hash)

*(I make an API call to an application, which responses with the URL I shall redirect_to)

+2  A: 

Two quick thoughts on this:

1) If your functional test actually connects to the external application, why not just get the params out of it as you would normally and test that the redirect occurs properly?

2) If your functional test does not actually connect to the external application, then you're faking it anyway, so I would just skip testing the redirect URL and just test for a redirect with assert_response :redirect. Or, create a mock that returns the URL for redirection as if it were the external app, but do it in such a way that you can get the params out of it.

That said, don't get so carried away with tests that you feel you have to cover every single possible scenario.

adriandz
Thanks for your thoughts. You're probably right, that I shouldn't get carried away too much with tests. I think in my case, it really is not _that_ important to test for the correct URL I get redirected_to. However, I was curious, if it's possible to solve this problem.
Daniel Pietzsch
+1  A: 

How about this? It wraps assert_redirected_to to allow a Regexp as the first argument. This won't work if you try to match the Regexp to a Hash -- only a String, though. Doing that would take a bit more work.

ActionController::TestCase.class_eval do

  old_assert_redirected_to = method(:assert_redirected_to)

  define_method(:assert_redirected_to) do |*args|
    if args.[0].kind_of?(Regexp)
      assert_response(:redirect, args[1])
      assert args[0] === @response.redirected_to
    else
      old_assert_redirected_to.bind(self).call(*args)
    end
  end

end
James A. Rosen
+1 for pointing me in the right direction. Your answer helped me find my own answer. :-) Thanks!
Daniel Pietzsch
A: 

The http request commands like post, get etc. create an instance variable called @response when they are called*. @response itself contains a method called redirected_to which stores the URL you have been redirected to (in case you have really been redirected).

Therefor, I can just use a normal assert_match to compare a regular expression to @response.redirected_to:

post :my_action_to_test
assert_response :redirect
assert_match /https:\/\/my.url.com\/foo/, @response.redirected_to

*(actually, these http methods just use the private method process, which creates the @response variable).

Daniel Pietzsch