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,63 +1,65 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "stringio"
4
6
  require "uri"
5
7
  require "rack/test"
6
8
  require "active_support/test_case"
7
9
 
8
10
  require "action_dispatch/testing/request_encoder"
11
+ require "action_dispatch/testing/test_helpers/page_dump_helper"
9
12
 
10
13
  module ActionDispatch
11
14
  module Integration # :nodoc:
12
15
  module RequestHelpers
13
- # Performs a GET request with the given parameters. See ActionDispatch::Integration::Session#process
14
- # for more details.
16
+ # Performs a GET request with the given parameters. See
17
+ # ActionDispatch::Integration::Session#process for more details.
15
18
  def get(path, **args)
16
19
  process(:get, path, **args)
17
20
  end
18
21
 
19
- # Performs a POST request with the given parameters. See ActionDispatch::Integration::Session#process
20
- # for more details.
22
+ # Performs a POST request with the given parameters. See
23
+ # ActionDispatch::Integration::Session#process for more details.
21
24
  def post(path, **args)
22
25
  process(:post, path, **args)
23
26
  end
24
27
 
25
- # Performs a PATCH request with the given parameters. See ActionDispatch::Integration::Session#process
26
- # for more details.
28
+ # Performs a PATCH request with the given parameters. See
29
+ # ActionDispatch::Integration::Session#process for more details.
27
30
  def patch(path, **args)
28
31
  process(:patch, path, **args)
29
32
  end
30
33
 
31
- # Performs a PUT request with the given parameters. See ActionDispatch::Integration::Session#process
32
- # for more details.
34
+ # Performs a PUT request with the given parameters. See
35
+ # ActionDispatch::Integration::Session#process for more details.
33
36
  def put(path, **args)
34
37
  process(:put, path, **args)
35
38
  end
36
39
 
37
- # Performs a DELETE request with the given parameters. See ActionDispatch::Integration::Session#process
38
- # for more details.
40
+ # Performs a DELETE request with the given parameters. See
41
+ # ActionDispatch::Integration::Session#process for more details.
39
42
  def delete(path, **args)
40
43
  process(:delete, path, **args)
41
44
  end
42
45
 
43
- # Performs a HEAD request with the given parameters. See ActionDispatch::Integration::Session#process
44
- # for more details.
46
+ # Performs a HEAD request with the given parameters. See
47
+ # ActionDispatch::Integration::Session#process for more details.
45
48
  def head(path, **args)
46
49
  process(:head, path, **args)
47
50
  end
48
51
 
49
- # Performs an OPTIONS request with the given parameters. See ActionDispatch::Integration::Session#process
50
- # for more details.
52
+ # Performs an OPTIONS request with the given parameters. See
53
+ # ActionDispatch::Integration::Session#process for more details.
51
54
  def options(path, **args)
52
55
  process(:options, path, **args)
53
56
  end
54
57
 
55
- # Follow a single redirect response. If the last response was not a
56
- # redirect, an exception will be raised. Otherwise, the redirect is
57
- # performed on the location header. If the redirection is a 307 or 308 redirect,
58
- # the same HTTP verb will be used when redirecting, otherwise a GET request
59
- # will be performed. Any arguments are passed to the
60
- # underlying request.
58
+ # Follow a single redirect response. If the last response was not a redirect, an
59
+ # exception will be raised. Otherwise, the redirect is performed on the location
60
+ # header. If the redirection is a 307 or 308 redirect, the same HTTP verb will
61
+ # be used when redirecting, otherwise a GET request will be performed. Any
62
+ # arguments are passed to the underlying request.
61
63
  #
62
64
  # The HTTP_REFERER header will be set to the previous url.
63
65
  def follow_redirect!(headers: {}, **args)
@@ -79,13 +81,13 @@ module ActionDispatch
79
81
  end
80
82
  end
81
83
 
