actionpack 7.1.3.4 → 7.2.0.beta1

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 (158) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +70 -541
  3. data/lib/abstract_controller/asset_paths.rb +2 -0
  4. data/lib/abstract_controller/base.rb +102 -98
  5. data/lib/abstract_controller/caching/fragments.rb +50 -53
  6. data/lib/abstract_controller/caching.rb +2 -0
  7. data/lib/abstract_controller/callbacks.rb +66 -64
  8. data/lib/abstract_controller/collector.rb +6 -6
  9. data/lib/abstract_controller/deprecator.rb +2 -0
  10. data/lib/abstract_controller/error.rb +2 -0
  11. data/lib/abstract_controller/helpers.rb +70 -85
  12. data/lib/abstract_controller/logger.rb +2 -0
  13. data/lib/abstract_controller/railties/routes_helpers.rb +2 -0
  14. data/lib/abstract_controller/rendering.rb +13 -12
  15. data/lib/abstract_controller/translation.rb +11 -10
  16. data/lib/abstract_controller/url_for.rb +8 -6
  17. data/lib/abstract_controller.rb +2 -0
  18. data/lib/action_controller/api/api_rendering.rb +2 -0
  19. data/lib/action_controller/api.rb +74 -72
  20. data/lib/action_controller/base.rb +155 -117
  21. data/lib/action_controller/caching.rb +15 -12
  22. data/lib/action_controller/deprecator.rb +2 -0
  23. data/lib/action_controller/form_builder.rb +20 -17
  24. data/lib/action_controller/log_subscriber.rb +3 -1
  25. data/lib/action_controller/metal/allow_browser.rb +119 -0
  26. data/lib/action_controller/metal/basic_implicit_render.rb +2 -0
  27. data/lib/action_controller/metal/conditional_get.rb +188 -174
  28. data/lib/action_controller/metal/content_security_policy.rb +25 -24
  29. data/lib/action_controller/metal/cookies.rb +4 -2
  30. data/lib/action_controller/metal/data_streaming.rb +64 -55
  31. data/lib/action_controller/metal/default_headers.rb +5 -3
  32. data/lib/action_controller/metal/etag_with_flash.rb +3 -1
  33. data/lib/action_controller/metal/etag_with_template_digest.rb +17 -15
  34. data/lib/action_controller/metal/exceptions.rb +11 -9
  35. data/lib/action_controller/metal/flash.rb +12 -10
  36. data/lib/action_controller/metal/head.rb +12 -10
  37. data/lib/action_controller/metal/helpers.rb +63 -55
  38. data/lib/action_controller/metal/http_authentication.rb +209 -201
  39. data/lib/action_controller/metal/implicit_render.rb +17 -15
  40. data/lib/action_controller/metal/instrumentation.rb +15 -12
  41. data/lib/action_controller/metal/live.rb +113 -107
  42. data/lib/action_controller/metal/logging.rb +6 -4
  43. data/lib/action_controller/metal/mime_responds.rb +151 -142
  44. data/lib/action_controller/metal/parameter_encoding.rb +34 -32
  45. data/lib/action_controller/metal/params_wrapper.rb +57 -59
  46. data/lib/action_controller/metal/permissions_policy.rb +13 -12
  47. data/lib/action_controller/metal/rate_limiting.rb +62 -0
  48. data/lib/action_controller/metal/redirecting.rb +108 -82
  49. data/lib/action_controller/metal/renderers.rb +50 -49
  50. data/lib/action_controller/metal/rendering.rb +103 -75
  51. data/lib/action_controller/metal/request_forgery_protection.rb +162 -133
  52. data/lib/action_controller/metal/rescue.rb +11 -9
  53. data/lib/action_controller/metal/streaming.rb +138 -136
  54. data/lib/action_controller/metal/strong_parameters.rb +525 -480
  55. data/lib/action_controller/metal/testing.rb +2 -0
  56. data/lib/action_controller/metal/url_for.rb +17 -15
  57. data/lib/action_controller/metal.rb +58 -57
  58. data/lib/action_controller/railtie.rb +3 -0
  59. data/lib/action_controller/railties/helpers.rb +2 -0
  60. data/lib/action_controller/renderer.rb +42 -36
  61. data/lib/action_controller/template_assertions.rb +4 -2
  62. data/lib/action_controller/test_case.rb +146 -126
  63. data/lib/action_controller.rb +10 -3
  64. data/lib/action_dispatch/constants.rb +2 -0
  65. data/lib/action_dispatch/deprecator.rb +2 -0
  66. data/lib/action_dispatch/http/cache.rb +27 -26
  67. data/lib/action_dispatch/http/content_disposition.rb +2 -0
  68. data/lib/action_dispatch/http/content_security_policy.rb +44 -38
  69. data/lib/action_dispatch/http/filter_parameters.rb +9 -5
  70. data/lib/action_dispatch/http/filter_redirect.rb +15 -1
  71. data/lib/action_dispatch/http/headers.rb +22 -22
  72. data/lib/action_dispatch/http/mime_negotiation.rb +30 -41
  73. data/lib/action_dispatch/http/mime_type.rb +29 -22
  74. data/lib/action_dispatch/http/mime_types.rb +2 -0
  75. data/lib/action_dispatch/http/parameters.rb +11 -9
  76. data/lib/action_dispatch/http/permissions_policy.rb +27 -37
  77. data/lib/action_dispatch/http/rack_cache.rb +2 -0
  78. data/lib/action_dispatch/http/request.rb +71 -71
  79. data/lib/action_dispatch/http/response.rb +61 -61
  80. data/lib/action_dispatch/http/upload.rb +18 -16
  81. data/lib/action_dispatch/http/url.rb +75 -73
  82. data/lib/action_dispatch/journey/formatter.rb +13 -6
  83. data/lib/action_dispatch/journey/gtg/builder.rb +4 -3
  84. data/lib/action_dispatch/journey/gtg/simulator.rb +2 -0
  85. data/lib/action_dispatch/journey/gtg/transition_table.rb +10 -8
  86. data/lib/action_dispatch/journey/nfa/dot.rb +2 -0
  87. data/lib/action_dispatch/journey/nodes/node.rb +6 -5
  88. data/lib/action_dispatch/journey/parser.rb +4 -3
  89. data/lib/action_dispatch/journey/parser_extras.rb +2 -0
  90. data/lib/action_dispatch/journey/path/pattern.rb +4 -1
  91. data/lib/action_dispatch/journey/route.rb +9 -7
  92. data/lib/action_dispatch/journey/router/utils.rb +16 -15
  93. data/lib/action_dispatch/journey/router.rb +4 -2
  94. data/lib/action_dispatch/journey/routes.rb +4 -2
  95. data/lib/action_dispatch/journey/scanner.rb +4 -2
  96. data/lib/action_dispatch/journey/visitors.rb +2 -0
  97. data/lib/action_dispatch/journey.rb +2 -0
  98. data/lib/action_dispatch/log_subscriber.rb +2 -0
  99. data/lib/action_dispatch/middleware/actionable_exceptions.rb +2 -0
  100. data/lib/action_dispatch/middleware/assume_ssl.rb +8 -5
  101. data/lib/action_dispatch/middleware/callbacks.rb +3 -1
  102. data/lib/action_dispatch/middleware/cookies.rb +119 -104
  103. data/lib/action_dispatch/middleware/debug_exceptions.rb +13 -5
  104. data/lib/action_dispatch/middleware/debug_locks.rb +15 -13
  105. data/lib/action_dispatch/middleware/debug_view.rb +2 -0
  106. data/lib/action_dispatch/middleware/exception_wrapper.rb +6 -11
  107. data/lib/action_dispatch/middleware/executor.rb +8 -0
  108. data/lib/action_dispatch/middleware/flash.rb +63 -51
  109. data/lib/action_dispatch/middleware/host_authorization.rb +17 -15
  110. data/lib/action_dispatch/middleware/public_exceptions.rb +8 -6
  111. data/lib/action_dispatch/middleware/reloader.rb +5 -3
  112. data/lib/action_dispatch/middleware/remote_ip.rb +77 -72
  113. data/lib/action_dispatch/middleware/request_id.rb +14 -9
  114. data/lib/action_dispatch/middleware/server_timing.rb +4 -2
  115. data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -0
  116. data/lib/action_dispatch/middleware/session/cache_store.rb +13 -8
  117. data/lib/action_dispatch/middleware/session/cookie_store.rb +27 -26
  118. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +7 -3
  119. data/lib/action_dispatch/middleware/show_exceptions.rb +31 -21
  120. data/lib/action_dispatch/middleware/ssl.rb +43 -40
  121. data/lib/action_dispatch/middleware/stack.rb +11 -10
  122. data/lib/action_dispatch/middleware/static.rb +33 -31
  123. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +1 -1
  124. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +1 -1
  125. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +1 -1
  126. data/lib/action_dispatch/railtie.rb +2 -4
  127. data/lib/action_dispatch/request/session.rb +23 -21
  128. data/lib/action_dispatch/request/utils.rb +2 -0
  129. data/lib/action_dispatch/routing/endpoint.rb +2 -0
  130. data/lib/action_dispatch/routing/inspector.rb +5 -3
  131. data/lib/action_dispatch/routing/mapper.rb +670 -635
  132. data/lib/action_dispatch/routing/polymorphic_routes.rb +69 -62
  133. data/lib/action_dispatch/routing/redirection.rb +37 -32
  134. data/lib/action_dispatch/routing/route_set.rb +59 -45
  135. data/lib/action_dispatch/routing/routes_proxy.rb +6 -4
  136. data/lib/action_dispatch/routing/url_for.rb +130 -125
  137. data/lib/action_dispatch/routing.rb +150 -148
  138. data/lib/action_dispatch/system_test_case.rb +91 -81
  139. data/lib/action_dispatch/system_testing/browser.rb +10 -3
  140. data/lib/action_dispatch/system_testing/driver.rb +3 -1
  141. data/lib/action_dispatch/system_testing/server.rb +2 -0
  142. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +32 -21
  143. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +2 -0
  144. data/lib/action_dispatch/testing/assertion_response.rb +8 -6
  145. data/lib/action_dispatch/testing/assertions/response.rb +26 -23
  146. data/lib/action_dispatch/testing/assertions/routing.rb +153 -84
  147. data/lib/action_dispatch/testing/assertions.rb +2 -0
  148. data/lib/action_dispatch/testing/integration.rb +223 -222
  149. data/lib/action_dispatch/testing/request_encoder.rb +2 -0
  150. data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
  151. data/lib/action_dispatch/testing/test_process.rb +12 -8
  152. data/lib/action_dispatch/testing/test_request.rb +3 -1
  153. data/lib/action_dispatch/testing/test_response.rb +27 -26
  154. data/lib/action_dispatch.rb +22 -28
  155. data/lib/action_pack/gem_version.rb +6 -4
  156. data/lib/action_pack/version.rb +3 -1
  157. data/lib/action_pack.rb +17 -16
  158. metadata +30 -13
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionDispatch
4
6
  module SystemTesting
