Behaviors in Action Controller's raising error has been changed in 7.1

I found that AbstractController::ActionNotFound and ActionController::MissingExactTemplate have been changed to Expected response to be a ... in 7.1.

This can be reproduced with the Rails Tutorial chapter 3 " 3.3Getting started with testing":

# test/controllers/static_pages_controller_test.rb
  ...
  test "should get about" do
    get static_pages_about_url
    assert_response :success
  end
  • When adding the test above, Rails 7.0.8 behaves as follows:
$ bin/rails test
...
StaticPagesControllerTest#test_should_get_about:
AbstractController::ActionNotFound: The action 'about' could not be found for StaticPagesController
    test/controllers/static_pages_controller_test.rb:16:in `block in <class:StaticPagesControllerTest>'
...

This indicates that an action is missing.

  • When adding a route get "static_pages/about", 7.0.8 behaves as follows:
$ bin/rails test
...
Error:
StaticPagesControllerTest#test_should_get_about:
ActionController::MissingExactTemplate: StaticPagesController#about is missing a template for request formats: text/html
    test/controllers/static_pages_controller_test.rb:16:in `block in <class:StaticPagesControllerTest>'
...

This indicates that a corresponding template is missing.

Those behaviors of 7.0.8 above match the Tutorial.

But in 7.1.1, the behaviors are as follows, respectively:

$ rails test
...
  1) Failure:
StaticPagesControllerTest#test_should_get_about [/Users/hachi8833/deve/yasslab/environment/sample_app/test/controllers/static_pages_controller_test.rb:17]:
Expected response to be a <2XX: success>, but was a <404: Not Found>
rails test
...
  1) Failure:
StaticPagesControllerTest#test_should_get_about [/Users/hachi8833/deve/yasslab/environment/sample_app/test/controllers/static_pages_controller_test.rb:17]:
Expected response to be a <2XX: success>, but was a <406: Not Acceptable>
...

I’m unsure what made the changes and whether it is an expected or not, but it seems inappropriate in the cases.

I was looking into this too, and it appears to be due to this default config change in config/environments/test.rb:

config.action_dispatch.show_exceptions = :rescuable

It used to be that you could only set this to true or false, but now it’s :all, :rescuable, :none (:all = former true, :none = former false).

The setting is a bit confusing, but I think it means that it will “show exceptions” (aka render them as an error response) instead of raising them.

This is confusing in development env, because there “raising exception” actually means showing the convenient exception debug screen, and “showing exception” means rendering the public exception response, that doesn’t reveal any details.

The setting makes a bit more sense in the context of test env. Setting :rescuable makes it so that exceptions that are configured to be rescued will be shown (aka rendered as a response) instead of raised right in your test. This makes tests work a bit more correctly, because you’re supposed to be pretending to be the client visiting the url, and checking that the response is the expected error response. Not that your test is interrupted by a raised error.

However, the errors that are not rescuable, the ones unhandled by Rails or your own rescue_from (basically the ones that would normally produce error 500 for the client) would still be raised directly in your test, so you can immediately see what the error is. If you want them all to be rendered, then you could set show_exceptions to :all. If you want old behavior (that works with assert_raises), you should set it to :none.

This is my current understanding, please correct me if I’m wrong.

1 Like

Thank you for the clarifying this! I got Make the test environment show rescuable exceptions in responses by jdufresne · Pull Request #45867 · rails/rails · GitHub made the change. I confirmed that changing this :none certainly revived the previous behavior.

I guess that this is a small but still a breaking change that might affect failing tests in controllers. The affects might be smaller because it is rare to write failing tests in controllers, but the current test messages are less informative and might affect writing tests, especially in TDD.