When a controller action redirects to an external URL (like http://somehost.com/some/path
) you will find that this is hard to test with Cucumber and Capybara:
- A non-Javascript Rack::Test scenario will just ignore the host and try to open
/some/path
in your local application - A Selenium test will actually follow the redirect, which you probably don't want either
There are two workarounds for this. You can use either, or a combination of both.
- Write a controller spec
Controller specs can test if a response is a redirect:
describe FooContoller do
describe '#redirecting_action' do
it 'should redirect to somehost.com' do
get :redirecting_action
response.should redirect_to('http://somehost.com/some/path')
end
end
end
- Make the redirect observable from Cucumber
A hack is to write the destination URL to the screen instead of actually redirecting (only in integration tests). This way Capybara can "see" the destination URL with a regular page.has_content?('http://....')
.
To do this, in your redirecting action, use observable_redirect_to
instead of redirect_to
:
class FooController < ApplicationController
def redirecting_action
observable_redirect_to('http://somehost.com/some/path')
end
end
To get observable_redirect_to
, add these helper methods to your ApplicationController
:
class ApplicationController < ActionController::Base
private
def integration_test?
Rails.env.test? && defined?(Cucumber::Rails)
end
def observable_redirect_to(url)
if integration_test?
render :text => "If this wasn't an integration test, you'd be redirected to: #{url}"
else
redirect_to url
end
end
end
In your Cucumber feature, you can now say:
Then I should be redirected to the external site "http://somehost.com/some/path"
This step is implemented with this step definition:
Then(/^I should be redirected to the external site "(.*?)"$/) do |url|
page.should have_content("If this wasn't an integration test, you'd be redirected to: #{url}")
end