How to test for a redirect with Rspec and Capybara
Solution 1
Capybara is not a rails-specific solution so it doesn't know anything about rails's rendering logic.
Capybara is meant specifically for Integration testing, which is essentially running tests from the viewpoint of an end-user interacting with a browser. In these tests, you should not be asserting templates because an end-user can't see that deep into your application. What you should instead be testing is that an action lands you on the correct path.
current_path.should == new_user_path
page.should have_selector('div#erro_div')
Solution 2
you can do it this way:
expect(current_path).to eql(new_app_user_registration_path)
Solution 3
Rspec 3:
The easiest way to test for the current path is with:
expect(page).to have_current_path('/login?status=invalid_token')
The have_current_path
has an advantage over this approach:
expect(current_path).to eq('/login')
because you can include query params.
Solution 4
The error message @request must be an ActionDispatch::Request
tells you that rspec-rails matcher redirect_to
(it delegates to Rails assert_redirected_to
) expects it to be used in Rails functional tests (should mix in ActionController::TestCase
). The code you posted looks like rspec-rails request spec. So redirect_to
is not available.
Checking for redirect is not supported in rspec-rails request specs, but is supported in Rails integration tests.
Whether you should explicitly check for how redirect was made (that it is was a 301 response and not a 307 response and not some javascript) is completely up to you.
Solution 5
Here is hackish solution that i found
# spec/features/user_confirmation_feature.rb
feature 'User confirmation' do
scenario 'provide confirmation and redirect' do
visit "/users/123/confirm"
expect(page).to have_content('Please enter the confirmation code')
find("input[id$='confirmation_code']").set '1234'
do_not_follow_redirect do
click_button('Verify')
expect(page.driver.status_code).to eq(302)
expect(page.driver.browser.last_response['Location']).to match(/\/en\//[^\/]+\/edit$/)
end
end
protected
# Capybara won't follow redirects
def do_not_follow_redirect &block
begin
options = page.driver.instance_variable_get(:@options)
prev_value = options[:follow_redirects]
options[:follow_redirects] = false
yield
ensure
options[:follow_redirects] = prev_value
end
end
end
Related videos on Youtube
Mohamad
I love well designed digital products, programming, and tech. Driving digital product roadmap in Brazil for world’s third largest retailer of home decor and building materials.
Updated on June 13, 2020Comments
-
Mohamad almost 4 years
I don't know what I'm doing wrong, but every time I try to test for a redirect, I get this error: "@request must be an ActionDispatch::Request"
context "as non-signed in user" do it "should redirect to the login page" do expect { visit admin_account_url(account, host: get_host(account)) }.to redirect_to(signin_path) end end 1) AdminAccountPages Admin::Accounts#show as non-signed in user should redirect to the login page Failure/Error: expect { visit admin_account_url(account, host: get_host(account)) }.to redirect_to(signin_path) ArgumentError: @request must be an ActionDispatch::Request # ./spec/requests/admin_account_pages_spec.rb:16:in `block (4 levels) in <top (required)>'
I'm using RSpec-rails (2.9.0) with Capybara (1.1.2) and Rails 3.2. I would appreciate it if someone could also explain why this is happening; why can't I use the expect in such a way?
-
Joseph Weissman almost 12 yearsMaybe I'm missing something, but what's wrong with
assert_redirected_to
? -
Mohamad almost 12 years@JosephWeissman, I get the same error!
-
-
bjnord over 7 yearsWith newer versions of Capybara this no longer works. I have 2.10.1 and there is a new method
have_current_path
that can be used:expect(page).to have_current_path(new_user_path)
-
Rennan Oliveira almost 7 yearsThis helps if your redirect happens to be an external link
-
sekmo over 6 yearswhich is the difference with expect(current_path).to eq('/login?status=invalid_token') ?
-
nruth over 5 years@sekmo if you do that (as most of us used to) it uses the current value, which might not have stabilised yet, and you'll have a race condition in your test. When you use
have_current_path
it uses the capybara retry logic you're familiar with from dom assertions to retry the value until it matches or hits your timeout/retry limit and fails the test. -
nruth over 5 yearswhich driver is this for?
-
randmin about 4 years@bjnord Not true. current_path still works even in 3.13. You use a new syntax that comes with latest rspec and has nothing to do with capybara. See the answer of The Whiz of Oz ;)