aflatter.de

Testing custom headers and ssl with Cucumber and Capybara

2010-06-22

Today I ran into yet another issue where a little hack is required to get the job done. I was testing our application and came to a point where ssl is required. In plain old webrat you could do:

header "HTTPS", "on"

Even simpler, when using Rack::Test directly, you can just use the third parameter of your favorite request method to pass additional stuff:

get :index, {}, { :https => 'on' }

If you try to test for custom headers with capybara, you will run into trouble. There is simply no method to get access to the request environment, so things become a little more difficult. The following solution will work only if you use the :rack_test driver. Any other drivers do not support setting headers. Simply put the following code into features/support/headers_hack.rb which will automatically be loaded by cucumber.

module RackTestMixin

  def self.included(mod)
    mod.class_eval do
      # This is where we save additional entries.
      def hacked_env
        @hacked_env ||= {}
      end
      
      # Alias the original method for further use.
      alias_method  :original_env, :env

      # Override the method to merge additional headers.
      # Plus this implicitly makes it public.
      def env
        original_env.merge(hacked_env)
      end
    end
  end

end

Capybara::Driver::RackTest.send :include, RackTestMixin

module HeadersHackHelper
  
  def add_headers(headers)
    page.driver.hacked_env.merge!(headers)
  end

end

World(HeadersHackHelper)

It will give you access to an additional attribute of the driver, #hacked_env. Use this hash to set additional entries as you like. Some examples:

# To test ssl
Given /^I use ssl$/ do
  add_headers('HTTPS', 'on')
end

# To set the remote ip
Given /^my IP is (\d{1,3}\.){3}\d{1,3}$/ do |ip|
  add_headers('REMOTE_ADDR', ip)
end

# If you check for user agent
Given /^my user agent is "(.+)"$/ do |agent|
  add_headers('User-Agent', agent)
end