5
7
  class Browser # :nodoc:
@@ -35,8 +37,8 @@ module ActionDispatch
35
37
  yield options if block_given?
36
38
  end
37
39
 
38
- # driver_path is lazily initialized by default. Eagerly set it to
39
- # avoid race conditions when using parallel tests.
40
+ # driver_path is lazily initialized by default. Eagerly set it to avoid race
41
+ # conditions when using parallel tests.
40
42
  def preload
41
43
  case type
42
44
  when :chrome
@@ -70,7 +72,12 @@ module ActionDispatch
70
72
  end
71
73
 
72
74
  def resolve_driver_path(namespace)
73
- namespace::Service.driver_path = ::Selenium::WebDriver::DriverFinder.path(options, namespace::Service)
75
+ # The path method has been deprecated in 4.20.0
76
+ if Gem::Version.new(::Selenium::WebDriver::VERSION) >= Gem::Version.new("4.20.0")
77
+ namespace::Service.driver_path = ::Selenium::WebDriver::DriverFinder.new(options, namespace::Service.new).driver_path
78
+ else
79
+ namespace::Service.driver_path = ::Selenium::WebDriver::DriverFinder.path(options, namespace::Service)
80
+ end
74
81
  end
75
82
  end
76
83
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionDispatch
4
6
  module SystemTesting
