ChatGPT解决这个技术问题 Extra ChatGPT

Rspec testing redirect_to :back

How do you test redirect_to :back in rspec?

I get

ActionController::RedirectBackError: No HTTP_REFERER was set in the request to this action, so redirect_to :back could not be called successfully. If this is a test, make sure to specify request.env["HTTP_REFERER"].

How do I go about setting the HTTP_REFERER in my test?

It might be useful to see the test source itself. This might be symptomatic of another issue...
I was able to alleviate this error by calling 'visit root_path' first. But I think I can only do that in an integration test. Is that right?

j
jrh

Using RSpec, you can set the referer in a before block. When I tried to set the referer directly in the test, it didn't seem to work no matter where I put it, but the before block does the trick.

describe BackController < ApplicationController do
  before(:each) do
    request.env["HTTP_REFERER"] = "where_i_came_from"
  end

  describe "GET /goback" do
    it "redirects back to the referring page" do
      get 'goback'
      response.should redirect_to "where_i_came_from"
    end
  end
end

I found it was a good idea to use: request.env["HTTP_REFERER"] = "where_i_came_from" unless request.nil? or request.env.nil?
yeah. for me it is always nil and it is just not working. Looks like a huge bug to me.
It may have been updated to fix this issue since this answer was created, but I'm able to successfully set request.env["HTTP_REFERER"] in my test without using a before block.
i
ivanxuu

From the rails guide when requesting the request with the new request style:

describe BackController < ApplicationController do
  describe "GET /goback" do
    it "redirects back to the referring page" do
      get :show, 
        params: { id: 12 },
        headers: { "HTTP_REFERER" => "http://example.com/home" }
      expect(response).to redirect_to("http://example.com/home")
    end
  end
end

s
sp89

If someone stumbles upon this and they're using request specs, you'll need to explicitly set the headers on the request you're making. The format of the test request depends on which version of RSpec you're using and if you can use keyword arguments instead of positional arguments.

let(:headers){ { "HTTP_REFERER" => "/widgets" } }

it "redirects back to widgets" do 
  post "/widgets", params: {}, headers: headers # keyword (better)
  post "/widgets", {}, headers                  # positional

  expect(response).to redirect_to(widgets_path)
end

https://relishapp.com/rspec/rspec-rails/docs/request-specs/request-spec


n
ndnenkov

IMHO the accepted answer is a bit hacky. A better alternative would be to set the HTTP_REFERER to an actual url in your application and then expect to be redirected back:

describe BackController, type: :controller do
  before(:each) do
    request.env['HTTP_REFERER'] = root_url
  end

  it 'redirects back' do
    get :whatever
    response.should redirect_to :back
  end
end

Redirecting to a random string constant feels as if it works by accident

You take advantage of rspec's built in functionality to express exactly what you wanted

You don't introduce and repeat magic string values

For newer versions of rspec, you can use expectations instead:

expect(response).to redirect_to :back

O
Obromios

In regard to testing :back links in integration tests, I first visit a deadend page, that I think is not likely to be ever used as a link, and then the page I am testing. So my code looks like this

   before(:each) do
       visit deadend_path
       visit testpage_path
    end
    it "testpage Page should have a Back button going :back" do
      response.should have_selector("a",:href => deadend_path,
                                        :content => "Back")
    end

However this does have the flaw that if the link is really to the deadend_path, then the test will incorrectly pass.


U
Undo
request.env['HTTP_REFERER'] = '/your_referring_url'