actionpack 3.2.22.5 → 5.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (271) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +279 -603
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +13 -297
  5. data/lib/abstract_controller/asset_paths.rb +4 -2
  6. data/lib/abstract_controller/base.rb +82 -52
  7. data/lib/abstract_controller/caching/fragments.rb +166 -0
  8. data/lib/abstract_controller/caching.rb +66 -0
  9. data/lib/abstract_controller/callbacks.rb +117 -103
  10. data/lib/abstract_controller/collector.rb +18 -7
  11. data/lib/abstract_controller/error.rb +6 -0
  12. data/lib/abstract_controller/helpers.rb +65 -38
  13. data/lib/abstract_controller/logger.rb +3 -2
  14. data/lib/abstract_controller/railties/routes_helpers.rb +5 -3
  15. data/lib/abstract_controller/rendering.rb +77 -129
  16. data/lib/abstract_controller/translation.rb +21 -3
  17. data/lib/abstract_controller/url_for.rb +9 -7
  18. data/lib/abstract_controller.rb +12 -13
  19. data/lib/action_controller/api/api_rendering.rb +16 -0
  20. data/lib/action_controller/api.rb +149 -0
  21. data/lib/action_controller/base.rb +81 -40
  22. data/lib/action_controller/caching.rb +22 -62
  23. data/lib/action_controller/form_builder.rb +50 -0
  24. data/lib/action_controller/log_subscriber.rb +30 -18
  25. data/lib/action_controller/metal/basic_implicit_render.rb +13 -0
  26. data/lib/action_controller/metal/conditional_get.rb +190 -47
  27. data/lib/action_controller/metal/content_security_policy.rb +52 -0
  28. data/lib/action_controller/metal/cookies.rb +3 -3
  29. data/lib/action_controller/metal/data_streaming.rb +40 -65
  30. data/lib/action_controller/metal/etag_with_flash.rb +18 -0
  31. data/lib/action_controller/metal/etag_with_template_digest.rb +57 -0
  32. data/lib/action_controller/metal/exceptions.rb +19 -12
  33. data/lib/action_controller/metal/flash.rb +42 -9
  34. data/lib/action_controller/metal/force_ssl.rb +79 -19
  35. data/lib/action_controller/metal/head.rb +35 -10
  36. data/lib/action_controller/metal/helpers.rb +31 -21
  37. data/lib/action_controller/metal/http_authentication.rb +182 -134
  38. data/lib/action_controller/metal/implicit_render.rb +62 -8
  39. data/lib/action_controller/metal/instrumentation.rb +28 -26
  40. data/lib/action_controller/metal/live.rb +312 -0
  41. data/lib/action_controller/metal/mime_responds.rb +159 -163
  42. data/lib/action_controller/metal/parameter_encoding.rb +51 -0
  43. data/lib/action_controller/metal/params_wrapper.rb +146 -93
  44. data/lib/action_controller/metal/redirecting.rb +80 -56
  45. data/lib/action_controller/metal/renderers.rb +119 -47
  46. data/lib/action_controller/metal/rendering.rb +89 -32
  47. data/lib/action_controller/metal/request_forgery_protection.rb +373 -41
  48. data/lib/action_controller/metal/rescue.rb +9 -16
  49. data/lib/action_controller/metal/streaming.rb +39 -45
  50. data/lib/action_controller/metal/strong_parameters.rb +1086 -0
  51. data/lib/action_controller/metal/testing.rb +8 -29
  52. data/lib/action_controller/metal/url_for.rb +43 -32
  53. data/lib/action_controller/metal.rb +112 -106
  54. data/lib/action_controller/railtie.rb +56 -18
  55. data/lib/action_controller/railties/helpers.rb +24 -0
  56. data/lib/action_controller/renderer.rb +117 -0
  57. data/lib/action_controller/template_assertions.rb +11 -0
  58. data/lib/action_controller/test_case.rb +402 -347
  59. data/lib/action_controller.rb +31 -30
  60. data/lib/action_dispatch/http/cache.rb +133 -34
  61. data/lib/action_dispatch/http/content_security_policy.rb +272 -0
  62. data/lib/action_dispatch/http/filter_parameters.rb +40 -24
  63. data/lib/action_dispatch/http/filter_redirect.rb +37 -0
  64. data/lib/action_dispatch/http/headers.rb +117 -16
  65. data/lib/action_dispatch/http/mime_negotiation.rb +98 -33
  66. data/lib/action_dispatch/http/mime_type.rb +198 -146
  67. data/lib/action_dispatch/http/mime_types.rb +22 -7
  68. data/lib/action_dispatch/http/parameter_filter.rb +61 -49
  69. data/lib/action_dispatch/http/parameters.rb +94 -51
  70. data/lib/action_dispatch/http/rack_cache.rb +4 -3
  71. data/lib/action_dispatch/http/request.rb +262 -117
  72. data/lib/action_dispatch/http/response.rb +400 -86
  73. data/lib/action_dispatch/http/upload.rb +66 -29
  74. data/lib/action_dispatch/http/url.rb +232 -60
  75. data/lib/action_dispatch/journey/formatter.rb +189 -0
  76. data/lib/action_dispatch/journey/gtg/builder.rb +164 -0
  77. data/lib/action_dispatch/journey/gtg/simulator.rb +41 -0
  78. data/lib/action_dispatch/journey/gtg/transition_table.rb +158 -0
  79. data/lib/action_dispatch/journey/nfa/builder.rb +78 -0
  80. data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
  81. data/lib/action_dispatch/journey/nfa/simulator.rb +49 -0
  82. data/lib/action_dispatch/journey/nfa/transition_table.rb +120 -0
  83. data/lib/action_dispatch/journey/nodes/node.rb +140 -0
  84. data/lib/action_dispatch/journey/parser.rb +199 -0
  85. data/lib/action_dispatch/journey/parser.y +50 -0
  86. data/lib/action_dispatch/journey/parser_extras.rb +31 -0
  87. data/lib/action_dispatch/journey/path/pattern.rb +199 -0
  88. data/lib/action_dispatch/journey/route.rb +203 -0
  89. data/lib/action_dispatch/journey/router/utils.rb +102 -0
  90. data/lib/action_dispatch/journey/router.rb +156 -0
  91. data/lib/action_dispatch/journey/routes.rb +82 -0
  92. data/lib/action_dispatch/journey/scanner.rb +64 -0
  93. data/lib/action_dispatch/journey/visitors.rb +268 -0
  94. data/lib/action_dispatch/journey/visualizer/fsm.css +30 -0
  95. data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
  96. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  97. data/lib/action_dispatch/journey.rb +7 -0
  98. data/lib/action_dispatch/middleware/callbacks.rb +17 -13
  99. data/lib/action_dispatch/middleware/cookies.rb +494 -162
  100. data/lib/action_dispatch/middleware/debug_exceptions.rb +176 -53
  101. data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
  102. data/lib/action_dispatch/middleware/exception_wrapper.rb +103 -38
  103. data/lib/action_dispatch/middleware/executor.rb +21 -0
  104. data/lib/action_dispatch/middleware/flash.rb +128 -91
  105. data/lib/action_dispatch/middleware/public_exceptions.rb +43 -16
  106. data/lib/action_dispatch/middleware/reloader.rb +6 -83
  107. data/lib/action_dispatch/middleware/remote_ip.rb +151 -49
  108. data/lib/action_dispatch/middleware/request_id.rb +19 -15
  109. data/lib/action_dispatch/middleware/session/abstract_store.rb +38 -34
  110. data/lib/action_dispatch/middleware/session/cache_store.rb +14 -9
  111. data/lib/action_dispatch/middleware/session/cookie_store.rb +94 -44
  112. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +15 -4
  113. data/lib/action_dispatch/middleware/show_exceptions.rb +36 -61
  114. data/lib/action_dispatch/middleware/ssl.rb +150 -0
  115. data/lib/action_dispatch/middleware/stack.rb +33 -41
  116. data/lib/action_dispatch/middleware/static.rb +92 -48
  117. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +22 -0
  118. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
  119. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +27 -0
  120. data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
  121. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +52 -0
  122. data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
  123. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +16 -0
  124. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
  125. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +21 -0
  126. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +13 -0
  127. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +134 -5
  128. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
  129. data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
  130. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +32 -0
  131. data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
  132. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
  133. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
  134. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +6 -0
  135. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
  136. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
  137. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +200 -0
  138. data/lib/action_dispatch/railtie.rb +29 -8
  139. data/lib/action_dispatch/request/session.rb +234 -0
  140. data/lib/action_dispatch/request/utils.rb +78 -0
  141. data/lib/action_dispatch/routing/endpoint.rb +17 -0
  142. data/lib/action_dispatch/routing/inspector.rb +225 -0
  143. data/lib/action_dispatch/routing/mapper.rb +1329 -582
  144. data/lib/action_dispatch/routing/polymorphic_routes.rb +237 -94
  145. data/lib/action_dispatch/routing/redirection.rb +120 -50
  146. data/lib/action_dispatch/routing/route_set.rb +545 -322
  147. data/lib/action_dispatch/routing/routes_proxy.rb +37 -7
  148. data/lib/action_dispatch/routing/url_for.rb +103 -34
  149. data/lib/action_dispatch/routing.rb +66 -99
  150. data/lib/action_dispatch/system_test_case.rb +147 -0
  151. data/lib/action_dispatch/system_testing/browser.rb +49 -0
  152. data/lib/action_dispatch/system_testing/driver.rb +59 -0
  153. data/lib/action_dispatch/system_testing/server.rb +31 -0
  154. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +96 -0
  155. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +31 -0
  156. data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +26 -0
  157. data/lib/action_dispatch/testing/assertion_response.rb +47 -0
  158. data/lib/action_dispatch/testing/assertions/response.rb +53 -42
  159. data/lib/action_dispatch/testing/assertions/routing.rb +79 -74
  160. data/lib/action_dispatch/testing/assertions.rb +15 -9
  161. data/lib/action_dispatch/testing/integration.rb +361 -207
  162. data/lib/action_dispatch/testing/request_encoder.rb +55 -0
  163. data/lib/action_dispatch/testing/test_process.rb +28 -19
  164. data/lib/action_dispatch/testing/test_request.rb +30 -33
  165. data/lib/action_dispatch/testing/test_response.rb +35 -11
  166. data/lib/action_dispatch.rb +42 -32
  167. data/lib/action_pack/gem_version.rb +17 -0
  168. data/lib/action_pack/version.rb +7 -7
  169. data/lib/action_pack.rb +4 -2
  170. metadata +116 -175
  171. data/lib/abstract_controller/layouts.rb +0 -423
  172. data/lib/abstract_controller/view_paths.rb +0 -96
  173. data/lib/action_controller/caching/actions.rb +0 -185
  174. data/lib/action_controller/caching/fragments.rb +0 -127
  175. data/lib/action_controller/caching/pages.rb +0 -187
  176. data/lib/action_controller/caching/sweeping.rb +0 -97
  177. data/lib/action_controller/deprecated/integration_test.rb +0 -2
  178. data/lib/action_controller/deprecated/performance_test.rb +0 -1
  179. data/lib/action_controller/deprecated.rb +0 -3
  180. data/lib/action_controller/metal/compatibility.rb +0 -65
  181. data/lib/action_controller/metal/hide_actions.rb +0 -41
  182. data/lib/action_controller/metal/rack_delegation.rb +0 -26
  183. data/lib/action_controller/metal/responder.rb +0 -286
  184. data/lib/action_controller/metal/session_management.rb +0 -14
  185. data/lib/action_controller/middleware.rb +0 -39
  186. data/lib/action_controller/railties/paths.rb +0 -25
  187. data/lib/action_controller/record_identifier.rb +0 -85
  188. data/lib/action_controller/vendor/html-scanner/html/document.rb +0 -68
  189. data/lib/action_controller/vendor/html-scanner/html/node.rb +0 -532
  190. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +0 -177
  191. data/lib/action_controller/vendor/html-scanner/html/selector.rb +0 -830
  192. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +0 -107
  193. data/lib/action_controller/vendor/html-scanner/html/version.rb +0 -11
  194. data/lib/action_controller/vendor/html-scanner.rb +0 -20
  195. data/lib/action_dispatch/middleware/best_standards_support.rb +0 -30
  196. data/lib/action_dispatch/middleware/body_proxy.rb +0 -30
  197. data/lib/action_dispatch/middleware/head.rb +0 -18
  198. data/lib/action_dispatch/middleware/params_parser.rb +0 -75
  199. data/lib/action_dispatch/middleware/rescue.rb +0 -26
  200. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +0 -31
  201. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +0 -26
  202. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +0 -10
  203. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +0 -2
  204. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +0 -15
  205. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +0 -17
  206. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +0 -2
  207. data/lib/action_dispatch/testing/assertions/dom.rb +0 -37
  208. data/lib/action_dispatch/testing/assertions/selector.rb +0 -435
  209. data/lib/action_dispatch/testing/assertions/tag.rb +0 -138
  210. data/lib/action_dispatch/testing/performance_test.rb +0 -10
  211. data/lib/action_view/asset_paths.rb +0 -142
  212. data/lib/action_view/base.rb +0 -220
  213. data/lib/action_view/buffers.rb +0 -43
  214. data/lib/action_view/context.rb +0 -36
  215. data/lib/action_view/flows.rb +0 -79
  216. data/lib/action_view/helpers/active_model_helper.rb +0 -50
  217. data/lib/action_view/helpers/asset_paths.rb +0 -7
  218. data/lib/action_view/helpers/asset_tag_helper.rb +0 -457
  219. data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +0 -146
  220. data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +0 -93
  221. data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +0 -193
  222. data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +0 -148
  223. data/lib/action_view/helpers/atom_feed_helper.rb +0 -200
  224. data/lib/action_view/helpers/cache_helper.rb +0 -64
  225. data/lib/action_view/helpers/capture_helper.rb +0 -203
  226. data/lib/action_view/helpers/controller_helper.rb +0 -25
  227. data/lib/action_view/helpers/csrf_helper.rb +0 -32
  228. data/lib/action_view/helpers/date_helper.rb +0 -1062
  229. data/lib/action_view/helpers/debug_helper.rb +0 -40
  230. data/lib/action_view/helpers/form_helper.rb +0 -1486
  231. data/lib/action_view/helpers/form_options_helper.rb +0 -658
  232. data/lib/action_view/helpers/form_tag_helper.rb +0 -685
  233. data/lib/action_view/helpers/javascript_helper.rb +0 -110
  234. data/lib/action_view/helpers/number_helper.rb +0 -622
  235. data/lib/action_view/helpers/output_safety_helper.rb +0 -38
  236. data/lib/action_view/helpers/record_tag_helper.rb +0 -111
  237. data/lib/action_view/helpers/rendering_helper.rb +0 -92
  238. data/lib/action_view/helpers/sanitize_helper.rb +0 -259
  239. data/lib/action_view/helpers/tag_helper.rb +0 -167
  240. data/lib/action_view/helpers/text_helper.rb +0 -426
  241. data/lib/action_view/helpers/translation_helper.rb +0 -91
  242. data/lib/action_view/helpers/url_helper.rb +0 -693
  243. data/lib/action_view/helpers.rb +0 -60
  244. data/lib/action_view/locale/en.yml +0 -160
  245. data/lib/action_view/log_subscriber.rb +0 -28
  246. data/lib/action_view/lookup_context.rb +0 -258
  247. data/lib/action_view/path_set.rb +0 -101
  248. data/lib/action_view/railtie.rb +0 -55
  249. data/lib/action_view/renderer/abstract_renderer.rb +0 -41
  250. data/lib/action_view/renderer/partial_renderer.rb +0 -415
  251. data/lib/action_view/renderer/renderer.rb +0 -61
  252. data/lib/action_view/renderer/streaming_template_renderer.rb +0 -106
  253. data/lib/action_view/renderer/template_renderer.rb +0 -95
  254. data/lib/action_view/template/error.rb +0 -128
  255. data/lib/action_view/template/handlers/builder.rb +0 -26
  256. data/lib/action_view/template/handlers/erb.rb +0 -125
  257. data/lib/action_view/template/handlers.rb +0 -50
  258. data/lib/action_view/template/resolver.rb +0 -298
  259. data/lib/action_view/template/text.rb +0 -30
  260. data/lib/action_view/template.rb +0 -337
  261. data/lib/action_view/test_case.rb +0 -246
  262. data/lib/action_view/testing/resolvers.rb +0 -49
  263. data/lib/action_view.rb +0 -84
  264. data/lib/sprockets/assets.rake +0 -99
  265. data/lib/sprockets/bootstrap.rb +0 -37
  266. data/lib/sprockets/compressors.rb +0 -83
  267. data/lib/sprockets/helpers/isolated_helper.rb +0 -13
  268. data/lib/sprockets/helpers/rails_helper.rb +0 -182
  269. data/lib/sprockets/helpers.rb +0 -6
  270. data/lib/sprockets/railtie.rb +0 -62
  271. data/lib/sprockets/static_compiler.rb +0 -56
