This blog has been archived. Our writing has moved to makandra cards.
The blog of , a Ruby on Rails development team

Testing your custom error pages with Webrat and Cucumber

When your application raises an error during development, Rails and Webrat will provide you with useful information like the error's type and stacktrace.

But now you created that shiny, custom error page by overriding rescue_action_in_public. You would like to write a Cucumber feature that tests whether your new error page localizes into 10 languages and displays all the information it should.

Unfortunately it requires some serious Judo to make your error page visible to selected scenarios, while keeping Rails' helpful default behavior for your other tests. Here is how you do it.

First, we will tame Webrat. Webrat raises an exception when you visit a page that shows an error. So we're going to write a step that visits a page, but ignores errors:

When /^I ignore errors while visiting (.+)$/ do |page_name|
  begin
    visit path_to(page_name)
  rescue
  end
end

Now we need to get Rails to render the error page for selected scenarios. Unfortunately we will have to flip a lot of switches to accomplish this.

Put the following into your support/env.rb. With this code we can make Rails treat selected requests as remote ones, (local requests never see error pages), regardless of what consider_all_requests_local is set to:

ActionController::Base.class_eval do
  protected

  cattr_accessor :local_request_override

  def local_request_with_override?
    local_request_override.nil? ? local_request_without_override? : local_request_override
  end

  alias_method_chain :local_request?, :override
end

Finally we need a step that flips all the magic switches for the current scenario and reverts to the previous error handling afterwards:

Given /^error pages will be rendered$/ do
  @old_allow_rescue = ActionController::Base.allow_rescue
  @old_consider_all_requests_local = ActionController::Base.consider_all_requests_local
  @old_local_request_override = ActionController::Base.local_request_override
  ActionController::Base.local_request_override = false
  ActionController::Base.allow_rescue = true
  ActionController::Base.consider_all_requests_local = false
end

After do
  @old_allow_rescue.nil? or ActionController::Base.allow_rescue = @old_allow_rescue
  @old_consider_all_requests_local.nil? or ActionController::Base.consider_all_requests_local = @old_consider_all_requests_local
  @old_local_request_override.nil? or ActionController::Base.local_request_override = @old_local_request_override
end

Now you can write your error_pages.feature:

Feature: custom error pages
  In order to not scare my users when things go wrong
  As the site owner
  I want to display friendly error pages

  Scenario: A country cannot be found
    Given error pages will be rendered
    And I ignore errors while visiting the country "Narnia"
    Then I should see "Oops, we couldn't find Narnia!"

I recommend you extend your feature to cover some more cases and also make it check if proper HTTP status codes are returned.

Was this post helpful to you? Then let us know!

Growing Rails Applications in Practice
Check out our e-book:
Learn to structure large Ruby on Rails codebases with the tools you already know and love.

Recent posts

Our address:
makandra GmbH
Werner-von-Siemens-Str. 6
86159 Augsburg
Germany
Contact us:
+49 821 58866 180
info@makandra.de
Commercial register court:
Augsburg Municipal Court
Register number:
HRB 24202
Sales tax identification number:
DE243555898
Chief executive officers:
Henning Koch
Thomas Eisenbarth