Rspec-rails: Some Errors Are Awkward to Test with Request Specs

Created on 11 Sep 2018  路  9Comments  路  Source: rspec/rspec-rails

What Ruby, Rails and RSpec versions are you using?

Ruby version: 2.4.1p111
Rails version: 5.1.3
Rspec version: 3.8

Observed behaviour

In a request spec, an example that results in a 404 raises an error.

Expected behaviour

I should be able to opt into having a 404 response returned. In Controller Specs I can call render_views to achieve this behaviour.

Can you provide an example app?

I can if needed.

Most helpful comment

Here's a workaround we implemented a couple months ago:

RSpec.describe 'Customizing errors', type: :request do
  it 'allows a 404 error page to be customized' do
    without_detailed_exceptions do
      get '/nonexsistent-route'
    end

    expect(response).to have_http_status(:not_found)
    expect(response.body).to include("The page you were looking for doesn't exist.")
  end
end

spec/support/without_detailed_exceptions.rb:

module WithoutDetailedExceptions
  RSpec.configure do |config|
    config.include self, type: :request
  end

  def 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

All 9 comments

Here's a workaround we implemented a couple months ago:

RSpec.describe 'Customizing errors', type: :request do
  it 'allows a 404 error page to be customized' do
    without_detailed_exceptions do
      get '/nonexsistent-route'
    end

    expect(response).to have_http_status(:not_found)
    expect(response.body).to include("The page you were looking for doesn't exist.")
  end
end

spec/support/without_detailed_exceptions.rb:

module WithoutDetailedExceptions
  RSpec.configure do |config|
    config.include self, type: :request
  end

  def 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

As @mikegee's patch shows, this is a Rails behaviour, and not one which is easily controlled, personally I feel this shouldn't be tested unless its invocation is controlled by code you own, (you can always check for the error if you're raising the error of course).

Here's an example of some behaviour we want to test:

  • I'm running an API, and a resource has a customizable slug
  • My app does a HEAD request to /my_resource/:slug
  • If the response is 404, I can go ahead and PUT with this slug. If not, warn the app that this isn't safe.

The above is a real world scenario I'm trying to write with a request spec.

If your intent is to write an end-to-end test, have you considered writing feature, or system level tests, which should enable this sort of assertion without tinkering with Rails innards, or asserting on the error raised and trusting Rails will turn that into a 404?

That could work. I have to admit I find the delineation between request and feature specs to be confusing. They more or less look the same. Would you be able to offer some guidance on the matter?

Request specs are Rails blessed replacement for controller specs, they are "full stack" through the controller middleware stack, but are still internal to Rails.

Feature specs are full stack through rack and use capybara (which is rack-test dressed up) to accomplish a similar goal, but from outside Rails.

Stupid follow up question: if you had a Rails API project with a huge suite of controller specs, and you knew that you needed to migrate away from these, would you migrate to feature or request specs?

If you were happy with controller specs I'd move them to request specs, you just might have the odd oddity caused by Rails behaviour such as this, I think you can force Rails to not render errors in test mode which might help...

Thank you very much for the feedback.

I think I have enough here to see that this issue should be closed as WILLNOTFIX per the alternatives presented.

Was this page helpful?
0 / 5 - 0 ratings