@@ -1,75 +1,52 @@
1
- require 'stringio'
2
- require 'uri'
3
- require 'active_support/core_ext/kernel/singleton_class'
4
- require 'active_support/core_ext/object/inclusion'
5
- require 'active_support/core_ext/object/try'
6
- require 'rack/test'
7
- require 'test/unit/assertions'
1
+ # frozen_string_literal: true
2
+
3
+ require "stringio"
4
+ require "uri"
5
+ require "active_support/core_ext/kernel/singleton_class"
6
+ require "active_support/core_ext/object/try"
7
+ require "rack/test"
8
+ require "minitest"
9
+
10
+ require "action_dispatch/testing/request_encoder"
8
11
 
9
12
  module ActionDispatch
10
13
  module Integration #:nodoc:
11
14
  module RequestHelpers
12
- # Performs a GET request with the given parameters.
13
- #
14
- # - +path+: The URI (as a String) on which you want to perform a GET
15
- # request.
16
- # - +parameters+: The HTTP parameters that you want to pass. This may
17
- # be +nil+,
18
- # a Hash, or a String that is appropriately encoded
19
- # (<tt>application/x-www-form-urlencoded</tt> or
20
- # <tt>multipart/form-data</tt>).
21
- # - +headers+: Additional headers to pass, as a Hash. The headers will be
22
- # merged into the Rack env hash.
23
- #
24
- # This method returns an Response object, which one can use to
25
- # inspect the details of the response. Furthermore, if this method was
26
- # called from an ActionDispatch::IntegrationTest object, then that
27
- # object's <tt>@response</tt> instance variable will point to the same
28
- # response object.
29
- #
30
- # You can also perform POST, PUT, DELETE, and HEAD requests with +#post+,
31
- # +#put+, +#delete+, and +#head+.
32
- def get(path, parameters = nil, headers = nil)
33
- process :get, path, parameters, headers
15
+ # Performs a GET request with the given parameters. See ActionDispatch::Integration::Session#process
16
+ # for more details.
17
+ def get(path, **args)
18
+ process(:get, path, **args)
34
19
  end