5
7
  class Driver # :nodoc:
@@ -16,7 +18,7 @@ module ActionDispatch
16
18
  gem "selenium-webdriver", ">= 4.0.0"
17
19
  require "selenium/webdriver"
18
20
  @browser = Browser.new(options[:using])
19
- @browser.preload
21
+ @browser.preload unless @options[:browser] == :remote
20
22
  else
21
23
  @browser = nil
22
24
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionDispatch
4
6
  module SystemTesting
5
7
  class Server # :nodoc:
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionDispatch
4
6
  module SystemTesting
5
7
  module TestHelpers
@@ -7,27 +9,35 @@ module ActionDispatch
7
9
  module ScreenshotHelper
8
10
  # Takes a screenshot of the current page in the browser.
9
11
  #
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. You can take multiple screenshots per test
13
- # to investigate changes at different points during your test. These will be
14
- # named with a sequential prefix (or 'failed' for failing tests)
12
+ # `take_screenshot` can be used at any point in your system tests to take a
13
+ # screenshot of the current state. This can be useful for debugging or
14
+ # automating visual testing. You can take multiple screenshots per test to
15
+ # investigate changes at different points during your test. These will be named
16
+ # with a sequential prefix (or 'failed' for failing tests)
17
+ #
18
+ # The default screenshots directory is `tmp/screenshots` but you can set a
19
+ # different one with `Capybara.save_path`
20
+ #
21
+ # You can use the `html` argument or set the
22
+ # `RAILS_SYSTEM_TESTING_SCREENSHOT_HTML` environment variable to save the HTML
23
+ # from the page that is being screenshotted so you can investigate the elements
24
+ # on the page at the time of the screenshot
25
+ #
26
+ # You can use the `screenshot` argument or set the
27
+ # `RAILS_SYSTEM_TESTING_SCREENSHOT` environment variable to control the output.
28
+ # Possible values are:
29
+ # `simple` (default)
30
+ # : Only displays the screenshot path. This is the default value.
31
+ #
32
+ # `inline`
33
+ # : Display the screenshot in the terminal using the iTerm image protocol
34
+ # (https://iterm2.com/documentation-images.html).
15
35
  #