82
- # An instance of this class represents a set of requests and responses
83
- # performed sequentially by a test process. Because you can instantiate
84
- # multiple sessions and run them side-by-side, you can also mimic (to some
85
- # limited extent) multiple simultaneous users interacting with your system.
84
+ # An instance of this class represents a set of requests and responses performed
85
+ # sequentially by a test process. Because you can instantiate multiple sessions
86
+ # and run them side-by-side, you can also mimic (to some limited extent)
87
+ # multiple simultaneous users interacting with your system.
86
88
  #
87
89
  # Typically, you will instantiate a new session using Runner#open_session,
88
- # rather than instantiating a \Session directly.
90
+ # rather than instantiating a Session directly.
89
91
  class Session
90
92
  DEFAULT_HOST = "www.example.com"
91
93
 
@@ -107,8 +109,8 @@ module ActionDispatch
107
109
  # The Accept header to send.
108
110
  attr_accessor :accept
109
111
 
110
- # A map of the cookies returned by the last response, and which will be
111
- # sent with the next request.
112
+ # A map of the cookies returned by the last response, and which will be sent
113
+ # with the next request.
112
114
  def cookies
113
115
  _mock_session.cookie_jar
114
116
  end
@@ -127,7 +129,7 @@ module ActionDispatch
127
129
 
128
130
  include ActionDispatch::Routing::UrlFor
129
131
 
130
- # Create and initialize a new \Session instance.
132
+ # Create and initialize a new Session instance.
131
133
  def initialize(app)
132
134
  super()
133
135
  @app = app
@@ -147,11 +149,10 @@ module ActionDispatch
147
149
  end
148
150
  end
149
151
 
150
- # Resets the instance. This can be used to reset the state information
151
- # in an existing session instance, so it can be used from a clean-slate
152
- # condition.
152
+ # Resets the instance. This can be used to reset the state information in an
153
+ # existing session instance, so it can be used from a clean-slate condition.
153
154
  #
154
- # session.reset!
155
+ # session.reset!
155
156
  def reset!
156
157
  @https = false
157
158
  @controller = @request = @response = nil
@@ -166,63 +167,61 @@ module ActionDispatch
166
167
  "*/*;q=0.5"
167
168
 
168
169
  unless defined? @named_routes_configured
169
- # the helpers are made protected by default--we make them public for
170
- # easier access during testing and troubleshooting.
170
+ # the helpers are made protected by default--we make them public for easier
171
+ # access during testing and troubleshooting.
171
172
  @named_routes_configured = true
172
173
  end
173
174
  end
174
175
 
175
176
  # Specify whether or not the session should mimic a secure HTTPS request.
176
177
  #
177
- # session.https!
178
- # session.https!(false)
178
+ # session.https!
179
+ # session.https!(false)
179
180
  def https!(flag = true)
180
181
  @https = flag
181
182
  end
182
183
 
183
- # Returns +true+ if the session is mimicking a secure HTTPS request.
184
+ # Returns `true` if the session is mimicking a secure HTTPS request.
184
185
  #
185
- # if session.https?
186
- # ...
187
- # end
186
+ # if session.https?
187
+ # ...
188
+ # end
188
189
  def https?
189
190
  @https
190
191
  end
191
192
 
192
193
  # Performs the actual request.
193
194
  #
