43

Does anyone know how to make rspec follow a redirect (in a controller spec)? (e.g test/unit has follow_redirect!)

I have tried "follow_redirect!" and "follow_redirect" but only get

undefined method `follow_redirect!' for #<Spec::Rails::Example::ControllerExampleGroup::Subclass_1:0xb6df5294>

For example:
When I create an account the page is redirected to accounts page and my new account should be at the top of the list.

it "should create an account" do
  post :create, :name => "My New Account"
  FOLLOW_REDIRECT!
  response.code.should == "200"
  accounts = assigns[:accounts]
  accounts[0].name.should == "My New Account"
end

But FOLLOW_REDIRECT! needs to be changed to something that actually works.

Jonas Söderström
  • 4,641
  • 2
  • 33
  • 45

6 Answers6

66

I think this is the default behavior for rspec-rails controller tests, in the sense that you can set an expectation on the response status and/or path, and test for success.

For example:

it "should create an account" do
  post :create
  response.code.should == "302"
  response.should redirect_to(accounts_path)
end
zetetic
  • 45,844
  • 10
  • 106
  • 115
  • Hi Zetetic. Thanks for your reply. What you describe in your answer would be the correct way to Verify that the response is a 302-redirect to the accounts_path. What I want to do is to follow the redirect to the accounts_path and verify the behaviour of that page. E.g. verify that my new account is listed there. – Jonas Söderström May 20 '10 at 07:35
  • I updated my question, hope you don't mind that I borrowed your example. – Jonas Söderström May 20 '10 at 07:41
  • 1
    Guess I misunderstood the question. Would `integrate_views` help in this situation? – zetetic May 20 '10 at 08:27
  • `integrate_views` does not seem to help. I still get "...You are being redirected..." response, but it was a good try – Jonas Söderström May 20 '10 at 11:58
  • 2
    Now I can test that the redirect worked. But that is not that I am looking for. I want, that rspec is following automatically the redirects and and I want to have success/error from the redirected page. This is important if you test a controller which enforces https. In that case I am even not leaving my domain. Any thought how to do that? – Robert Reiz Jul 16 '12 at 11:24
  • This answer addresses that: http://stackoverflow.com/a/2874007/17410. Capybara is a good choice. – zetetic Jul 16 '12 at 17:56
  • As of RSpec3.1, it prefers this syntax: `expect(response).to redirect_to(accounts_path)` see also - https://www.relishapp.com/rspec/rspec-rails/docs/matchers/redirect-to-matcher – Nobu Dec 01 '14 at 20:20
30

You can access the redirect location with

response.headers['Location']

you could then request that directly.

toonsend
  • 919
  • 8
  • 12
  • 7
    This is the only direct answer to the OP. Others state what **should** be done, but this is the only one that tells how to do what is requested. That is helpful in case someone comes here from a Google query like I did. – Jonathan Geisler Apr 30 '14 at 18:06
  • This would work but be sure to declare `response.params` if any. For example, maybe I want to test that my redirect renders a particular flash message. testing a `GET response.headers['Location']` alone won't do that. – Jesse Novotny Jun 16 '17 at 22:37
19

If you want to test the redirect you are moving outside of the rspec-rails domain.

You can use Webrat or some other integration-test framework to test this.

The easiest way to solve this without resorting to integration testing is probably to mock out the method that is causing the redirect.

andersjanmyr
  • 10,492
  • 5
  • 26
  • 28
  • 1
    i think this answer is incorrect, the one from zetetic is correct – jpw Dec 23 '12 at 04:26
  • 4
    Actually this answer *is* correct, and mine is not. My answer only shows how to verify that a redirect occurs -- OP asked how to test the contents of the response after the redirect is followed. – zetetic Mar 19 '13 at 21:43
4

The spec is out of scope, if you want to follow a redirect use request spec, the equivalent of integration test in Test::Unit.

In request specs follow_redirect! works as well as in Test::Unit.

Or if you want to redirect inmediately use _via_redirect as suffix for the verb, example:

post_via_redirect :create, user: @user
2

Try to use integration/request tests. They are using web-like acces through routing to controllers. For example: I have for Rails 2 app in file /spec/integration/fps_spec.rb

 require 'spec_helper'

 describe "FinPoradci" do 

   it "POST /fps.html with params" do
     fp_params={:accord_id => "FP99998", :under_acc => "OM001", :first_name => "Pavel", :last_name => "Novy"}
     fp_test=FinPoradce.new(fp_params)
     #after create follow redirection to show
     post_via_redirect "/fps", {:fp => fp_params}
     response.response_code.should == 200 # => :found ,  not 302 :created
     new_fp=assigns(:fp)
     new_fp.should_not be_empty
     new_fp.errors.should be_empty
     flash[:error].should be_empty
     flash[:notice].should_not be_empty
     response.should render_template(:show)
   end
 end

and it works. Until you want to send headers (for basic http authorization).

 env={'HTTP_AUTHORIZATION' => ActionController::HttpAuthentication::Basic.encode_credentials(user,password)}
 post_via_redirect "/fps", {:fp => fp_params}, env

is fine for create, but after redirection it returns 401 and needs new authorization. SO I have to split it in 2 tests: creation and show on result of creation.

Foton
  • 1,057
  • 12
  • 20
0

For RSpec / Capybara + Rails

response_headers['Location']

But it works only if there is no delay before redirect. If it is there, then it's harder to follow the logic.

Vjatseslav Gedrovits
  • 1,091
  • 1
  • 9
  • 12