16
- # The default screenshots directory is +tmp/screenshots+ but you can set a different
17
- # one with +Capybara.save_path+
36
+ # `artifact`
37
+ # : Display the screenshot in the terminal, using the terminal artifact
38
+ # format (https://buildkite.github.io/terminal-to-html/inline-images/).
18
39
  #
19
- # You can use the +html+ argument or set the +RAILS_SYSTEM_TESTING_SCREENSHOT_HTML+
20
- # environment variable to save the HTML from the page that is being screenshotted
21
- # so you can investigate the elements on the page at the time of the screenshot
22
40
  #
23
- # You can use the +screenshot+ argument or set the +RAILS_SYSTEM_TESTING_SCREENSHOT+
24
- # environment variable to control the output. Possible values are:
25
- # * [+simple+ (default)] Only displays the screenshot path.
26
- # This is the default value.
27
- # * [+inline+] Display the screenshot in the terminal using the
28
- # iTerm image protocol (https://iterm2.com/documentation-images.html).
29
- # * [+artifact+] Display the screenshot in the terminal, using the terminal
30
- # artifact format (https://buildkite.github.io/terminal-to-html/inline-images/).
31
41
  def take_screenshot(html: false, screenshot: nil)
32
42
  showing_html = html || html_from_env?
33
43
 
@@ -37,10 +47,9 @@ module ActionDispatch
37
47
  show display_image(html: showing_html, screenshot_output: screenshot)
38
48
  end
39
49
 
40
- # Takes a screenshot of the current page in the browser if the test
41
- # failed.
50
+ # Takes a screenshot of the current page in the browser if the test failed.
42
51
  #
43
- # +take_failed_screenshot+ is called during system test teardown.
52
+ # `take_failed_screenshot` is called during system test teardown.
44
53
  def take_failed_screenshot
45
54
  return unless failed? && supports_screenshot? && Capybara::Session.instance_created?
46
55
 
@@ -98,6 +107,7 @@ module ActionDispatch
98
107
  "#{absolute_path}.html"
99
108
  end
100
109
 
110
+ # rubocop:disable Lint/Debugger
101
111
  def save_html
102
112
  page.save_page(absolute_html_path)
103
113
  end
@@ -105,6 +115,7 @@ module ActionDispatch
105
115
  def save_image
106
116
  page.save_screenshot(absolute_image_path)
107
117
  end
118
+ # rubocop:enable Lint/Debugger
108
119
 
109
120
  def output_type
110
121
  # Environment variables have priority
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionDispatch
4
6
  module SystemTesting
5
7
  module TestHelpers
@@ -1,9 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  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.
6
+ # This is a class that abstracts away an asserted response. It purposely does
7
+ # not inherit from Response because it doesn't need it. That means it does not
8
+ # have headers or a body.
7
9
  class AssertionResponse
8
10
  attr_reader :code, :name
9
11
 
@@ -14,9 +16,9 @@ module ActionDispatch
14
16
  error: "5XX"
15
17
  }
16
18
 
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).
19
+ # Accepts a specific response status code as an Integer (404) or String ('404')
20
+ # or a response status range as a Symbol pseudo-code (:success, indicating any
21
+ # 200-299 status code).
20
22
  def initialize(code_or_name)
21
23
  if code_or_name.is_a?(Symbol)
22
24
  @name = code_or_name
@@ -1,8 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionDispatch
4
6
  module Assertions
5
- # A small suite of assertions that test responses from \Rails applications.
7
+ # A small suite of assertions that test responses from Rails applications.
6
8
  module ResponseAssertions