35
20
 
36
- # Performs a POST request with the given parameters. See +#get+ for more
37
- # details.
38
- def post(path, parameters = nil, headers = nil)
39
- process :post, path, parameters, headers
21
+ # Performs a POST request with the given parameters. See ActionDispatch::Integration::Session#process
22
+ # for more details.
23
+ def post(path, **args)
24
+ process(:post, path, **args)
40
25
  end
41
26
 
42
- # Performs a PUT request with the given parameters. See +#get+ for more
43
- # details.
44
- def put(path, parameters = nil, headers = nil)
45
- process :put, path, parameters, headers
27
+ # Performs a PATCH request with the given parameters. See ActionDispatch::Integration::Session#process
28
+ # for more details.
29
+ def patch(path, **args)
30
+ process(:patch, path, **args)
46
31
  end
47
32
 
48
- # Performs a DELETE request with the given parameters. See +#get+ for
49
- # more details.
50
- def delete(path, parameters = nil, headers = nil)
51
- process :delete, path, parameters, headers
33
+ # Performs a PUT request with the given parameters. See ActionDispatch::Integration::Session#process
34
+ # for more details.
35
+ def put(path, **args)
36
+ process(:put, path, **args)
52
37
  end
53
38
 
54
- # Performs a HEAD request with the given parameters. See +#get+ for more
55
- # details.
56
- def head(path, parameters = nil, headers = nil)
57
- process :head, path, parameters, headers
39
+ # Performs a DELETE request with the given parameters. See ActionDispatch::Integration::Session#process
40
+ # for more details.
41
+ def delete(path, **args)
42
+ process(:delete, path, **args)
58
43
  end
