actionpack 7.1.3 → 7.2.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (158) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +82 -501
  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 +15 -7
  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 +198 -126
  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 +123 -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 +210 -205
  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 +86 -60
  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 +18 -9
  70. data/lib/action_dispatch/http/filter_redirect.rb +22 -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 +31 -24
  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 +20 -44
  77. data/lib/action_dispatch/http/rack_cache.rb +2 -0
  78. data/lib/action_dispatch/http/request.rb +94 -75
  79. data/lib/action_dispatch/http/response.rb +73 -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 +671 -636
  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 +39 -16
@@ -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"