7
9
  RESPONSE_PREDICATES = { # :nodoc:
8
10
  success: :successful?,
@@ -13,20 +15,21 @@ module ActionDispatch
13
15
 
14
16
  # Asserts that the response is one of the following types:
15
17
  #
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
18
+ # * `:success` - Status code was in the 200-299 range
19
+ # * `:redirect` - Status code was in the 300-399 range
20
+ # * `:missing` - Status code was 404
21
+ # * `:error` - Status code was in the 500-599 range
22
+ #
20
23
  #
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
+ # You can also pass an explicit status number like `assert_response(501)` or its
25
+ # symbolic equivalent `assert_response(:not_implemented)`. See
26
+ # `Rack::Utils::SYMBOL_TO_STATUS_CODE` for a full list.
24
27
  #
25
- # # Asserts that the response was a redirection
26
- # assert_response :redirect
28
+ # # Asserts that the response was a redirection
29
+ # assert_response :redirect
27
30
  #
28
- # # Asserts that the response code was status code 401 (unauthorized)
29
- # assert_response 401
31
+ # # Asserts that the response code was status code 401 (unauthorized)
32
+ # assert_response 401
30
33
  def assert_response(type, message = nil)
31
34
  message ||= generate_response_message(type)
32
35
 
@@ -39,21 +42,21 @@ module ActionDispatch
39
42
 
40
43
  # Asserts that the response is a redirect to a URL matching the given options.
41
44
  #
42
- # # Asserts that the redirection was to the "index" action on the WeblogController
43
- # assert_redirected_to controller: "weblog", action: "index"
45
+ # # Asserts that the redirection was to the "index" action on the WeblogController
46
+ # assert_redirected_to controller: "weblog", action: "index"
44
47
  #
45
- # # Asserts that the redirection was to the named route login_url
46
- # assert_redirected_to login_url
48
+ # # Asserts that the redirection was to the named route login_url
49
+ # assert_redirected_to login_url
47
50
  #
48
- # # Asserts that the redirection was to the URL for @customer
49
- # assert_redirected_to @customer
51
+ # # Asserts that the redirection was to the URL for @customer
52
+ # assert_redirected_to @customer
50
53
  #
51
- # # Asserts that the redirection matches the regular expression
52
- # assert_redirected_to %r(\Ahttp://example.org)
54
+ # # Asserts that the redirection matches the regular expression
55
+ # assert_redirected_to %r(\Ahttp://example.org)
53
56
  #
54
- # # Asserts that the redirection has the HTTP status code 301 (Moved
55
- # # Permanently).
56
- # assert_redirected_to "/some/path", status: :moved_permanently
57
+ # # Asserts that the redirection has the HTTP status code 301 (Moved
58
+ # # Permanently).
59
+ # assert_redirected_to "/some/path", status: :moved_permanently
57
60
  def assert_redirected_to(url_options = {}, options = {}, message = nil)
58
61
  options, message = {}, options unless options.is_a?(Hash)
59
62
 
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "uri"
4
6
  require "active_support/core_ext/hash/indifferent_access"
5
7
  require "active_support/core_ext/string/access"
@@ -7,23 +9,82 @@ require "action_controller/metal/exceptions"
7
9
 
8
10
  module ActionDispatch
9
11
  module Assertions
10
- # Suite of assertions to test routes generated by \Rails and the handling of requests made to them.
12
+ # Suite of assertions to test routes generated by Rails and the handling of
13
+ # requests made to them.
11
14
  module RoutingAssertions
12
15
  extend ActiveSupport::Concern
13
16
 
17
+ module WithIntegrationRouting # :nodoc:
18
+ extend ActiveSupport::Concern
19
+
20
+ module ClassMethods
21
+ def with_routing(&block)
22
+ old_routes = nil
23
+ old_integration_session = nil
24
+
25
+ setup do
26
+ old_routes = app.routes
27
+ old_integration_session = integration_session
28
+ create_routes(&block)
29
+ end
30
+
31
+ teardown do
32
+ reset_routes(old_routes, old_integration_session)
33
+ end
34
+ end
35
+ end
36
+
37
+ def with_routing(&block)
38
+ old_routes = app.routes
39
+ old_integration_session = integration_session
40
+ create_routes(&block)
41
+ ensure
42
+ reset_routes(old_routes, old_integration_session)
43
+ end
44
+
45
+ private
46
+ def create_routes
47
+ app = self.app
48
+ routes = ActionDispatch::Routing::RouteSet.new
49
+ rack_app = app.config.middleware.build(routes)
50
+ https = integration_session.https?
51
+ host = integration_session.host
52
+
53
+ app.instance_variable_set(:@routes, routes)
54
+ app.instance_variable_set(:@app, rack_app)
55
+ @integration_session = Class.new(ActionDispatch::Integration::Session) do
56
+ include app.routes.url_helpers
57
+ include app.routes.mounted_helpers
58
+ end.new(app)
59
+ @integration_session.https! https
60
+ @integration_session.host! host
61
+ @routes = routes
62
+
63
+ yield routes
64
+ end
65
+
66
+ def reset_routes(old_routes, old_integration_session)
67
+ old_rack_app = app.config.middleware.build(old_routes)
68
+
69
+ app.instance_variable_set(:@routes, old_routes)
70
+ app.instance_variable_set(:@app, old_rack_app)
71
+ @integration_session = old_integration_session
72
+ @routes = old_routes
73
+ end
74
+ end
75
+
14
76
  module ClassMethods
15
- # A helper to make it easier to test different route configurations.
16
- # This method temporarily replaces @routes with a new RouteSet instance
17
- # before each test.
77
+ # A helper to make it easier to test different route configurations. This method
78
+ # temporarily replaces @routes with a new RouteSet instance before each test.
18
79
  #
19
- # The new instance is yielded to the passed block. Typically the block
20
- # will create some routes using <tt>set.draw { match ... }</tt>:
80
+ # The new instance is yielded to the passed block. Typically the block will
81
+ # create some routes using `set.draw { match ... }`:
21
82
  #
22
- # with_routing do |set|
23
- # set.draw do
24
- # resources :users
83
+ # with_routing do |set|
84
+ # set.draw do
85
+ # resources :users
86
+ # end
25
87
  # end
26
- # end
27
88
  #
28
89
  def with_routing(&block)
29
90
  old_routes, old_controller = nil
@@ -44,36 +105,62 @@ module ActionDispatch
44
105
  super
45
106
  end
46
107
 
47
- # Asserts that the routing of the given +path+ was handled correctly and that the parsed options (given in the +expected_options+ hash)
48
- # match +path+. Basically, it asserts that \Rails recognizes the route given by +expected_options+.
108
+ # A helper to make it easier to test different route configurations. This method
109
+ # temporarily replaces @routes with a new RouteSet instance.
110
+ #
111
+ # The new instance is yielded to the passed block. Typically the block will
112
+ # create some routes using `set.draw { match ... }`:
113
+ #
114
+ # with_routing do |set|
115
+ # set.draw do
116
+ # resources :users
117
+ # end
118
+ # assert_equal "/users", users_path
119
+ # end
120
+ #
121
+ def with_routing(&block)
122
+ old_routes, old_controller = @routes, @controller
123
+ create_routes(&block)
124
+ ensure
125
+ reset_routes(old_routes, old_controller)
126
+ end
127
+
128
+ # Asserts that the routing of the given `path` was handled correctly and that
129
+ # the parsed options (given in the `expected_options` hash) match `path`.
130
+ # Basically, it asserts that Rails recognizes the route given by
131
+ # `expected_options`.
49
132
  #
50
- # Pass a hash in the second argument (+path+) to specify the request method. This is useful for routes
51
- # requiring a specific HTTP method. The hash should contain a +:path+ with the incoming request path
52
- # and a +:method+ containing the required HTTP verb.
133
+ # Pass a hash in the second argument (`path`) to specify the request method.
134
+ # This is useful for routes requiring a specific HTTP method. The hash should
135
+ # contain a `:path` with the incoming request path and a `:method` containing
136
+ # the required HTTP verb.
53
137
  #
54
- # # Asserts that POSTing to /items will call the create action on ItemsController
55
- # assert_recognizes({controller: 'items', action: 'create'}, {path: 'items', method: :post})
138
+ # # Asserts that POSTing to /items will call the create action on ItemsController
139
+ # assert_recognizes({controller: 'items', action: 'create'}, {path: 'items', method: :post})
56
140
  #
57
- # You can also pass in +extras+ with a hash containing URL parameters that would normally be in the query string. This can be used
58
- # to assert that values in the query string will end up in the params hash correctly. To test query strings you must use the extras
59
- # argument because appending the query string on the path directly will not work. For example:
141
+ # You can also pass in `extras` with a hash containing URL parameters that would
142
+ # normally be in the query string. This can be used to assert that values in the
143
+ # query string will end up in the params hash correctly. To test query strings
144
+ # you must use the extras argument because appending the query string on the
145
+ # path directly will not work. For example:
60
146
  #
61
- # # Asserts that a path of '/items/list/1?view=print' returns the correct options
62
- # assert_recognizes({controller: 'items', action: 'list', id: '1', view: 'print'}, 'items/list/1', { view: "print" })
147
+ # # Asserts that a path of '/items/list/1?view=print' returns the correct options
148
+ # assert_recognizes({controller: 'items', action: 'list', id: '1', view: 'print'}, 'items/list/1', { view: "print" })
63
149
  #
64
- # The +message+ parameter allows you to pass in an error message that is displayed upon failure.
150
+ # The `message` parameter allows you to pass in an error message that is
151
+ # displayed upon failure.
65
152
  #
66
- # # Check the default route (i.e., the index action)
67
- # assert_recognizes({controller: 'items', action: 'index'}, 'items')
153
+ # # Check the default route (i.e., the index action)
154
+ # assert_recognizes({controller: 'items', action: 'index'}, 'items')
68
155
  #
69
- # # Test a specific action
70
- # assert_recognizes({controller: 'items', action: 'list'}, 'items/list')
156
+ # # Test a specific action
157
+ # assert_recognizes({controller: 'items', action: 'list'}, 'items/list')
71
158
  #
72
- # # Test an action with a parameter
73
- # assert_recognizes({controller: 'items', action: 'destroy', id: '1'}, 'items/destroy/1')
159
+ # # Test an action with a parameter
160
+ # assert_recognizes({controller: 'items', action: 'destroy', id: '1'}, 'items/destroy/1')
74
161
  #
75
- # # Test a custom route
76
- # assert_recognizes({controller: 'items', action: 'show', id: '1'}, 'view/item1')
162
+ # # Test a custom route
163
+ # assert_recognizes({controller: 'items', action: 'show', id: '1'}, 'view/item1')
77
164
  def assert_recognizes(expected_options, path, extras = {}, msg = nil)
78
165
  if path.is_a?(Hash) && path[:method].to_s == "all"
79
166
  [:get, :post, :put, :delete].each do |method|
@@ -95,23 +182,25 @@ module ActionDispatch
95
182
  end
96
183
  end
97
184
 
98
- # Asserts that the provided options can be used to generate the provided path. This is the inverse of +assert_recognizes+.
99
- # The +extras+ parameter is used to tell the request the names and values of additional request parameters that would be in
100
- # a query string. The +message+ parameter allows you to specify a custom error message for assertion failures.
185
+ # Asserts that the provided options can be used to generate the provided path.
186
+ # This is the inverse of `assert_recognizes`. The `extras` parameter is used to
187
+ # tell the request the names and values of additional request parameters that
188
+ # would be in a query string. The `message` parameter allows you to specify a
189
+ # custom error message for assertion failures.
101
190
  #
102
- # The +defaults+ parameter is unused.
191
+ # The `defaults` parameter is unused.
103
192
  #
104
- # # Asserts that the default action is generated for a route with no action
105
- # assert_generates "/items", controller: "items", action: "index"
193
+ # # Asserts that the default action is generated for a route with no action
194
+ # assert_generates "/items", controller: "items", action: "index"
106
195
  #
107
- # # Tests that the list action is properly routed
108
- # assert_generates "/items/list", controller: "items", action: "list"
196
+ # # Tests that the list action is properly routed
197
+ # assert_generates "/items/list", controller: "items", action: "list"
109
198
  #
110
- # # Tests the generation of a route with a parameter
111
- # assert_generates "/items/list/1", { controller: "items", action: "list", id: "1" }
199
+ # # Tests the generation of a route with a parameter
200
+ # assert_generates "/items/list/1", { controller: "items", action: "list", id: "1" }
112
201
  #
113
- # # Asserts that the generated route gives us our custom route
114
- # assert_generates "changesets/12", { controller: 'scm', action: 'show_diff', revision: "12" }
202
+ # # Asserts that the generated route gives us our custom route
203
+ # assert_generates "changesets/12", { controller: 'scm', action: 'show_diff', revision: "12" }
115
204
  def assert_generates(expected_path, options, defaults = {}, extras = {}, message = nil)
116
205
  if expected_path.include?("://")
117
206
  fail_on(URI::InvalidURIError, message) do
@@ -134,27 +223,28 @@ module ActionDispatch
134
223
  assert_equal(expected_path, generated_path, msg)
135
224
  end
136
225
 
137
- # Asserts that path and options match both ways; in other words, it verifies that <tt>path</tt> generates
138
- # <tt>options</tt> and then that <tt>options</tt> generates <tt>path</tt>. This essentially combines +assert_recognizes+
139
- # and +assert_generates+ into one step.
226
+ # Asserts that path and options match both ways; in other words, it verifies
227
+ # that `path` generates `options` and then that `options` generates `path`. This
228
+ # essentially combines `assert_recognizes` and `assert_generates` into one step.
140
229
  #
141
- # The +extras+ hash allows you to specify options that would normally be provided as a query string to the action. The
142
- # +message+ parameter allows you to specify a custom error message to display upon failure.
230
+ # The `extras` hash allows you to specify options that would normally be
231
+ # provided as a query string to the action. The `message` parameter allows you
232
+ # to specify a custom error message to display upon failure.
143
233
  #
144
- # # Asserts a basic route: a controller with the default action (index)
145
- # assert_routing '/home', controller: 'home', action: 'index'
234
+ # # Asserts a basic route: a controller with the default action (index)
235
+ # assert_routing '/home', controller: 'home', action: 'index'
146
236
  #
147
- # # Test a route generated with a specific controller, action, and parameter (id)
148
- # assert_routing '/entries/show/23', controller: 'entries', action: 'show', id: 23
237
+ # # Test a route generated with a specific controller, action, and parameter (id)
238
+ # assert_routing '/entries/show/23', controller: 'entries', action: 'show', id: 23
149
239
  #
150
- # # Asserts a basic route (controller + default action), with an error message if it fails
151
- # assert_routing '/store', { controller: 'store', action: 'index' }, {}, {}, 'Route for store index not generated properly'
240
+ # # Asserts a basic route (controller + default action), with an error message if it fails
241
+ # assert_routing '/store', { controller: 'store', action: 'index' }, {}, {}, 'Route for store index not generated properly'
152
242
  #
153
- # # Tests a route, providing a defaults hash
154
- # assert_routing 'controller/action/9', {id: "9", item: "square"}, {controller: "controller", action: "action"}, {}, {item: "square"}
243
+ # # Tests a route, providing a defaults hash
244
+ # assert_routing 'controller/action/9', {id: "9", item: "square"}, {controller: "controller", action: "action"}, {}, {item: "square"}
155
245
  #
156
- # # Tests a route with an HTTP method
157
- # assert_routing({ method: 'put', path: '/product/321' }, { controller: "product", action: "update", id: "321" })
246
+ # # Tests a route with an HTTP method
247
+ # assert_routing({ method: 'put', path: '/product/321' }, { controller: "product", action: "update", id: "321" })
158
248
  def assert_routing(path, options, defaults = {}, extras = {}, message = nil)
159
249
  assert_recognizes(options, path, extras, message)
160
250
 
@@ -167,40 +257,19 @@ module ActionDispatch
167
257
  assert_generates(path.is_a?(Hash) ? path[:path] : path, generate_options, defaults, extras, message)
168
258
  end
169
259
 
170
- # A helper to make it easier to test different route configurations.
171
- # This method temporarily replaces @routes with a new RouteSet instance.
172
- #
173
- # The new instance is yielded to the passed block. Typically the block
174
- # will create some routes using <tt>set.draw { match ... }</tt>:
175
- #
176
- # with_routing do |set|
177
- # set.draw do
178
- # resources :users
179
- # end
180
- # assert_equal "/users", users_path
181
- # end
182
- #
183
- def with_routing(&block)
184
- old_routes, old_controller = @routes, @controller
185
- create_routes(&block)
186
- ensure
187
- reset_routes(old_routes, old_controller)
188
- end
189
-
190
260
  # ROUTES TODO: These assertions should really work in an integration context
191
- def method_missing(selector, *args, &block)
192
- if defined?(@controller) && @controller && defined?(@routes) && @routes && @routes.named_routes.route_defined?(selector)
193
- @controller.public_send(selector, *args, &block)
261
+ def method_missing(selector, ...)
262
+ if @controller && @routes&.named_routes&.route_defined?(selector)
263
+ @controller.public_send(selector, ...)
194
264
  else
195
265
  super
196
266
  end
197
267
  end
198
- ruby2_keywords(:method_missing)
199
268
 
200
269
  private
201
270
  def create_routes
202
271
  @routes = ActionDispatch::Routing::RouteSet.new
203
- if defined?(@controller) && @controller
272
+ if @controller
204
273
  @controller = @controller.clone
205
274
  _routes = @routes
206
275
 
@@ -224,7 +293,7 @@ module ActionDispatch
224
293
 
225
294
  def reset_routes(old_routes, old_controller)
226
295
  @routes = old_routes
227
- if defined?(@controller) && @controller
296
+ if @controller
228
297
  @controller = old_controller
229
298
  end
230
299
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "rails-dom-testing"
4
6
  require "action_dispatch/testing/assertions/response"
5
7
  require "action_dispatch/testing/assertions/routing"