actionpack 5.2.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionpack might be problematic. Click here for more details.

Files changed (170) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +429 -0
  3. data/MIT-LICENSE +21 -0
  4. data/README.rdoc +57 -0
  5. data/lib/abstract_controller.rb +27 -0
  6. data/lib/abstract_controller/asset_paths.rb +12 -0
  7. data/lib/abstract_controller/base.rb +265 -0
  8. data/lib/abstract_controller/caching.rb +66 -0
  9. data/lib/abstract_controller/caching/fragments.rb +166 -0
  10. data/lib/abstract_controller/callbacks.rb +212 -0
  11. data/lib/abstract_controller/collector.rb +43 -0
  12. data/lib/abstract_controller/error.rb +6 -0
  13. data/lib/abstract_controller/helpers.rb +194 -0
  14. data/lib/abstract_controller/logger.rb +14 -0
  15. data/lib/abstract_controller/railties/routes_helpers.rb +20 -0
  16. data/lib/abstract_controller/rendering.rb +127 -0
  17. data/lib/abstract_controller/translation.rb +31 -0
  18. data/lib/abstract_controller/url_for.rb +35 -0
  19. data/lib/action_controller.rb +66 -0
  20. data/lib/action_controller/api.rb +149 -0
  21. data/lib/action_controller/api/api_rendering.rb +16 -0
  22. data/lib/action_controller/base.rb +276 -0
  23. data/lib/action_controller/caching.rb +46 -0
  24. data/lib/action_controller/form_builder.rb +50 -0
  25. data/lib/action_controller/log_subscriber.rb +78 -0
  26. data/lib/action_controller/metal.rb +256 -0
  27. data/lib/action_controller/metal/basic_implicit_render.rb +13 -0
  28. data/lib/action_controller/metal/conditional_get.rb +274 -0
  29. data/lib/action_controller/metal/content_security_policy.rb +52 -0
  30. data/lib/action_controller/metal/cookies.rb +16 -0
  31. data/lib/action_controller/metal/data_streaming.rb +152 -0
  32. data/lib/action_controller/metal/etag_with_flash.rb +18 -0
  33. data/lib/action_controller/metal/etag_with_template_digest.rb +57 -0
  34. data/lib/action_controller/metal/exceptions.rb +53 -0
  35. data/lib/action_controller/metal/flash.rb +61 -0
  36. data/lib/action_controller/metal/force_ssl.rb +99 -0
  37. data/lib/action_controller/metal/head.rb +60 -0
  38. data/lib/action_controller/metal/helpers.rb +123 -0
  39. data/lib/action_controller/metal/http_authentication.rb +519 -0
  40. data/lib/action_controller/metal/implicit_render.rb +73 -0
  41. data/lib/action_controller/metal/instrumentation.rb +107 -0
  42. data/lib/action_controller/metal/live.rb +312 -0
  43. data/lib/action_controller/metal/mime_responds.rb +313 -0
  44. data/lib/action_controller/metal/parameter_encoding.rb +51 -0
  45. data/lib/action_controller/metal/params_wrapper.rb +293 -0
  46. data/lib/action_controller/metal/redirecting.rb +133 -0
  47. data/lib/action_controller/metal/renderers.rb +181 -0
  48. data/lib/action_controller/metal/rendering.rb +122 -0
  49. data/lib/action_controller/metal/request_forgery_protection.rb +445 -0
  50. data/lib/action_controller/metal/rescue.rb +28 -0
  51. data/lib/action_controller/metal/streaming.rb +223 -0
  52. data/lib/action_controller/metal/strong_parameters.rb +1086 -0
  53. data/lib/action_controller/metal/testing.rb +16 -0
  54. data/lib/action_controller/metal/url_for.rb +58 -0
  55. data/lib/action_controller/railtie.rb +89 -0
  56. data/lib/action_controller/railties/helpers.rb +24 -0
  57. data/lib/action_controller/renderer.rb +117 -0
  58. data/lib/action_controller/template_assertions.rb +11 -0
  59. data/lib/action_controller/test_case.rb +629 -0
  60. data/lib/action_dispatch.rb +112 -0
  61. data/lib/action_dispatch/http/cache.rb +222 -0
  62. data/lib/action_dispatch/http/content_security_policy.rb +272 -0
  63. data/lib/action_dispatch/http/filter_parameters.rb +84 -0
  64. data/lib/action_dispatch/http/filter_redirect.rb +37 -0
  65. data/lib/action_dispatch/http/headers.rb +132 -0
  66. data/lib/action_dispatch/http/mime_negotiation.rb +175 -0
  67. data/lib/action_dispatch/http/mime_type.rb +342 -0
  68. data/lib/action_dispatch/http/mime_types.rb +50 -0
  69. data/lib/action_dispatch/http/parameter_filter.rb +86 -0
  70. data/lib/action_dispatch/http/parameters.rb +126 -0
  71. data/lib/action_dispatch/http/rack_cache.rb +63 -0
  72. data/lib/action_dispatch/http/request.rb +430 -0
  73. data/lib/action_dispatch/http/response.rb +519 -0
  74. data/lib/action_dispatch/http/upload.rb +84 -0
  75. data/lib/action_dispatch/http/url.rb +350 -0
  76. data/lib/action_dispatch/journey.rb +7 -0
  77. data/lib/action_dispatch/journey/formatter.rb +189 -0
  78. data/lib/action_dispatch/journey/gtg/builder.rb +164 -0
  79. data/lib/action_dispatch/journey/gtg/simulator.rb +41 -0
  80. data/lib/action_dispatch/journey/gtg/transition_table.rb +158 -0
  81. data/lib/action_dispatch/journey/nfa/builder.rb +78 -0
  82. data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
  83. data/lib/action_dispatch/journey/nfa/simulator.rb +49 -0
  84. data/lib/action_dispatch/journey/nfa/transition_table.rb +120 -0
  85. data/lib/action_dispatch/journey/nodes/node.rb +140 -0
  86. data/lib/action_dispatch/journey/parser.rb +199 -0
  87. data/lib/action_dispatch/journey/parser.y +50 -0
  88. data/lib/action_dispatch/journey/parser_extras.rb +31 -0
  89. data/lib/action_dispatch/journey/path/pattern.rb +198 -0
  90. data/lib/action_dispatch/journey/route.rb +203 -0
  91. data/lib/action_dispatch/journey/router.rb +156 -0
  92. data/lib/action_dispatch/journey/router/utils.rb +102 -0
  93. data/lib/action_dispatch/journey/routes.rb +82 -0
  94. data/lib/action_dispatch/journey/scanner.rb +64 -0
  95. data/lib/action_dispatch/journey/visitors.rb +268 -0
  96. data/lib/action_dispatch/journey/visualizer/fsm.css +30 -0
  97. data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
  98. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  99. data/lib/action_dispatch/middleware/callbacks.rb +36 -0
  100. data/lib/action_dispatch/middleware/cookies.rb +685 -0
  101. data/lib/action_dispatch/middleware/debug_exceptions.rb +205 -0
  102. data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
  103. data/lib/action_dispatch/middleware/exception_wrapper.rb +147 -0
  104. data/lib/action_dispatch/middleware/executor.rb +21 -0
  105. data/lib/action_dispatch/middleware/flash.rb +300 -0
  106. data/lib/action_dispatch/middleware/public_exceptions.rb +57 -0
  107. data/lib/action_dispatch/middleware/reloader.rb +12 -0
  108. data/lib/action_dispatch/middleware/remote_ip.rb +183 -0
  109. data/lib/action_dispatch/middleware/request_id.rb +43 -0
  110. data/lib/action_dispatch/middleware/session/abstract_store.rb +92 -0
  111. data/lib/action_dispatch/middleware/session/cache_store.rb +54 -0
  112. data/lib/action_dispatch/middleware/session/cookie_store.rb +118 -0
  113. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +28 -0
  114. data/lib/action_dispatch/middleware/show_exceptions.rb +62 -0
  115. data/lib/action_dispatch/middleware/ssl.rb +150 -0
  116. data/lib/action_dispatch/middleware/stack.rb +116 -0
  117. data/lib/action_dispatch/middleware/static.rb +130 -0
  118. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +22 -0
  119. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
  120. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +27 -0
  121. data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
  122. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +52 -0
  123. data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
  124. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +16 -0
  125. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
  126. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +21 -0
  127. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +13 -0
  128. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +161 -0
  129. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
  130. data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
  131. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +32 -0
  132. data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
  133. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
  134. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
  135. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +6 -0
  136. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
  137. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
  138. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +200 -0
  139. data/lib/action_dispatch/railtie.rb +55 -0
  140. data/lib/action_dispatch/request/session.rb +234 -0
  141. data/lib/action_dispatch/request/utils.rb +78 -0
  142. data/lib/action_dispatch/routing.rb +260 -0
  143. data/lib/action_dispatch/routing/endpoint.rb +17 -0
  144. data/lib/action_dispatch/routing/inspector.rb +225 -0
  145. data/lib/action_dispatch/routing/mapper.rb +2267 -0
  146. data/lib/action_dispatch/routing/polymorphic_routes.rb +352 -0
  147. data/lib/action_dispatch/routing/redirection.rb +201 -0
  148. data/lib/action_dispatch/routing/route_set.rb +890 -0
  149. data/lib/action_dispatch/routing/routes_proxy.rb +69 -0
  150. data/lib/action_dispatch/routing/url_for.rb +236 -0
  151. data/lib/action_dispatch/system_test_case.rb +147 -0
  152. data/lib/action_dispatch/system_testing/browser.rb +49 -0
  153. data/lib/action_dispatch/system_testing/driver.rb +59 -0
  154. data/lib/action_dispatch/system_testing/server.rb +31 -0
  155. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +96 -0
  156. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +31 -0
  157. data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +26 -0
  158. data/lib/action_dispatch/testing/assertion_response.rb +47 -0
  159. data/lib/action_dispatch/testing/assertions.rb +24 -0
  160. data/lib/action_dispatch/testing/assertions/response.rb +107 -0
  161. data/lib/action_dispatch/testing/assertions/routing.rb +222 -0
  162. data/lib/action_dispatch/testing/integration.rb +652 -0
  163. data/lib/action_dispatch/testing/request_encoder.rb +55 -0
  164. data/lib/action_dispatch/testing/test_process.rb +50 -0
  165. data/lib/action_dispatch/testing/test_request.rb +71 -0
  166. data/lib/action_dispatch/testing/test_response.rb +53 -0
  167. data/lib/action_pack.rb +26 -0
  168. data/lib/action_pack/gem_version.rb +17 -0
  169. data/lib/action_pack/version.rb +10 -0
  170. metadata +318 -0
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionDispatch
4
+ module SystemTesting
5
+ class Browser # :nodoc:
6
+ attr_reader :name
7
+
8
+ def initialize(name)
9
+ @name = name
10
+ end
11
+
12
+ def type
13
+ case name
14
+ when :headless_chrome
15
+ :chrome
16
+ when :headless_firefox
17
+ :firefox
18
+ else
19
+ name
20
+ end
21
+ end
22
+
23
+ def options
24
+ case name
25
+ when :headless_chrome
26
+ headless_chrome_browser_options
27
+ when :headless_firefox
28
+ headless_firefox_browser_options
29
+ end
30
+ end
31
+
32
+ private
33
+ def headless_chrome_browser_options
34
+ options = Selenium::WebDriver::Chrome::Options.new
35
+ options.args << "--headless"
36
+ options.args << "--disable-gpu" if Gem.win_platform?
37
+
38
+ options
39
+ end
40
+
41
+ def headless_firefox_browser_options
42
+ options = Selenium::WebDriver::Firefox::Options.new
43
+ options.args << "-headless"
44
+
45
+ options
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionDispatch
4
+ module SystemTesting
5
+ class Driver # :nodoc:
6
+ def initialize(name, **options)
7
+ @name = name
8
+ @browser = Browser.new(options[:using])
9
+ @screen_size = options[:screen_size]
10
+ @options = options[:options]
11
+ end
12
+
13
+ def use
14
+ register if registerable?
15
+
16
+ setup
17
+ end
18
+
19
+ private
20
+ def registerable?
21
+ [:selenium, :poltergeist, :webkit].include?(@name)
22
+ end
23
+
24
+ def register
25
+ Capybara.register_driver @name do |app|
26
+ case @name
27
+ when :selenium then register_selenium(app)
28
+ when :poltergeist then register_poltergeist(app)
29
+ when :webkit then register_webkit(app)
30
+ end
31
+ end
32
+ end
33
+
34
+ def browser_options
35
+ @options.merge(options: @browser.options).compact
36
+ end
37
+
38
+ def register_selenium(app)
39
+ Capybara::Selenium::Driver.new(app, { browser: @browser.type }.merge(browser_options)).tap do |driver|
40
+ driver.browser.manage.window.size = Selenium::WebDriver::Dimension.new(*@screen_size)
41
+ end
42
+ end
43
+
44
+ def register_poltergeist(app)
45
+ Capybara::Poltergeist::Driver.new(app, @options.merge(window_size: @screen_size))
46
+ end
47
+
48
+ def register_webkit(app)
49
+ Capybara::Webkit::Driver.new(app, Capybara::Webkit::Configuration.to_hash.merge(@options)).tap do |driver|
50
+ driver.resize_window_to(driver.current_window_handle, *@screen_size)
51
+ end
52
+ end
53
+
54
+ def setup
55
+ Capybara.current_driver = @name
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionDispatch
4
+ module SystemTesting
5
+ class Server # :nodoc:
6
+ class << self
7
+ attr_accessor :silence_puma
8
+ end
9
+
10
+ self.silence_puma = false
11
+
12
+ def run
13
+ setup
14
+ end
15
+
16
+ private
17
+ def setup
18
+ set_server
19
+ set_port
20
+ end
21
+
22
+ def set_server
23
+ Capybara.server = :puma, { Silent: self.class.silence_puma } if Capybara.server == Capybara.servers[:default]
24
+ end
25
+
26
+ def set_port
27
+ Capybara.always_include_port = true
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionDispatch
4
+ module SystemTesting
5
+ module TestHelpers
6
+ # Screenshot helper for system testing.
7
+ module ScreenshotHelper
8
+ # Takes a screenshot of the current page in the browser.
9
+ #
10
+ # +take_screenshot+ can be used at any point in your system tests to take
11
+ # a screenshot of the current state. This can be useful for debugging or
12
+ # automating visual testing.
13
+ #
14
+ # The screenshot will be displayed in your console, if supported.
15
+ #
16
+ # You can set the +RAILS_SYSTEM_TESTING_SCREENSHOT+ environment variable to
17
+ # control the output. Possible values are:
18
+ # * [+simple+ (default)] Only displays the screenshot path.
19
+ # This is the default value.
20
+ # * [+inline+] Display the screenshot in the terminal using the
21
+ # iTerm image protocol (https://iterm2.com/documentation-images.html).
22
+ # * [+artifact+] Display the screenshot in the terminal, using the terminal
23
+ # artifact format (https://buildkite.github.io/terminal/inline-images/).
24
+ def take_screenshot
25
+ save_image
26
+ puts display_image
27
+ end
28
+
29
+ # Takes a screenshot of the current page in the browser if the test
30
+ # failed.
31
+ #
32
+ # +take_failed_screenshot+ is included in <tt>application_system_test_case.rb</tt>
33
+ # that is generated with the application. To take screenshots when a test
34
+ # fails add +take_failed_screenshot+ to the teardown block before clearing
35
+ # sessions.
36
+ def take_failed_screenshot
37
+ take_screenshot if failed? && supports_screenshot?
38
+ end
39
+
40
+ private
41
+ def image_name
42
+ failed? ? "failures_#{method_name}" : method_name
43
+ end
44
+
45
+ def image_path
46
+ @image_path ||= absolute_image_path.relative_path_from(Pathname.pwd).to_s
47
+ end
48
+
49
+ def absolute_image_path
50
+ Rails.root.join("tmp/screenshots/#{image_name}.png")
51
+ end
52
+
53
+ def save_image
54
+ page.save_screenshot(absolute_image_path)
55
+ end
56
+
57
+ def output_type
58
+ # Environment variables have priority
59
+ output_type = ENV["RAILS_SYSTEM_TESTING_SCREENSHOT"] || ENV["CAPYBARA_INLINE_SCREENSHOT"]
60
+
61
+ # Default to outputting a path to the screenshot
62
+ output_type ||= "simple"
63
+
64
+ output_type
65
+ end
66
+
67
+ def display_image
68
+ message = "[Screenshot]: #{image_path}\n".dup
69
+
70
+ case output_type
71
+ when "artifact"
72
+ message << "\e]1338;url=artifact://#{absolute_image_path}\a\n"
73
+ when "inline"
74
+ name = inline_base64(File.basename(absolute_image_path))
75
+ image = inline_base64(File.read(absolute_image_path))
76
+ message << "\e]1337;File=name=#{name};height=400px;inline=1:#{image}\a\n"
77
+ end
78
+
79
+ message
80
+ end
81
+
82
+ def inline_base64(path)
83
+ Base64.encode64(path).gsub("\n", "")
84
+ end
85
+
86
+ def failed?
87
+ !passed? && !skipped?
88
+ end
89
+
90
+ def supports_screenshot?
91
+ Capybara.current_driver != :rack_test
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionDispatch
4
+ module SystemTesting
5
+ module TestHelpers
6
+ module SetupAndTeardown # :nodoc:
7
+ DEFAULT_HOST = "http://127.0.0.1"
8
+
9
+ def host!(host)
10
+ super
11
+ Capybara.app_host = host
12
+ end
13
+
14
+ def before_setup
15
+ host! DEFAULT_HOST
16
+ super
17
+ end
18
+
19
+ def after_teardown
20
+ begin
21
+ take_failed_screenshot
22
+ ensure
23
+ Capybara.reset_sessions!
24
+ end
25
+ ensure
26
+ super
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionDispatch
4
+ module SystemTesting
5
+ module TestHelpers
6
+ module UndefMethods # :nodoc:
7
+ extend ActiveSupport::Concern
8
+ included do
9
+ METHODS = %i(get post put patch delete).freeze
10
+
11
+ METHODS.each do |verb|
12
+ undef_method verb
13
+ end
14
+
15
+ def method_missing(method, *args, &block)
16
+ if METHODS.include?(method)
17
+ raise NoMethodError, "System tests cannot make direct requests via ##{method}; use #visit and #click_on instead. See http://www.rubydoc.info/github/teamcapybara/capybara/master#The_DSL for more information."
18
+ else
19
+ super
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionDispatch
4
+ # This is a class that abstracts away an asserted response. It purposely
5
+ # does not inherit from Response because it doesn't need it. That means it
6
+ # does not have headers or a body.
7
+ class AssertionResponse
8
+ attr_reader :code, :name
9
+
10
+ GENERIC_RESPONSE_CODES = { # :nodoc:
11
+ success: "2XX",
12
+ missing: "404",
13
+ redirect: "3XX",
14
+ error: "5XX"
15
+ }
16
+
17
+ # Accepts a specific response status code as an Integer (404) or String
18
+ # ('404') or a response status range as a Symbol pseudo-code (:success,
19
+ # indicating any 200-299 status code).
20
+ def initialize(code_or_name)
21
+ if code_or_name.is_a?(Symbol)
22
+ @name = code_or_name
23
+ @code = code_from_name(code_or_name)
24
+ else
25
+ @name = name_from_code(code_or_name)
26
+ @code = code_or_name
27
+ end
28
+
29
+ raise ArgumentError, "Invalid response name: #{name}" if @code.nil?
30
+ raise ArgumentError, "Invalid response code: #{code}" if @name.nil?
31
+ end
32
+
33
+ def code_and_name
34
+ "#{code}: #{name}"
35
+ end
36
+
37
+ private
38
+
39
+ def code_from_name(name)
40
+ GENERIC_RESPONSE_CODES[name] || Rack::Utils::SYMBOL_TO_STATUS_CODE[name]
41
+ end
42
+
43
+ def name_from_code(code)
44
+ GENERIC_RESPONSE_CODES.invert[code] || Rack::Utils::HTTP_STATUS_CODES[code]
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails-dom-testing"
4
+
5
+ module ActionDispatch
6
+ module Assertions
7
+ autoload :ResponseAssertions, "action_dispatch/testing/assertions/response"
8
+ autoload :RoutingAssertions, "action_dispatch/testing/assertions/routing"
9
+
10
+ extend ActiveSupport::Concern
11
+
12
+ include ResponseAssertions
13
+ include RoutingAssertions
14
+ include Rails::Dom::Testing::Assertions
15
+
16
+ def html_document
17
+ @html_document ||= if @response.content_type.to_s.end_with?("xml")
18
+ Nokogiri::XML::Document.parse(@response.body)
19
+ else
20
+ Nokogiri::HTML::Document.parse(@response.body)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionDispatch
4
+ module Assertions
5
+ # A small suite of assertions that test responses from \Rails applications.
6
+ module ResponseAssertions
7
+ RESPONSE_PREDICATES = { # :nodoc:
8
+ success: :successful?,
9
+ missing: :not_found?,
10
+ redirect: :redirection?,
11
+ error: :server_error?,
12
+ }
13
+
14
+ # Asserts that the response is one of the following types:
15
+ #
16
+ # * <tt>:success</tt> - Status code was in the 200-299 range
17
+ # * <tt>:redirect</tt> - Status code was in the 300-399 range
18
+ # * <tt>:missing</tt> - Status code was 404
19
+ # * <tt>:error</tt> - Status code was in the 500-599 range
20
+ #
21
+ # You can also pass an explicit status number like <tt>assert_response(501)</tt>
22
+ # or its symbolic equivalent <tt>assert_response(:not_implemented)</tt>.
23
+ # See Rack::Utils::SYMBOL_TO_STATUS_CODE for a full list.
24
+ #
25
+ # # Asserts that the response was a redirection
26
+ # assert_response :redirect
27
+ #
28
+ # # Asserts that the response code was status code 401 (unauthorized)
29
+ # assert_response 401
30
+ def assert_response(type, message = nil)
31
+ message ||= generate_response_message(type)
32
+
33
+ if RESPONSE_PREDICATES.keys.include?(type)
34
+ assert @response.send(RESPONSE_PREDICATES[type]), message
35
+ else
36
+ assert_equal AssertionResponse.new(type).code, @response.response_code, message
37
+ end
38
+ end
39
+
40
+ # Asserts that the redirection options passed in match those of the redirect called in the latest action.
41
+ # This match can be partial, such that <tt>assert_redirected_to(controller: "weblog")</tt> will also
42
+ # match the redirection of <tt>redirect_to(controller: "weblog", action: "show")</tt> and so on.
43
+ #
44
+ # # Asserts that the redirection was to the "index" action on the WeblogController
45
+ # assert_redirected_to controller: "weblog", action: "index"
46
+ #
47
+ # # Asserts that the redirection was to the named route login_url
48
+ # assert_redirected_to login_url
49
+ #
50
+ # # Asserts that the redirection was to the URL for @customer
51
+ # assert_redirected_to @customer
52
+ #
53
+ # # Asserts that the redirection matches the regular expression
54
+ # assert_redirected_to %r(\Ahttp://example.org)
55
+ def assert_redirected_to(options = {}, message = nil)
56
+ assert_response(:redirect, message)
57
+ return true if options === @response.location
58
+
59
+ redirect_is = normalize_argument_to_redirection(@response.location)
60
+ redirect_expected = normalize_argument_to_redirection(options)
61
+
62
+ message ||= "Expected response to be a redirect to <#{redirect_expected}> but was a redirect to <#{redirect_is}>"
63
+ assert_operator redirect_expected, :===, redirect_is, message
64
+ end
65
+
66
+ private
67
+ # Proxy to to_param if the object will respond to it.
68
+ def parameterize(value)
69
+ value.respond_to?(:to_param) ? value.to_param : value
70
+ end
71
+
72
+ def normalize_argument_to_redirection(fragment)
73
+ if Regexp === fragment
74
+ fragment
75
+ else
76
+ handle = @controller || ActionController::Redirecting
77
+ handle._compute_redirect_to_location(@request, fragment)
78
+ end
79
+ end
80
+
81
+ def generate_response_message(expected, actual = @response.response_code)
82
+ "Expected response to be a <#{code_with_name(expected)}>,"\
83
+ " but was a <#{code_with_name(actual)}>"
84
+ .dup.concat(location_if_redirected).concat(response_body_if_short)
85
+ end
86
+
87
+ def response_body_if_short
88
+ return "" if @response.body.size > 500
89
+ "\nResponse body: #{@response.body}"
90
+ end
91
+
92
+ def location_if_redirected
93
+ return "" unless @response.redirection? && @response.location.present?
94
+ location = normalize_argument_to_redirection(@response.location)
95
+ " redirect to <#{location}>"
96
+ end
97
+
98
+ def code_with_name(code_or_name)
99
+ if RESPONSE_PREDICATES.values.include?("#{code_or_name}?".to_sym)
100
+ code_or_name = RESPONSE_PREDICATES.invert["#{code_or_name}?".to_sym]
101
+ end
102
+
103
+ AssertionResponse.new(code_or_name).code_and_name
104
+ end
105
+ end
106
+ end
107
+ end