How to Get Production-like Error Responses in Your Rails Tests

In the Rails test environment, when your app responds with an error, it will show a detailed exception page (the one with the stacktrace and console) to help you debug it.

Showing the detailed exception page is perfect for unexpected errors - it helps you debug. However, for expected error responses that you want to test (say an API error or a 404 Not Found), for consistency, you'll usually want your app to respond with the same responses your app would give in production.

In these cases where you need production-like error responses to test against, you can temporarily set the Rails exception page configuration to match typical production values. Below is the code to help you do this in an RSpec suite.

# File: spec/support/error_responses.rb
# Ensure this file is require-d by rails_helper.rb or spec_helper.rb
module ErrorResponses

  def respond_without_detailed_exceptions
    env_config = Rails.application.env_config
    original_show_exceptions = env_config["action_dispatch.show_exceptions"]
    original_show_detailed_exceptions = env_config["action_dispatch.show_detailed_exceptions"]
    env_config["action_dispatch.show_exceptions"] = true
    env_config["action_dispatch.show_detailed_exceptions"] = false
    yield
  ensure
    env_config["action_dispatch.show_exceptions"] = original_show_exceptions
    env_config["action_dispatch.show_detailed_exceptions"] = original_show_detailed_exceptions
  end

end

RSpec.configure do |config|
  config.include ErrorResponses

  config.around(realistic_error_responses: true) do |example|
    respond_without_detailed_exceptions(&example)
  end
end

Source: https://github.com/eliotsykes/rails-testing-toolbox/blob/master/error_responses.rb

Add :realistic_error_responses (or realistic_error_responses: true) to your spec metadata to get the production-like error responses we've been talking about, for example:

describe 'Sessions API', :realistic_error_responses do
  ...
end

(Alternatively, you can call the respond_without_detailed_exceptions method directly, passing it a block inside of which you make the request, but I prefer the metadata technique, I find it more intention-revealing and it doesn't add as much distracting noise to the test.)