diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index b93ae8f8ff7cb528c01429d24eed4bc998b302ff..575c01ddfd00b6a4d736ec37a31691f6f7da6124 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,3 +1,7 @@ +* Provide the name of HTTP Status code in assertions. + + *Sean Collins* + * More explicit error message when running `rake routes`. `CONTROLLER` argument can now be supplied in different ways: `Rails::WelcomeController`, `Rails::Welcome`, `rails/welcome` diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb index 7bc6575ccd02f13ee02353ced1bab572d74e675f..1e4df07d6e66da9bccee7c4fd06fc042597b6bb3 100644 --- a/actionpack/lib/action_dispatch.rb +++ b/actionpack/lib/action_dispatch.rb @@ -95,6 +95,7 @@ module Session autoload :TestProcess autoload :TestRequest autoload :TestResponse + autoload :AssertionResponse end end diff --git a/actionpack/lib/action_dispatch/testing/assertion_response.rb b/actionpack/lib/action_dispatch/testing/assertion_response.rb new file mode 100644 index 0000000000000000000000000000000000000000..3fb81ff083025680f8350416737748bbff3fa199 --- /dev/null +++ b/actionpack/lib/action_dispatch/testing/assertion_response.rb @@ -0,0 +1,49 @@ +module ActionDispatch + # This is a class that abstracts away an asserted response. + # It purposely does not inherit from Response, because it doesn't need it. + # That means it does not have headers or a body. + # + # As an input to the initializer, we take a Fixnum, a String, or a Symbol. + # If it's a Fixnum or String, we figure out what its symbolized name. + # If it's a Symbol, we figure out what its corresponding code is. + # The resulting code will be a Fixnum, for real HTTP codes, and it will + # be a String for the pseudo-HTTP codes, such as: + # :success, :missing, :redirect and :error + class AssertionResponse + attr_reader :code, :name + + GENERIC_RESPONSE_CODES = { # :nodoc: + success: "2XX", + missing: "404", + redirect: "3XX", + error: "5XX" + } + + def initialize(code_or_name) + if code_or_name.is_a?(Symbol) + @name = code_or_name + @code = code_from_name(code_or_name) + else + @name = name_from_code(code_or_name) + @code = code_or_name + end + + raise ArgumentError, "Invalid response name: #{name}" if @code.nil? + raise ArgumentError, "Invalid response code: #{code}" if @name.nil? + end + + def code_and_name + "#{code}: #{name}" + end + + private + + def code_from_name(name) + GENERIC_RESPONSE_CODES[name] || Rack::Utils::SYMBOL_TO_STATUS_CODE[name] + end + + def name_from_code(code) + GENERIC_RESPONSE_CODES.invert[code] || Rack::Utils::HTTP_STATUS_CODES[code] + end + end +end diff --git a/actionpack/lib/action_dispatch/testing/assertions/response.rb b/actionpack/lib/action_dispatch/testing/assertions/response.rb index c138660a2162fd1c600b73894459b3411111e6c0..cd55b7d9757db0c8771c51adc48a3788a6f6ca66 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/response.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/response.rb @@ -1,4 +1,3 @@ - module ActionDispatch module Assertions # A small suite of assertions that test responses from \Rails applications. @@ -29,18 +28,10 @@ module ResponseAssertions def assert_response(type, message = nil) message ||= generate_response_message(type) - if Symbol === type - if [:success, :missing, :redirect, :error].include?(type) - assert @response.send(RESPONSE_PREDICATES[type]), message - else - code = Rack::Utils::SYMBOL_TO_STATUS_CODE[type] - if code.nil? - raise ArgumentError, "Invalid response type :#{type}" - end - assert_equal code, @response.response_code, message - end + if RESPONSE_PREDICATES.keys.include?(type) + assert @response.send(RESPONSE_PREDICATES[type]), message else - assert_equal type, @response.response_code, message + assert_equal AssertionResponse.new(type).code, @response.response_code, message end end @@ -85,8 +76,9 @@ def normalize_argument_to_redirection(fragment) end end - def generate_response_message(type, code = @response.response_code) - "Expected response to be a <#{type}>, but was a <#{code}>" + def generate_response_message(expected, actual = @response.response_code) + "Expected response to be a <#{code_with_name(expected)}>,"\ + " but was a <#{code_with_name(actual)}>" .concat location_if_redirected end @@ -95,6 +87,14 @@ def location_if_redirected location = normalize_argument_to_redirection(@response.location) " redirect to <#{location}>" end + + def code_with_name(code_or_name) + if RESPONSE_PREDICATES.values.include?("#{code_or_name}?".to_sym) + code_or_name = RESPONSE_PREDICATES.invert["#{code_or_name}?".to_sym] + end + + AssertionResponse.new(code_or_name).code_and_name + end end end end diff --git a/actionpack/test/assertions/response_assertions_test.rb b/actionpack/test/assertions/response_assertions_test.rb index 841fa6aaad863ad73470d991cdf9a8a345de2110..579ce0ed2994a1a7e362e4a922a9fa99b8508a26 100644 --- a/actionpack/test/assertions/response_assertions_test.rb +++ b/actionpack/test/assertions/response_assertions_test.rb @@ -74,7 +74,18 @@ def test_error_message_shows_404_when_404_asserted_for_success @response.status = 404 error = assert_raises(Minitest::Assertion) { assert_response :success } - expected = "Expected response to be a , but was a <404>" + expected = "Expected response to be a <2XX: success>,"\ + " but was a <404: Not Found>" + assert_match expected, error.message + end + + def test_error_message_shows_404_when_asserted_for_200 + @response = ActionDispatch::Response.new + @response.status = 404 + + error = assert_raises(Minitest::Assertion) { assert_response 200 } + expected = "Expected response to be a <200: OK>,"\ + " but was a <404: Not Found>" assert_match expected, error.message end @@ -84,7 +95,8 @@ def test_error_message_shows_302_redirect_when_302_asserted_for_success @response.location = 'http://test.host/posts/redirect/1' error = assert_raises(Minitest::Assertion) { assert_response :success } - expected = "Expected response to be a , but was a <302>" \ + expected = "Expected response to be a <2XX: success>,"\ + " but was a <302: Found>" \ " redirect to " assert_match expected, error.message end @@ -95,7 +107,8 @@ def test_error_message_shows_302_redirect_when_302_asserted_for_301 @response.location = 'http://test.host/posts/redirect/2' error = assert_raises(Minitest::Assertion) { assert_response 301 } - expected = "Expected response to be a <301>, but was a <302>" \ + expected = "Expected response to be a <301: Moved Permanently>,"\ + " but was a <302: Found>" \ " redirect to " assert_match expected, error.message end