194
- # - +method+: The HTTP method (GET, POST, PATCH, PUT, DELETE, HEAD, OPTIONS)
195
- # as a symbol.
196
- # - +path+: The URI (as a String) on which you want to perform the
197
- # request.
198
- # - +params+: The HTTP parameters that you want to pass. This may
199
- # be +nil+,
200
- # a Hash, or a String that is appropriately encoded
201
- # (<tt>application/x-www-form-urlencoded</tt> or
202
- # <tt>multipart/form-data</tt>).
203
- # - +headers+: Additional headers to pass, as a Hash. The headers will be
204
- # merged into the Rack env hash.
205
- # - +env+: Additional env to pass, as a Hash. The headers will be
206
- # merged into the Rack env hash.
207
- # - +xhr+: Set to +true+ if you want to make an Ajax request.
208
- # Adds request headers characteristic of XMLHttpRequest e.g. HTTP_X_REQUESTED_WITH.
209
- # The headers will be merged into the Rack env hash.
210
- # - +as+: Used for encoding the request with different content type.
211
- # Supports +:json+ by default and will set the appropriate request headers.
212
- # The headers will be merged into the Rack env hash.
195
+ # * `method`: The HTTP method (GET, POST, PATCH, PUT, DELETE, HEAD, OPTIONS)
196
+ # as a symbol.
197
+ # * `path`: The URI (as a String) on which you want to perform the request.
198
+ # * `params`: The HTTP parameters that you want to pass. This may be `nil`, a
199
+ # Hash, or a String that is appropriately encoded
200
+ # (`application/x-www-form-urlencoded` or `multipart/form-data`).
201
+ # * `headers`: Additional headers to pass, as a Hash. The headers will be
202
+ # merged into the Rack env hash.
203
+ # * `env`: Additional env to pass, as a Hash. The headers will be merged into
204
+ # the Rack env hash.
205
+ # * `xhr`: Set to `true` if you want to make an Ajax request. Adds request
206
+ # headers characteristic of XMLHttpRequest e.g. HTTP_X_REQUESTED_WITH. The
207
+ # headers will be merged into the Rack env hash.
208
+ # * `as`: Used for encoding the request with different content type. Supports
209
+ # `:json` by default and will set the appropriate request headers. The
210
+ # headers will be merged into the Rack env hash.
211
+ #
213
212
  #
214
213
  # This method is rarely used directly. Use RequestHelpers#get,
215
- # RequestHelpers#post, or other standard HTTP methods in integration
216
- # tests. +#process+ is only required when using a request method that
217
- # doesn't have a method defined in the integration tests.
214
+ # RequestHelpers#post, or other standard HTTP methods in integration tests.
215
+ # `#process` is only required when using a request method that doesn't have a
216
+ # method defined in the integration tests.
218
217
  #
219
218
  # This method returns the response status, after performing the request.
220
- # Furthermore, if this method was called from an ActionDispatch::IntegrationTest object,
221
- # then that object's <tt>@response</tt> instance variable will point to a Response object
222
- # which one can use to inspect the details of the response.
219
+ # Furthermore, if this method was called from an ActionDispatch::IntegrationTest
220
+ # object, then that object's `@response` instance variable will point to a
221
+ # Response object which one can use to inspect the details of the response.
223
222
  #
224
223
  # Example:
225
- # process :get, '/author', params: { since: 201501011400 }
224
+ # process :get, '/author', params: { since: 201501011400 }
226
225
  def process(method, path, params: nil, headers: nil, env: nil, xhr: false, as: nil)
227
226
  request_encoder = RequestEncoder.encoder(as)
228
227
  headers ||= {}
@@ -283,8 +282,8 @@ module ActionDispatch
283
282
 
284
283
  session = Rack::Test::Session.new(_mock_session)
285
284
 
286
- # NOTE: rack-test v0.5 doesn't build a default uri correctly
287
- # Make sure requested path is always a full URI.
285
+ # NOTE: rack-test v0.5 doesn't build a default uri correctly Make sure requested
286
+ # path is always a full URI.
288
287
  session.request(build_full_uri(path, request_env), request_env)
289
288
 
290
289
  @request_count += 1
@@ -302,7 +301,7 @@ module ActionDispatch
302
301
 
303
302
  # Set the host name to use in the next request.
304
303
  #
305
- # session.host! "www.example.com"
304
+ # session.host! "www.example.com"
306
305
  alias :host! :host=
307
306
 
308
307
  private
@@ -344,16 +343,16 @@ module ActionDispatch
344
343
  @integration_session ||= create_session(app)
345
344
  end
346
345
 
347
- # Reset the current session. This is useful for testing multiple sessions
348
- # in a single test case.
346
+ # Reset the current session. This is useful for testing multiple sessions in a
347
+ # single test case.
349
348
  def reset!
350
349
  @integration_session = create_session(app)
351
350
  end
352
351
 
353
352
  def create_session(app)