59
44
 
60
- # Performs an XMLHttpRequest request with the given parameters, mirroring
61
- # a request from the Prototype library.
62
- #
63
- # The request_method is +:get+, +:post+, +:put+, +:delete+ or +:head+; the
64
- # parameters are +nil+, a hash, or a url-encoded or multipart string;
65
- # the headers are a hash.
66
- def xml_http_request(request_method, path, parameters = nil, headers = nil)
67
- headers ||= {}
68
- headers['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
69
- headers['HTTP_ACCEPT'] ||= [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ')
70
- process(request_method, path, parameters, headers)
45
+ # Performs a HEAD request with the given parameters. See ActionDispatch::Integration::Session#process
46
+ # for more details.
47
+ def head(path, *args)
48
+ process(:head, path, *args)
71
49
  end
72
- alias xhr :xml_http_request
73
50
 
74
51
  # Follow a single redirect response. If the last response was not a
75
52
  # redirect, an exception will be raised. Otherwise, the redirect is
@@ -79,40 +56,6 @@ module ActionDispatch
79
56
  get(response.location)
80
57
  status
81
58
  end
82
-
83
- # Performs a request using the specified method, following any subsequent
84
- # redirect. Note that the redirects are followed until the response is
85
- # not a redirect--this means you may run into an infinite loop if your
86
- # redirect loops back to itself.
87
- def request_via_redirect(http_method, path, parameters = nil, headers = nil)
88
- process(http_method, path, parameters, headers)
89
- follow_redirect! while redirect?
90
- status
91
- end
92
-
93
- # Performs a GET request, following any subsequent redirect.
94
- # See +request_via_redirect+ for more information.
95
- def get_via_redirect(path, parameters = nil, headers = nil)
96
- request_via_redirect(:get, path, parameters, headers)
97
- end
98
-
99
- # Performs a POST request, following any subsequent redirect.
100
- # See +request_via_redirect+ for more information.
101
- def post_via_redirect(path, parameters = nil, headers = nil)
102
- request_via_redirect(:post, path, parameters, headers)
103
- end
104
-
105
- # Performs a PUT request, following any subsequent redirect.
106
- # See +request_via_redirect+ for more information.
107
- def put_via_redirect(path, parameters = nil, headers = nil)
108
- request_via_redirect(:put, path, parameters, headers)
109
- end
110
-
111
- # Performs a DELETE request, following any subsequent redirect.
112
- # See +request_via_redirect+ for more information.
113
- def delete_via_redirect(path, parameters = nil, headers = nil)
114
- request_via_redirect(:delete, path, parameters, headers)
115
- end
116
59
  end
117
60
 
118
61
  # An instance of this class represents a set of requests and responses
@@ -126,15 +69,15 @@ module ActionDispatch
126
69
  class Session
127
70
  DEFAULT_HOST = "www.example.com"
128
71
 
129
- include Test::Unit::Assertions
72
+ include Minitest::Assertions
130
73
  include TestProcess, RequestHelpers, Assertions
131
74
 
132
75
  %w( status status_message headers body redirect? ).each do |method|
133
- delegate method, :to => :response, :allow_nil => true
76
+ delegate method, to: :response, allow_nil: true
134
77
  end
135
78
 
136
79
  %w( path ).each do |method|
137
- delegate method, :to => :request, :allow_nil => true
80
+ delegate method, to: :request, allow_nil: true
138
81
  end
139
82
 
140
83
  # The hostname used in the last request.
@@ -174,15 +117,6 @@ module ActionDispatch
174
117
  super()
175
118
  @app = app
176
119
 
177
- # If the app is a Rails app, make url_helpers available on the session
178
- # This makes app.url_for and app.foo_path available in the console
179
- if app.respond_to?(:routes)
180
- singleton_class.class_eval do
181
- include app.routes.url_helpers if app.routes.respond_to?(:url_helpers)
182
- include app.routes.mounted_helpers if app.routes.respond_to?(:mounted_helpers)
183
- end
184
- end
185
-
186
120
  reset!
187
121
  end
188
122
 
@@ -190,11 +124,11 @@ module ActionDispatch
190
124
  @url_options ||= default_url_options.dup.tap do |url_options|
191
125
  url_options.reverse_merge!(controller.url_options) if controller
192
126
 
193
- if @app.respond_to?(:routes) && @app.routes.respond_to?(:default_url_options)
127
+ if @app.respond_to?(:routes)
194
128
  url_options.reverse_merge!(@app.routes.default_url_options)
195
129
  end
196
130
 
197
- url_options.reverse_merge!(:host => host, :protocol => https? ? "https" : "http")
131
+ url_options.reverse_merge!(host: host, protocol: https? ? "https" : "http")
198
132
  end
199
133
  end
200
134
 
@@ -212,8 +146,8 @@ module ActionDispatch
212
146
 
213
147
  self.host = DEFAULT_HOST
214
148
  self.remote_addr = "127.0.0.1"
215
- self.accept = "text/xml,application/xml,application/xhtml+xml," +
216
- "text/html;q=0.9,text/plain;q=0.8,image/png," +
149
+ self.accept = "text/xml,application/xml,application/xhtml+xml," \
150
+ "text/html;q=0.9,text/plain;q=0.8,image/png," \
217
151
  "*/*;q=0.5"
218
152
 
219
153
  unless defined? @named_routes_configured
@@ -231,7 +165,7 @@ module ActionDispatch
231
165
  @https = flag
232
166
  end
233
167
 
234
- # Return +true+ if the session is mimicking a secure HTTPS request.
168
+ # Returns +true+ if the session is mimicking a secure HTTPS request.
235
169
  #
236
170
  # if session.https?
237
171
  # ...
@@ -240,96 +174,179 @@ module ActionDispatch
240
174
  @https
241
175
  end
242
176
 
243
- # Set the host name to use in the next request.
177
+ # Performs the actual request.
244
178
  #
245
- # session.host! "www.example.com"
246
- alias :host! :host=
179
+ # - +method+: The HTTP method (GET, POST, PATCH, PUT, DELETE, HEAD, OPTIONS)
180
+ # as a symbol.
181
+ # - +path+: The URI (as a String) on which you want to perform the
182
+ # request.
183
+ # - +params+: The HTTP parameters that you want to pass. This may
184
+ # be +nil+,
185
+ # a Hash, or a String that is appropriately encoded
186
+ # (<tt>application/x-www-form-urlencoded</tt> or
187
+ # <tt>multipart/form-data</tt>).
188
+ # - +headers+: Additional headers to pass, as a Hash. The headers will be
189
+ # merged into the Rack env hash.
190
+ # - +env+: Additional env to pass, as a Hash. The headers will be
191
+ # merged into the Rack env hash.
192
+ #
193
+ # This method is rarely used directly. Use +#get+, +#post+, or other standard
194
+ # HTTP methods in integration tests. +#process+ is only required when using a
195
+ # request method that doesn't have a method defined in the integration tests.
196
+ #
197
+ # This method returns the response status, after performing the request.
198
+ # Furthermore, if this method was called from an ActionDispatch::IntegrationTest object,
199
+ # then that object's <tt>@response</tt> instance variable will point to a Response object
200
+ # which one can use to inspect the details of the response.
201
+ #
202
+ # Example:
203
+ # process :get, '/author', params: { since: 201501011400 }
204
+ def process(method, path, params: nil, headers: nil, env: nil, xhr: false, as: nil)
205
+ request_encoder = RequestEncoder.encoder(as)
206
+ headers ||= {}
247
207
 
248
- private
249
- def _mock_session
250
- @_mock_session ||= Rack::MockSession.new(@app, host)
208
+ if method == :get && as == :json && params
209
+ headers["X-Http-Method-Override"] = "GET"
210
+ method = :post
251
211
  end
252
212
 
253
- # Performs the actual request.
254
- def process(method, path, parameters = nil, rack_env = nil)
255
- rack_env ||= {}
256
- if path =~ %r{://}
257
- location = URI.parse(path)
213
+ if path =~ %r{://}
214
+ path = build_expanded_path(path) do |location|
258
215
  https! URI::HTTPS === location if location.scheme
259
- host! location.host if location.host
260
- path = location.query ? "#{location.path}?#{location.query}" : location.path
261
- end
262
216
 
263
- unless ActionController::Base < ActionController::Testing
264
- ActionController::Base.class_eval do
265
- include ActionController::Testing
217
+ if url_host = location.host
218
+ default = Rack::Request::DEFAULT_PORTS[location.scheme]
219
+ url_host += ":#{location.port}" if default != location.port
220
+ host! url_host
266
221
  end
267
222
  end
223
+ end
268
224
 
269
- hostname, port = host.split(':')
225
+ hostname, port = host.split(":")
270
226
 
271
- env = {
272
- :method => method,
273
- :params => parameters,
227
+ request_env = {
228
+ :method => method,
229
+ :params => request_encoder.encode_params(params),
274
230
 
275
- "SERVER_NAME" => hostname,
276
- "SERVER_PORT" => port || (https? ? "443" : "80"),
277
- "HTTPS" => https? ? "on" : "off",
278
- "rack.url_scheme" => https? ? "https" : "http",
231
+ "SERVER_NAME" => hostname,
232
+ "SERVER_PORT" => port || (https? ? "443" : "80"),
233
+ "HTTPS" => https? ? "on" : "off",
234
+ "rack.url_scheme" => https? ? "https" : "http",
279
235
 
280
- "REQUEST_URI" => path,
281
- "HTTP_HOST" => host,
282
- "REMOTE_ADDR" => remote_addr,
283
- "CONTENT_TYPE" => "application/x-www-form-urlencoded",
284
- "HTTP_ACCEPT" => accept
285
- }
236
+ "REQUEST_URI" => path,
237
+ "HTTP_HOST" => host,
238
+ "REMOTE_ADDR" => remote_addr,
239
+ "CONTENT_TYPE" => request_encoder.content_type,
240
+ "HTTP_ACCEPT" => request_encoder.accept_header || accept
241
+ }
286
242
 
287
- session = Rack::Test::Session.new(_mock_session)
243
+ wrapped_headers = Http::Headers.from_hash({})
244
+ wrapped_headers.merge!(headers) if headers
245
+
246
+ if xhr
247
+ wrapped_headers["HTTP_X_REQUESTED_WITH"] = "XMLHttpRequest"
248
+ wrapped_headers["HTTP_ACCEPT"] ||= [Mime[:js], Mime[:html], Mime[:xml], "text/xml", "*/*"].join(", ")
249
+ end
250
+
251
+ # This modifies the passed request_env directly.
252
+ if wrapped_headers.present?
253
+ Http::Headers.from_hash(request_env).merge!(wrapped_headers)
254
+ end
255
+ if env.present?
256
+ Http::Headers.from_hash(request_env).merge!(env)
257
+ end
258
+
259
+ session = Rack::Test::Session.new(_mock_session)
260
+
261
+ # NOTE: rack-test v0.5 doesn't build a default uri correctly
262
+ # Make sure requested path is always a full URI.
263
+ session.request(build_full_uri(path, request_env), request_env)
264
+
265
+ @request_count += 1
266
+ @request = ActionDispatch::Request.new(session.last_request.env)
267
+ response = _mock_session.last_response
268
+ @response = ActionDispatch::TestResponse.from_response(response)
269
+ @response.request = @request
270
+ @html_document = nil
271
+ @url_options = nil
288
272
 
289
- env.merge!(rack_env)
273
+ @controller = @request.controller_instance
290
274
 
291
- # NOTE: rack-test v0.5 doesn't build a default uri correctly
292
- # Make sure requested path is always a full uri
293
- uri = URI.parse('/')
294
- uri.scheme ||= env['rack.url_scheme']
295
- uri.host ||= env['SERVER_NAME']
296
- uri.port ||= env['SERVER_PORT'].try(:to_i)
297
- uri += path
275
+ response.status
276
+ end
298
277
 
299
- session.request(uri.to_s, env)
278
+ # Set the host name to use in the next request.
279
+ #
280
+ # session.host! "www.example.com"
281
+ alias :host! :host=
300
282
 
301
- @request_count += 1
302
- @request = ActionDispatch::Request.new(session.last_request.env)
303
- response = _mock_session.last_response
304
- @response = ActionDispatch::TestResponse.new(response.status, response.headers, response.body)
305
- @html_document = nil
306
- @url_options = nil
283
+ private
284
+ def _mock_session
285
+ @_mock_session ||= Rack::MockSession.new(@app, host)
286
+ end
307
287
 
308
- @controller = session.last_request.env['action_controller.instance']
288
+ def build_full_uri(path, env)
289
+ "#{env['rack.url_scheme']}://#{env['SERVER_NAME']}:#{env['SERVER_PORT']}#{path}"
290
+ end
309
291
 
310
- return response.status
292
+ def build_expanded_path(path)
293
+ location = URI.parse(path)
294
+ yield location if block_given?
295
+ path = location.path
296
+ location.query ? "#{path}?#{location.query}" : path
311
297
  end
312
298
  end
313
299
 
314
300
  module Runner
315
301
  include ActionDispatch::Assertions
316
302
 
317
- def app
318
- @app ||= nil
303
+ APP_SESSIONS = {}
304
+
305
+ attr_reader :app
306
+
307
+ def initialize(*args, &blk)
308
+ super(*args, &blk)
309
+ @integration_session = nil
310
+ end
311
+
312
+ def before_setup # :nodoc:
313
+ @app = nil
314
+ super
315
+ end
316
+
317
+ def integration_session
318
+ @integration_session ||= create_session(app)
319
319
  end
320
320
 
321
321
  # Reset the current session. This is useful for testing multiple sessions
322
322
  # in a single test case.
323
323
  def reset!
324
- @integration_session = Integration::Session.new(app)
324
+ @integration_session = create_session(app)
325
+ end
326
+
327
+ def create_session(app)
328
+ klass = APP_SESSIONS[app] ||= Class.new(Integration::Session) {
329
+ # If the app is a Rails app, make url_helpers available on the session.
330
+ # This makes app.url_for and app.foo_path available in the console.
331
+ if app.respond_to?(:routes)
332
+ include app.routes.url_helpers
333
+ include app.routes.mounted_helpers
334
+ end
335
+ }
336
+ klass.new(app)
337
+ end
338
+
339
+ def remove! # :nodoc:
340
+ @integration_session = nil
325
341
  end
326
342
 
327
- %w(get post put head delete cookies assigns
328
- xml_http_request xhr get_via_redirect post_via_redirect).each do |method|
343
+ %w(get post patch put head delete cookies assigns follow_redirect!).each do |method|
329
344
  define_method(method) do |*args|
330
- reset! unless integration_session
331
- # reset the html_document variable, but only for new get/post calls
332
- @html_document = nil unless method.in?(["cookies", "assigns"])
345
+ # reset the html_document variable, except for cookies/assigns calls
346
+ unless method == "cookies" || method == "assigns"
347
+ @html_document = nil
348
+ end
349
+
333
350
  integration_session.__send__(method, *args).tap do
334
351
  copy_session_variables!
335
352
  end
@@ -346,8 +363,9 @@ module ActionDispatch
346
363
  # By default, a single session is automatically created for you, but you
347
364
  # can use this method to open multiple sessions that ought to be tested
348
365
  # simultaneously.
349
- def open_session(app = nil)
366
+ def open_session
350
367
  dup.tap do |session|
368
+ session.reset!
351
369
  yield session if block_given?
352
370
  end
353
371
  end
@@ -355,42 +373,34 @@ module ActionDispatch
355
373
  # Copy the instance variables from the current session instance into the
356
374
  # test instance.
357
375
  def copy_session_variables! #:nodoc:
358
- return unless integration_session
359
- %w(controller response request).each do |var|
360
- instance_variable_set("@#{var}", @integration_session.__send__(var))
361
- end
376
+ @controller = @integration_session.controller
377
+ @response = @integration_session.response
378
+ @request = @integration_session.request
362
379
  end
363
380
 
364
381
  def default_url_options
365
- reset! unless integration_session
366
382
  integration_session.default_url_options
367
383
  end
368
384
 
369
385
  def default_url_options=(options)
370
- integration_session.url_options
371
386
  integration_session.default_url_options = options
372
387
  end
373
388
 
374
- def respond_to?(method, include_private = false)
375
- integration_session.respond_to?(method, include_private) || super
389
+ private
390
+ def respond_to_missing?(method, _)
391
+ integration_session.respond_to?(method) || super
376
392
  end
377
393
 
378
394
  # Delegate unhandled messages to the current session instance.
379
- def method_missing(sym, *args, &block)
380
- reset! unless integration_session
381
- if integration_session.respond_to?(sym)
382
- integration_session.__send__(sym, *args, &block).tap do
395
+ def method_missing(method, *args, &block)
396
+ if integration_session.respond_to?(method)
397
+ integration_session.public_send(method, *args, &block).tap do
383
398
  copy_session_variables!
384
399
  end
385
400
  else
386
401
  super
387
402
  end
388
403
  end
389
-
390
- private
391
- def integration_session
392
- @integration_session ||= nil
393
- end
394
404
  end
395
405
  end
396
406
 
@@ -413,8 +423,8 @@ module ActionDispatch
413
423
  # assert_equal 200, status
414
424
  #
415
425
  # # post the login and follow through to the home page
416
- # post "/login", :username => people(:jamis).username,
417
- # :password => people(:jamis).password
426
+ # post "/login", params: { username: people(:jamis).username,
427
+ # password: people(:jamis).password }
418
428
  # follow_redirect!
419
429
  # assert_equal 200, status
420
430
  # assert_equal "/home", path
@@ -447,13 +457,13 @@ module ActionDispatch
447
457
  # module CustomAssertions
448
458
  # def enter(room)
449
459
  # # reference a named route, for maximum internal consistency!
450
- # get(room_url(:id => room.id))
460
+ # get(room_url(id: room.id))
451
461
  # assert(...)
452
462
  # ...
453
463
  # end
454
464
  #
455
465
  # def speak(room, message)
456
- # xml_http_request "/say/#{room.id}", :message => message
466
+ # post "/say/#{room.id}", xhr: true, params: { message: message }
457
467
  # assert(...)
458
468
  # ...
459
469
  # end
@@ -463,36 +473,180 @@ module ActionDispatch
463
473
  # open_session do |sess|
464
474
  # sess.extend(CustomAssertions)
465
475
  # who = people(who)
466
- # sess.post "/login", :username => who.username,
467
- # :password => who.password
476
+ # sess.post "/login", params: { username: who.username,
477
+ # password: who.password }
468
478
  # assert(...)
469
479
  # end
470
480
  # end
471
481
  # end
472
- class IntegrationTest < ActiveSupport::TestCase
473
- include Integration::Runner
474
- include ActionController::TemplateAssertions
475
- include ActionDispatch::Routing::UrlFor
482
+ #
483
+ # Another longer example would be:
484
+ #
485
+ # A simple integration test that exercises multiple controllers:
486
+ #
487
+ # require 'test_helper'
488
+ #
489
+ # class UserFlowsTest < ActionDispatch::IntegrationTest
490
+ # test "login and browse site" do
491
+ # # login via https
492
+ # https!
493
+ # get "/login"
494
+ # assert_response :success
495
+ #
496
+ # post "/login", params: { username: users(:david).username, password: users(:david).password }
497
+ # follow_redirect!
498
+ # assert_equal '/welcome', path
499
+ # assert_equal 'Welcome david!', flash[:notice]
500
+ #
501
+ # https!(false)
502
+ # get "/articles/all"
503
+ # assert_response :success
504
+ # assert_select 'h1', 'Articles'
505
+ # end
506
+ # end
507
+ #
508
+ # As you can see the integration test involves multiple controllers and
509
+ # exercises the entire stack from database to dispatcher. In addition you can
510
+ # have multiple session instances open simultaneously in a test and extend
511
+ # those instances with assertion methods to create a very powerful testing
512
+ # DSL (domain-specific language) just for your application.
513
+ #
514
+ # Here's an example of multiple sessions and custom DSL in an integration test
515
+ #
516
+ # require 'test_helper'
517
+ #
518
+ # class UserFlowsTest < ActionDispatch::IntegrationTest
519
+ # test "login and browse site" do
520
+ # # User david logs in
521
+ # david = login(:david)
522
+ # # User guest logs in
523
+ # guest = login(:guest)
524
+ #
525
+ # # Both are now available in different sessions
526
+ # assert_equal 'Welcome david!', david.flash[:notice]
527
+ # assert_equal 'Welcome guest!', guest.flash[:notice]
528
+ #
529
+ # # User david can browse site
530
+ # david.browses_site
531
+ # # User guest can browse site as well
532
+ # guest.browses_site
533
+ #
534
+ # # Continue with other assertions
535
+ # end
536
+ #
537
+ # private
538
+ #
539
+ # module CustomDsl
540
+ # def browses_site
541
+ # get "/products/all"
542
+ # assert_response :success
543
+ # assert_select 'h1', 'Products'
544
+ # end
545
+ # end
546
+ #
547
+ # def login(user)
548
+ # open_session do |sess|
549
+ # sess.extend(CustomDsl)
550
+ # u = users(user)
551
+ # sess.https!
552
+ # sess.post "/login", params: { username: u.username, password: u.password }
553
+ # assert_equal '/welcome', sess.path
554
+ # sess.https!(false)
555
+ # end
556
+ # end
557
+ # end
558
+ #
559
+ # See the {request helpers documentation}[rdoc-ref:ActionDispatch::Integration::RequestHelpers] for help on how to
560
+ # use +get+, etc.
561
+ #
562
+ # === Changing the request encoding
563
+ #
564
+ # You can also test your JSON API easily by setting what the request should
565
+ # be encoded as:
566
+ #
567
+ # require "test_helper"
568
+ #
569
+ # class ApiTest < ActionDispatch::IntegrationTest
570
+ # test "creates articles" do
571
+ # assert_difference -> { Article.count } do
572
+ # post articles_path, params: { article: { title: "Ahoy!" } }, as: :json
573
+ # end
574
+ #
575
+ # assert_response :success
576
+ # assert_equal({ id: Article.last.id, title: "Ahoy!" }, response.parsed_body)
577
+ # end
578
+ # end
579
+ #
580
+ # The +as+ option passes an "application/json" Accept header (thereby setting
581
+ # the request format to JSON unless overridden), sets the content type to
582
+ # "application/json" and encodes the parameters as JSON.
583
+ #
584
+ # Calling +parsed_body+ on the response parses the response body based on the
585
+ # last response MIME type.
586
+ #
587
+ # Out of the box, only <tt>:json</tt> is supported. But for any custom MIME
588
+ # types you've registered, you can add your own encoders with:
589
+ #
590
+ # ActionDispatch::IntegrationTest.register_encoder :wibble,
591
+ # param_encoder: -> params { params.to_wibble },
592
+ # response_parser: -> body { body }
593
+ #
594
+ # Where +param_encoder+ defines how the params should be encoded and
595
+ # +response_parser+ defines how the response body should be parsed through
596
+ # +parsed_body+.
597
+ #
598
+ # Consult the Rails Testing Guide for more.
476
599
 
477
- @@app = nil
600
+ class IntegrationTest < ActiveSupport::TestCase
601
+ include TestProcess::FixtureFile
478
602
 
479
- def self.app
480
- # DEPRECATE Rails application fallback
481
- # This should be set by the initializer
482
- @@app || (defined?(Rails.application) && Rails.application) || nil
603
+ module UrlOptions
604
+ extend ActiveSupport::Concern
605
+ def url_options
606
+ integration_session.url_options
607
+ end
483
608
  end
484
609
 
485
- def self.app=(app)
486
- @@app = app
487
- end
610
+ module Behavior
611
+ extend ActiveSupport::Concern
488
612
 
489
- def app
490
- super || self.class.app
491
- end
613
+ include Integration::Runner
614
+ include ActionController::TemplateAssertions
615
+
616
+ included do
617
+ include ActionDispatch::Routing::UrlFor
618
+ include UrlOptions # don't let UrlFor override the url_options method
619
+ ActiveSupport.run_load_hooks(:action_dispatch_integration_test, self)
620
+ @@app = nil
621
+ end
492
622
 
493
- def url_options
494
- reset! unless integration_session
495
- integration_session.url_options
623
+ module ClassMethods
624
+ def app
625
+ if defined?(@@app) && @@app
626
+ @@app
627
+ else
628
+ ActionDispatch.test_app
629
+ end
630
+ end
631
+
632
+ def app=(app)
633
+ @@app = app
634
+ end
635
+
636
+ def register_encoder(*args)
637
+ RequestEncoder.register_encoder(*args)
638
+ end
639
+ end
640
+
641
+ def app
642
+ super || self.class.app
643
+ end
644
+
645
+ def document_root_element
646
+ html_document.root
647
+ end
496
648
  end
649
+
650
+ include Behavior
497
651
  end
498
652
  end