Read more

Test redirects to an external URL with Cucumber/Capybara

Henning Koch
March 21, 2013Software engineer at makandra GmbH

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
Illustration web development

Do you need DevOps-experts?

Your development team has a full backlog? No time for infrastructure architecture? Our DevOps team is ready to support you!

  • We build reliable cloud solutions with Infrastructure as code
  • We are experts in security, Linux and databases
  • We support your dev team to perform
Read more Show archive.org snapshot

There are two workarounds for this. You can use either, or a combination of both.

  1. 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
  1. 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
Henning Koch
March 21, 2013Software engineer at makandra GmbH
Posted by Henning Koch to makandra dev (2013-03-21 15:03)