354
353
  klass = APP_SESSIONS[app] ||= Class.new(Integration::Session) {
355
- # If the app is a Rails app, make url_helpers available on the session.
356
- # This makes app.url_for and app.foo_path available in the console.
354
+ # If the app is a Rails app, make url_helpers available on the session. This
355
+ # makes app.url_for and app.foo_path available in the console.
357
356
  if app.respond_to?(:routes) && app.routes.is_a?(ActionDispatch::Routing::RouteSet)
358
357
  include app.routes.url_helpers
359
358
  include app.routes.mounted_helpers
@@ -383,16 +382,15 @@ module ActionDispatch
383
382
  RUBY
384
383
  end
385
384
 
386
- # Open a new session instance. If a block is given, the new session is
387
- # yielded to the block before being returned.
385
+ # Open a new session instance. If a block is given, the new session is yielded
386
+ # to the block before being returned.
388
387
  #
389
- # session = open_session do |sess|
390
- # sess.extend(CustomAssertions)
391
- # end
388
+ # session = open_session do |sess|
389
+ # sess.extend(CustomAssertions)
390
+ # end
392
391
  #
393
- # By default, a single session is automatically created for you, but you
394
- # can use this method to open multiple sessions that ought to be tested
395
- # simultaneously.
392
+ # By default, a single session is automatically created for you, but you can use
393
+ # this method to open multiple sessions that ought to be tested simultaneously.
396
394
  def open_session
397
395
  dup.tap do |session|
398
396
  session.reset!
@@ -409,8 +407,8 @@ module ActionDispatch
409
407
  root_session ? root_session.assertions = assertions : super
410
408
  end
411
409
 
412
- # Copy the instance variables from the current session instance into the
413
- # test instance.
410
+ # Copy the instance variables from the current session instance into the test
411
+ # instance.
414
412
  def copy_session_variables! # :nodoc:
415
413
  @controller = @integration_session.controller
416
414
  @response = @integration_session.response
@@ -431,212 +429,213 @@ module ActionDispatch
431
429
  end
432
430
 
433
431
  # Delegate unhandled messages to the current session instance.
434
- def method_missing(method, *args, &block)
432
+ def method_missing(method, ...)
435
433
  if integration_session.respond_to?(method)
436
- integration_session.public_send(method, *args, &block).tap do
434
+ integration_session.public_send(method, ...).tap do
437
435
  copy_session_variables!
438
436
  end
439
437
  else
440
438
  super
441
439
  end
442
440
  end
443
- ruby2_keywords(:method_missing)
444
441
  end
445
442
  end
446
443
 
447
- # An integration test spans multiple controllers and actions,
448
- # tying them all together to ensure they work together as expected. It tests
449
- # more completely than either unit or functional tests do, exercising the
450
- # entire stack, from the dispatcher to the database.
444
+ # An integration test spans multiple controllers and actions, tying them all
445
+ # together to ensure they work together as expected. It tests more completely
446
+ # than either unit or functional tests do, exercising the entire stack, from the
447
+ # dispatcher to the database.
451
448
  #
452
- # At its simplest, you simply extend <tt>IntegrationTest</tt> and write your
453
- # tests using the Integration::RequestHelpers#get and/or
449
+ # At its simplest, you simply extend `IntegrationTest` and write your tests
450
+ # using the Integration::RequestHelpers#get and/or
454
451
  # Integration::RequestHelpers#post methods:
455
452
  #
456
- # require "test_helper"
453
+ # require "test_helper"
457
454
  #
458
- # class ExampleTest < ActionDispatch::IntegrationTest
459
- # fixtures :people
455
+ # class ExampleTest < ActionDispatch::IntegrationTest
456
+ # fixtures :people
460
457
  #
461
- # def test_login
462
- # # get the login page
463
- # get "/login"
464
- # assert_equal 200, status
458
+ # def test_login
459
+ # # get the login page
460
+ # get "/login"
461
+ # assert_equal 200, status
465
462
  #
466
- # # post the login and follow through to the home page
467
- # post "/login", params: { username: people(:jamis).username,
468
- # password: people(:jamis).password }
469
- # follow_redirect!
470
- # assert_equal 200, status
471
- # assert_equal "/home", path
463
+ # # post the login and follow through to the home page
464
+ # post "/login", params: { username: people(:jamis).username,
465
+ # password: people(:jamis).password }
466
+ # follow_redirect!
467
+ # assert_equal 200, status
468
+ # assert_equal "/home", path
469
+ # end
472
470
  # end
473
- # end
474
- #
475
- # However, you can also have multiple session instances open per test, and
476
- # even extend those instances with assertions and methods to create a very
477
- # powerful testing DSL that is specific for your application. You can even
478
- # reference any named routes you happen to have defined.
479
- #
480
- # require "test_helper"
481
471
  #
482
- # class AdvancedTest < ActionDispatch::IntegrationTest
483
- # fixtures :people, :rooms
472
+ # However, you can also have multiple session instances open per test, and even
473
+ # extend those instances with assertions and methods to create a very powerful
474
+ # testing DSL that is specific for your application. You can even reference any
475
+ # named routes you happen to have defined.
484
476
  #
485
- # def test_login_and_speak
486
- # jamis, david = login(:jamis), login(:david)
487
- # room = rooms(:office)
477
+ # require "test_helper"
488
478
  #
489
- # jamis.enter(room)
490
- # jamis.speak(room, "anybody home?")
479
+ # class AdvancedTest < ActionDispatch::IntegrationTest
480
+ # fixtures :people, :rooms
491
481
  #
492
- # david.enter(room)
493
- # david.speak(room, "hello!")
494
- # end
482
+ # def test_login_and_speak
483
+ # jamis, david = login(:jamis), login(:david)
484
+ # room = rooms(:office)
495
485
  #
496
- # private
486
+ # jamis.enter(room)
487
+ # jamis.speak(room, "anybody home?")
497
488
  #
498
- # module CustomAssertions
499
- # def enter(room)
500
- # # reference a named route, for maximum internal consistency!
501
- # get(room_url(id: room.id))
502
- # assert(...)
503
- # ...
504
- # end
489
+ # david.enter(room)
490
+ # david.speak(room, "hello!")
491
+ # end
505
492
  #
506
- # def speak(room, message)
507
- # post "/say/#{room.id}", xhr: true, params: { message: message }
508
- # assert(...)
509
- # ...
493
+ # private
494
+ #
495
+ # module CustomAssertions
496
+ # def enter(room)
497
+ # # reference a named route, for maximum internal consistency!
498
+ # get(room_url(id: room.id))
499
+ # assert(...)
500
+ # ...
501
+ # end
502
+ #
503
+ # def speak(room, message)
504
+ # post "/say/#{room.id}", xhr: true, params: { message: message }
505
+ # assert(...)
506
+ # ...
507
+ # end
510
508
  # end
511
- # end
512
509
  #
513
- # def login(who)
514
- # open_session do |sess|
515
- # sess.extend(CustomAssertions)
516
- # who = people(who)
517
- # sess.post "/login", params: { username: who.username,
518
- # password: who.password }
519
- # assert(...)
510
+ # def login(who)
511
+ # open_session do |sess|
512
+ # sess.extend(CustomAssertions)
513
+ # who = people(who)
514
+ # sess.post "/login", params: { username: who.username,
515
+ # password: who.password }
516
+ # assert(...)
517
+ # end
520
518
  # end
521
- # end
522
- # end
519
+ # end
523
520
  #
524
521
  # Another longer example would be:
525
522
  #
526
523
  # A simple integration test that exercises multiple controllers:
527
524
  #
528
- # require "test_helper"
525
+ # require "test_helper"
529
526
  #
530
- # class UserFlowsTest < ActionDispatch::IntegrationTest
531
- # test "login and browse site" do
532
- # # login via https
533
- # https!
534
- # get "/login"
535
- # assert_response :success
527
+ # class UserFlowsTest < ActionDispatch::IntegrationTest
528
+ # test "login and browse site" do
529
+ # # login via https
530
+ # https!
531
+ # get "/login"
532
+ # assert_response :success
536
533
  #
537
- # post "/login", params: { username: users(:david).username, password: users(:david).password }
538
- # follow_redirect!
539
- # assert_equal '/welcome', path
540
- # assert_equal 'Welcome david!', flash[:notice]
534
+ # post "/login", params: { username: users(:david).username, password: users(:david).password }
535
+ # follow_redirect!
536
+ # assert_equal '/welcome', path
537
+ # assert_equal 'Welcome david!', flash[:notice]
541
538
  #
542
- # https!(false)
543
- # get "/articles/all"
544
- # assert_response :success
545
- # assert_select 'h1', 'Articles'
539
+ # https!(false)
540
+ # get "/articles/all"
541
+ # assert_response :success
542
+ # assert_select 'h1', 'Articles'
543
+ # end
546
544
  # end
547
- # end
548
545
  #
549
546
  # As you can see the integration test involves multiple controllers and
550
547
  # exercises the entire stack from database to dispatcher. In addition you can
551
- # have multiple session instances open simultaneously in a test and extend
552
- # those instances with assertion methods to create a very powerful testing
553
- # DSL (domain-specific language) just for your application.
548
+ # have multiple session instances open simultaneously in a test and extend those
549
+ # instances with assertion methods to create a very powerful testing DSL
550
+ # (domain-specific language) just for your application.
554
551
  #
555
552
  # Here's an example of multiple sessions and custom DSL in an integration test
556
553
  #
557
- # require "test_helper"
554
+ # require "test_helper"
558
555
  #
559
- # class UserFlowsTest < ActionDispatch::IntegrationTest
560
- # test "login and browse site" do
561
- # # User david logs in
562
- # david = login(:david)
563
- # # User guest logs in
564
- # guest = login(:guest)
556
+ # class UserFlowsTest < ActionDispatch::IntegrationTest
557
+ # test "login and browse site" do
558
+ # # User david logs in
559
+ # david = login(:david)
560
+ # # User guest logs in
561
+ # guest = login(:guest)
565
562
  #
566
- # # Both are now available in different sessions
567
- # assert_equal 'Welcome david!', david.flash[:notice]
568
- # assert_equal 'Welcome guest!', guest.flash[:notice]
563
+ # # Both are now available in different sessions
564
+ # assert_equal 'Welcome david!', david.flash[:notice]
565
+ # assert_equal 'Welcome guest!', guest.flash[:notice]
569
566
  #
570
- # # User david can browse site
571
- # david.browses_site
572
- # # User guest can browse site as well
573
- # guest.browses_site
567
+ # # User david can browse site
568
+ # david.browses_site
569
+ # # User guest can browse site as well
570
+ # guest.browses_site
574
571
  #
575
- # # Continue with other assertions
576
- # end
572
+ # # Continue with other assertions
573
+ # end
577
574
  #
578
- # private
575
+ # private
579
576
  #
580
- # module CustomDsl
581
- # def browses_site
582
- # get "/products/all"
583
- # assert_response :success
584
- # assert_select 'h1', 'Products'
577
+ # module CustomDsl
578
+ # def browses_site
579
+ # get "/products/all"
580
+ # assert_response :success
581
+ # assert_select 'h1', 'Products'
582
+ # end
585
583
  # end
586
- # end
587
584
  #
588
- # def login(user)
589
- # open_session do |sess|
590
- # sess.extend(CustomDsl)
591
- # u = users(user)
592
- # sess.https!
593
- # sess.post "/login", params: { username: u.username, password: u.password }
594
- # assert_equal '/welcome', sess.path
595
- # sess.https!(false)
585
+ # def login(user)
586
+ # open_session do |sess|
587
+ # sess.extend(CustomDsl)
588
+ # u = users(user)
589
+ # sess.https!
590
+ # sess.post "/login", params: { username: u.username, password: u.password }
591
+ # assert_equal '/welcome', sess.path
592
+ # sess.https!(false)
593
+ # end
596
594
  # end
597
- # end
598
- # end
595
+ # end
599
596
  #
600
- # See the {request helpers documentation}[rdoc-ref:ActionDispatch::Integration::RequestHelpers] for help on how to
601
- # use +get+, etc.
597
+ # See the [request helpers documentation]
598
+ # (rdoc-ref:ActionDispatch::Integration::RequestHelpers) for help
599
+ # on how to use `get`, etc.
602
600
  #
603
- # === Changing the request encoding
601
+ # ### Changing the request encoding
604
602
  #
605
- # You can also test your JSON API easily by setting what the request should
606
- # be encoded as:
603
+ # You can also test your JSON API easily by setting what the request should be
604
+ # encoded as:
607
605
  #
608
- # require "test_helper"
606
+ # require "test_helper"
609
607
  #
610
- # class ApiTest < ActionDispatch::IntegrationTest
611
- # test "creates articles" do
612
- # assert_difference -> { Article.count } do
613
- # post articles_path, params: { article: { title: "Ahoy!" } }, as: :json
614
- # end
608
+ # class ApiTest < ActionDispatch::IntegrationTest
609
+ # test "creates articles" do
610
+ # assert_difference -> { Article.count } do
611
+ # post articles_path, params: { article: { title: "Ahoy!" } }, as: :json
612
+ # end
615
613
  #
616
- # assert_response :success
617
- # assert_equal({ id: Article.last.id, title: "Ahoy!" }, response.parsed_body)
614
+ # assert_response :success
615
+ # assert_equal({ id: Article.last.id, title: "Ahoy!" }, response.parsed_body)
616
+ # end
618
617
  # end
619
- # end
620
618
  #
621
- # The +as+ option passes an "application/json" Accept header (thereby setting
619
+ # The `as` option passes an "application/json" Accept header (thereby setting
622
620
  # the request format to JSON unless overridden), sets the content type to
623
621
  # "application/json" and encodes the parameters as JSON.
624
622
  #
625
- # Calling TestResponse#parsed_body on the response parses the response body based on the
626
- # last response MIME type.
623
+ # Calling TestResponse#parsed_body on the response parses the response body
624
+ # based on the last response MIME type.
627
625
  #
628
- # Out of the box, only <tt>:json</tt> is supported. But for any custom MIME
629
- # types you've registered, you can add your own encoders with:
626
+ # Out of the box, only `:json` is supported. But for any custom MIME types
627
+ # you've registered, you can add your own encoders with:
630
628
  #
631
- # ActionDispatch::IntegrationTest.register_encoder :wibble,
632
- # param_encoder: -> params { params.to_wibble },
633
- # response_parser: -> body { body }
629
+ # ActionDispatch::IntegrationTest.register_encoder :wibble,
630
+ # param_encoder: -> params { params.to_wibble },
631
+ # response_parser: -> body { body }
634
632
  #
635
- # Where +param_encoder+ defines how the params should be encoded and
636
- # +response_parser+ defines how the response body should be parsed through
633
+ # Where `param_encoder` defines how the params should be encoded and
634
+ # `response_parser` defines how the response body should be parsed through
637
635
  # TestResponse#parsed_body.
638
636
  #
639
- # Consult the {Rails Testing Guide}[https://guides.rubyonrails.org/testing.html] for more.
637
+ # Consult the [Rails Testing Guide](https://guides.rubyonrails.org/testing.html)
638
+ # for more.
640
639
 
641
640
  class IntegrationTest < ActiveSupport::TestCase
642
641
  include TestProcess::FixtureFile
@@ -653,10 +652,12 @@ module ActionDispatch
653
652
 
654
653
  include Integration::Runner
655
654
  include ActionController::TemplateAssertions
655
+ include TestHelpers::PageDumpHelper
656
656
 
657
657
  included do
658
658
  include ActionDispatch::Routing::UrlFor
659
659
  include UrlOptions # don't let UrlFor override the url_options method
660
+ include ActionDispatch::Assertions::RoutingAssertions::WithIntegrationRouting
660
661
  ActiveSupport.run_load_hooks(:action_dispatch_integration_test, self)
661
662
  @@app = nil
662
663
  end