actionpack 5.2.4.4 → 6.1.1

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

Potentially problematic release.


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

Files changed (155) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +264 -322
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -3
  5. data/lib/abstract_controller.rb +1 -0
  6. data/lib/abstract_controller/base.rb +38 -4
  7. data/lib/abstract_controller/caching.rb +1 -1
  8. data/lib/abstract_controller/caching/fragments.rb +6 -22
  9. data/lib/abstract_controller/callbacks.rb +14 -2
  10. data/lib/abstract_controller/collector.rb +1 -2
  11. data/lib/abstract_controller/helpers.rb +106 -90
  12. data/lib/abstract_controller/railties/routes_helpers.rb +1 -1
  13. data/lib/abstract_controller/rendering.rb +9 -9
  14. data/lib/abstract_controller/translation.rb +11 -5
  15. data/lib/action_controller.rb +7 -4
  16. data/lib/action_controller/api.rb +4 -3
  17. data/lib/action_controller/base.rb +6 -9
  18. data/lib/action_controller/caching.rb +1 -3
  19. data/lib/action_controller/log_subscriber.rb +10 -7
  20. data/lib/action_controller/metal.rb +10 -8
  21. data/lib/action_controller/metal/basic_implicit_render.rb +1 -1
  22. data/lib/action_controller/metal/conditional_get.rb +19 -5
  23. data/lib/action_controller/metal/content_security_policy.rb +1 -2
  24. data/lib/action_controller/metal/cookies.rb +3 -1
  25. data/lib/action_controller/metal/data_streaming.rb +6 -7
  26. data/lib/action_controller/metal/default_headers.rb +17 -0
  27. data/lib/action_controller/metal/etag_with_template_digest.rb +3 -5
  28. data/lib/action_controller/metal/exceptions.rb +56 -2
  29. data/lib/action_controller/metal/flash.rb +5 -5
  30. data/lib/action_controller/metal/head.rb +7 -4
  31. data/lib/action_controller/metal/helpers.rb +14 -5
  32. data/lib/action_controller/metal/http_authentication.rb +24 -23
  33. data/lib/action_controller/metal/implicit_render.rb +5 -15
  34. data/lib/action_controller/metal/instrumentation.rb +13 -14
  35. data/lib/action_controller/metal/live.rb +30 -32
  36. data/lib/action_controller/metal/logging.rb +20 -0
  37. data/lib/action_controller/metal/mime_responds.rb +19 -4
  38. data/lib/action_controller/metal/parameter_encoding.rb +35 -4
  39. data/lib/action_controller/metal/params_wrapper.rb +31 -22
  40. data/lib/action_controller/metal/permissions_policy.rb +46 -0
  41. data/lib/action_controller/metal/redirecting.rb +6 -6
  42. data/lib/action_controller/metal/renderers.rb +4 -4
  43. data/lib/action_controller/metal/rendering.rb +8 -3
  44. data/lib/action_controller/metal/request_forgery_protection.rb +62 -34
  45. data/lib/action_controller/metal/rescue.rb +1 -1
  46. data/lib/action_controller/metal/streaming.rb +0 -1
  47. data/lib/action_controller/metal/strong_parameters.rb +167 -58
  48. data/lib/action_controller/metal/url_for.rb +1 -1
  49. data/lib/action_controller/railties/helpers.rb +1 -1
  50. data/lib/action_controller/renderer.rb +37 -13
  51. data/lib/action_controller/template_assertions.rb +1 -1
  52. data/lib/action_controller/test_case.rb +70 -65
  53. data/lib/action_dispatch.rb +9 -3
  54. data/lib/action_dispatch/http/cache.rb +26 -21
  55. data/lib/action_dispatch/http/content_disposition.rb +45 -0
  56. data/lib/action_dispatch/http/content_security_policy.rb +33 -19
  57. data/lib/action_dispatch/http/filter_parameters.rb +9 -8
  58. data/lib/action_dispatch/http/filter_redirect.rb +2 -3
  59. data/lib/action_dispatch/http/headers.rb +4 -4
  60. data/lib/action_dispatch/http/mime_negotiation.rb +26 -13
  61. data/lib/action_dispatch/http/mime_type.rb +42 -23
  62. data/lib/action_dispatch/http/parameters.rb +14 -23
  63. data/lib/action_dispatch/http/permissions_policy.rb +173 -0
  64. data/lib/action_dispatch/http/request.rb +45 -22
  65. data/lib/action_dispatch/http/response.rb +45 -25
  66. data/lib/action_dispatch/http/upload.rb +9 -1
  67. data/lib/action_dispatch/http/url.rb +82 -82
  68. data/lib/action_dispatch/journey.rb +0 -2
  69. data/lib/action_dispatch/journey/formatter.rb +54 -30
  70. data/lib/action_dispatch/journey/gtg/builder.rb +22 -37
  71. data/lib/action_dispatch/journey/gtg/simulator.rb +8 -7
  72. data/lib/action_dispatch/journey/gtg/transition_table.rb +6 -5
  73. data/lib/action_dispatch/journey/nfa/dot.rb +0 -11
  74. data/lib/action_dispatch/journey/nodes/node.rb +13 -11
  75. data/lib/action_dispatch/journey/parser.rb +13 -13
  76. data/lib/action_dispatch/journey/parser.y +1 -1
  77. data/lib/action_dispatch/journey/path/pattern.rb +19 -21
  78. data/lib/action_dispatch/journey/route.rb +10 -20
  79. data/lib/action_dispatch/journey/router.rb +26 -34
  80. data/lib/action_dispatch/journey/router/utils.rb +14 -12
  81. data/lib/action_dispatch/journey/routes.rb +0 -2
  82. data/lib/action_dispatch/journey/scanner.rb +10 -4
  83. data/lib/action_dispatch/journey/visitors.rb +1 -4
  84. data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
  85. data/lib/action_dispatch/middleware/callbacks.rb +2 -4
  86. data/lib/action_dispatch/middleware/cookies.rb +128 -109
  87. data/lib/action_dispatch/middleware/debug_exceptions.rb +43 -66
  88. data/lib/action_dispatch/middleware/debug_locks.rb +5 -5
  89. data/lib/action_dispatch/middleware/debug_view.rb +66 -0
  90. data/lib/action_dispatch/middleware/exception_wrapper.rb +75 -30
  91. data/lib/action_dispatch/middleware/flash.rb +1 -1
  92. data/lib/action_dispatch/middleware/host_authorization.rb +121 -0
  93. data/lib/action_dispatch/middleware/public_exceptions.rb +6 -3
  94. data/lib/action_dispatch/middleware/remote_ip.rb +14 -16
  95. data/lib/action_dispatch/middleware/request_id.rb +5 -6
  96. data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -3
  97. data/lib/action_dispatch/middleware/session/cookie_store.rb +3 -9
  98. data/lib/action_dispatch/middleware/show_exceptions.rb +3 -2
  99. data/lib/action_dispatch/middleware/ssl.rb +20 -15
  100. data/lib/action_dispatch/middleware/stack.rb +56 -2
  101. data/lib/action_dispatch/middleware/static.rb +153 -93
  102. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
  103. data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
  104. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
  105. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +3 -1
  106. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
  107. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +4 -2
  108. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +45 -35
  109. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -0
  110. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -0
  111. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +23 -4
  112. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +1 -1
  113. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +6 -3
  114. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +3 -1
  115. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +104 -8
  116. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -0
  117. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
  118. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +2 -2
  119. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -1
  120. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +2 -2
  121. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
  122. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +24 -1
  123. data/lib/action_dispatch/railtie.rb +8 -2
  124. data/lib/action_dispatch/request/session.rb +10 -9
  125. data/lib/action_dispatch/request/utils.rb +26 -2
  126. data/lib/action_dispatch/routing.rb +21 -20
  127. data/lib/action_dispatch/routing/inspector.rb +100 -52
  128. data/lib/action_dispatch/routing/mapper.rb +155 -103
  129. data/lib/action_dispatch/routing/polymorphic_routes.rb +13 -15
  130. data/lib/action_dispatch/routing/redirection.rb +3 -3
  131. data/lib/action_dispatch/routing/route_set.rb +71 -69
  132. data/lib/action_dispatch/routing/url_for.rb +2 -2
  133. data/lib/action_dispatch/system_test_case.rb +54 -11
  134. data/lib/action_dispatch/system_testing/browser.rb +53 -16
  135. data/lib/action_dispatch/system_testing/driver.rb +11 -3
  136. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +49 -7
  137. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +8 -10
  138. data/lib/action_dispatch/testing/assertion_response.rb +0 -1
  139. data/lib/action_dispatch/testing/assertions.rb +1 -1
  140. data/lib/action_dispatch/testing/assertions/response.rb +4 -7
  141. data/lib/action_dispatch/testing/assertions/routing.rb +20 -8
  142. data/lib/action_dispatch/testing/integration.rb +61 -28
  143. data/lib/action_dispatch/testing/request_encoder.rb +2 -2
  144. data/lib/action_dispatch/testing/test_process.rb +29 -4
  145. data/lib/action_dispatch/testing/test_request.rb +3 -3
  146. data/lib/action_dispatch/testing/test_response.rb +4 -32
  147. data/lib/action_pack.rb +1 -1
  148. data/lib/action_pack/gem_version.rb +4 -4
  149. metadata +38 -26
  150. data/lib/action_controller/metal/force_ssl.rb +0 -99
  151. data/lib/action_dispatch/http/parameter_filter.rb +0 -86
  152. data/lib/action_dispatch/journey/nfa/builder.rb +0 -78
  153. data/lib/action_dispatch/journey/nfa/simulator.rb +0 -49
  154. data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -120
  155. data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +0 -26
@@ -107,6 +107,7 @@ module ActionDispatch
107
107
  @_routes = nil
108
108
  super
109
109
  end
110
+ ruby2_keywords(:initialize) if respond_to?(:ruby2_keywords, true)
110
111
 
111
112
  # Hook overridden in controller to add request information
112
113
  # with +default_url_options+. Application logic should not
@@ -133,6 +134,7 @@ module ActionDispatch
133
134
  # <tt>ActionDispatch::Http::URL.tld_length</tt>, which in turn defaults to 1.
134
135
  # * <tt>:port</tt> - Optionally specify the port to connect to.
135
136
  # * <tt>:anchor</tt> - An anchor name to be appended to the path.
137
+ # * <tt>:params</tt> - The query parameters to be appended to the path.
136
138
  # * <tt>:trailing_slash</tt> - If true, adds a trailing slash, as in "/archive/2009/"
137
139
  # * <tt>:script_name</tt> - Specifies application path relative to domain root. If provided, prepends application path.
138
140
  #
@@ -214,13 +216,11 @@ module ActionDispatch
214
216
  end
215
217
 
216
218
  protected
217
-
218
219
  def optimize_routes_generation?
219
220
  _routes.optimize_routes_generation? && default_url_options.empty?
220
221
  end
221
222
 
222
223
  private
223
-
224
224
  def _with_routes(routes) # :doc:
225
225
  old_routes, @_routes = @_routes, routes
226
226
  yield
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- gem "capybara", ">= 2.15"
3
+ gem "capybara", ">= 3.26"
4
4
 
5
5
  require "capybara/dsl"
6
6
  require "capybara/minitest"
@@ -10,7 +10,6 @@ require "action_dispatch/system_testing/browser"
10
10
  require "action_dispatch/system_testing/server"
11
11
  require "action_dispatch/system_testing/test_helpers/screenshot_helper"
12
12
  require "action_dispatch/system_testing/test_helpers/setup_and_teardown"
13
- require "action_dispatch/system_testing/test_helpers/undef_methods"
14
13
 
15
14
  module ActionDispatch
16
15
  # = System Testing
@@ -27,7 +26,7 @@ module ActionDispatch
27
26
  #
28
27
  # Here is an example system test:
29
28
  #
30
- # require 'application_system_test_case'
29
+ # require "application_system_test_case"
31
30
  #
32
31
  # class Users::CreateTest < ApplicationSystemTestCase
33
32
  # test "adding a new user" do
@@ -89,18 +88,36 @@ module ActionDispatch
89
88
  # { js_errors: true }
90
89
  # end
91
90
  #
91
+ # Some drivers require browser capabilities to be passed as a block instead
92
+ # of through the +options+ hash.
93
+ #
94
+ # As an example, if you want to add mobile emulation on chrome, you'll have to
95
+ # create an instance of selenium's +Chrome::Options+ object and add
96
+ # capabilities with a block.
97
+ #
98
+ # The block will be passed an instance of <tt><Driver>::Options</tt> where you can
99
+ # define the capabilities you want. Please refer to your driver documentation
100
+ # to learn about supported options.
101
+ #
102
+ # class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
103
+ # driven_by :selenium, using: :chrome, screen_size: [1024, 768] do |driver_option|
104
+ # driver_option.add_emulation(device_name: 'iPhone 6')
105
+ # driver_option.add_extension('path/to/chrome_extension.crx')
106
+ # end
107
+ # end
108
+ #
92
109
  # Because <tt>ActionDispatch::SystemTestCase</tt> is a shim between Capybara
93
110
  # and Rails, any driver that is supported by Capybara is supported by system
94
111
  # tests as long as you include the required gems and files.
95
- class SystemTestCase < IntegrationTest
112
+ class SystemTestCase < ActiveSupport::TestCase
96
113
  include Capybara::DSL
97
114
  include Capybara::Minitest::Assertions
98
115
  include SystemTesting::TestHelpers::SetupAndTeardown
99
116
  include SystemTesting::TestHelpers::ScreenshotHelper
100
- include SystemTesting::TestHelpers::UndefMethods
101
117
 
102
118
  def initialize(*) # :nodoc:
103
119
  super
120
+ self.class.driven_by(:selenium) unless self.class.driver?
104
121
  self.class.driver.use
105
122
  end
106
123
 
@@ -134,14 +151,40 @@ module ActionDispatch
134
151
  # driven_by :selenium, using: :firefox
135
152
  #
136
153
  # driven_by :selenium, using: :headless_firefox
137
- def self.driven_by(driver, using: :chrome, screen_size: [1400, 1400], options: {})
138
- self.driver = SystemTesting::Driver.new(driver, using: using, screen_size: screen_size, options: options)
154
+ def self.driven_by(driver, using: :chrome, screen_size: [1400, 1400], options: {}, &capabilities)
155
+ driver_options = { using: using, screen_size: screen_size, options: options }
156
+
157
+ self.driver = SystemTesting::Driver.new(driver, **driver_options, &capabilities)
139
158
  end
140
159
 
141
- driven_by :selenium
160
+ private
161
+ def url_helpers
162
+ @url_helpers ||=
163
+ if ActionDispatch.test_app
164
+ Class.new do
165
+ include ActionDispatch.test_app.routes.url_helpers
166
+ include ActionDispatch.test_app.routes.mounted_helpers
142
167
 
143
- ActiveSupport.run_load_hooks(:action_dispatch_system_test_case, self)
144
- end
168
+ def url_options
169
+ default_url_options.reverse_merge(host: Capybara.app_host || Capybara.current_session.server_url)
170
+ end
171
+ end.new
172
+ end
173
+ end
174
+
175
+ def method_missing(name, *args, &block)
176
+ if url_helpers.respond_to?(name)
177
+ url_helpers.public_send(name, *args, &block)
178
+ else
179
+ super
180
+ end
181
+ end
145
182
 
146
- SystemTestCase.start_application
183
+ def respond_to_missing?(name, include_private = false)
184
+ url_helpers.respond_to?(name)
185
+ end
186
+ end
147
187
  end
188
+
189
+ ActiveSupport.run_load_hooks :action_dispatch_system_test_case, ActionDispatch::SystemTestCase
190
+ ActionDispatch::SystemTestCase.start_application
@@ -3,10 +3,11 @@
3
3
  module ActionDispatch
4
4
  module SystemTesting
5
5
  class Browser # :nodoc:
6
- attr_reader :name
6
+ attr_reader :name, :options
7
7
 
8
8
  def initialize(name)
9
9
  @name = name
10
+ set_default_options
10
11
  end
11
12
 
12
13
  def type
@@ -20,29 +21,65 @@ module ActionDispatch
20
21
  end
21
22
  end
22
23
 
23
- def options
24
- case name
25
- when :headless_chrome
26
- headless_chrome_browser_options
27
- when :headless_firefox
28
- headless_firefox_browser_options
24
+ def configure
25
+ initialize_options
26
+ yield options if block_given? && options
27
+ end
28
+
29
+ # driver_path can be configured as a proc. The webdrivers gem uses this
30
+ # proc to update web drivers. Running this proc early allows us to only
31
+ # update the webdriver once and avoid race conditions when using
32
+ # parallel tests.
33
+ def preload
34
+ case type
35
+ when :chrome
36
+ if ::Selenium::WebDriver::Service.respond_to? :driver_path=
37
+ ::Selenium::WebDriver::Chrome::Service.driver_path&.call
38
+ else
39
+ # Selenium <= v3.141.0
40
+ ::Selenium::WebDriver::Chrome.driver_path
41
+ end
42
+ when :firefox
43
+ if ::Selenium::WebDriver::Service.respond_to? :driver_path=
44
+ ::Selenium::WebDriver::Firefox::Service.driver_path&.call
45
+ else
46
+ # Selenium <= v3.141.0
47
+ ::Selenium::WebDriver::Firefox.driver_path
48
+ end
29
49
  end
30
50
  end
31
51
 
32
52
  private
33
- def headless_chrome_browser_options
34
- options = Selenium::WebDriver::Chrome::Options.new
35
- options.args << "--headless"
36
- options.args << "--disable-gpu" if Gem.win_platform?
53
+ def initialize_options
54
+ @options ||=
55
+ case type
56
+ when :chrome
57
+ ::Selenium::WebDriver::Chrome::Options.new
58
+ when :firefox
59
+ ::Selenium::WebDriver::Firefox::Options.new
60
+ end
61
+ end
37
62
 
38
- options
63
+ def set_default_options
64
+ case name
65
+ when :headless_chrome
66
+ set_headless_chrome_browser_options
67
+ when :headless_firefox
68
+ set_headless_firefox_browser_options
69
+ end
39
70
  end
40
71
 
41
- def headless_firefox_browser_options
42
- options = Selenium::WebDriver::Firefox::Options.new
43
- options.args << "-headless"
72
+ def set_headless_chrome_browser_options
73
+ configure do |capabilities|
74
+ capabilities.add_argument("--headless")
75
+ capabilities.add_argument("--disable-gpu") if Gem.win_platform?
76
+ end
77
+ end
44
78
 
45
- options
79
+ def set_headless_firefox_browser_options
80
+ configure do |capabilities|
81
+ capabilities.add_argument("-headless")
82
+ end
46
83
  end
47
84
  end
48
85
  end
@@ -3,11 +3,17 @@
3
3
  module ActionDispatch
4
4
  module SystemTesting
5
5
  class Driver # :nodoc:
6
- def initialize(name, **options)
6
+ def initialize(name, **options, &capabilities)
7
7
  @name = name
8
8
  @browser = Browser.new(options[:using])
9
9
  @screen_size = options[:screen_size]
10
- @options = options[:options]
10
+ @options = options[:options] || {}
11
+ @capabilities = capabilities
12
+
13
+ if name == :selenium
14
+ require "selenium/webdriver"
15
+ @browser.preload
16
+ end
11
17
  end
12
18
 
13
19
  def use
@@ -22,6 +28,8 @@ module ActionDispatch
22
28
  end
23
29
 
24
30
  def register
31
+ @browser.configure(&@capabilities)
32
+
25
33
  Capybara.register_driver @name do |app|
26
34
  case @name
27
35
  when :selenium then register_selenium(app)
@@ -36,7 +44,7 @@ module ActionDispatch
36
44
  end
37
45
 
38
46
  def register_selenium(app)
39
- Capybara::Selenium::Driver.new(app, { browser: @browser.type }.merge(browser_options)).tap do |driver|
47
+ Capybara::Selenium::Driver.new(app, **{ browser: @browser.type }.merge(browser_options)).tap do |driver|
40
48
  driver.browser.manage.window.size = Selenium::WebDriver::Dimension.new(*@screen_size)
41
49
  end
42
50
  end
@@ -9,10 +9,16 @@ module ActionDispatch
9
9
  #
10
10
  # +take_screenshot+ can be used at any point in your system tests to take
11
11
  # a screenshot of the current state. This can be useful for debugging or
12
- # automating visual testing.
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)
13
15
  #
14
16
  # The screenshot will be displayed in your console, if supported.
15
17
  #
18
+ # You can set the +RAILS_SYSTEM_TESTING_SCREENSHOT_HTML+ environment variable to
19
+ # save the HTML from the page that is being screenhoted so you can investigate the
20
+ # elements on the page at the time of the screenshot
21
+ #
16
22
  # You can set the +RAILS_SYSTEM_TESTING_SCREENSHOT+ environment variable to
17
23
  # control the output. Possible values are:
18
24
  # * [+simple+ (default)] Only displays the screenshot path.
@@ -20,8 +26,10 @@ module ActionDispatch
20
26
  # * [+inline+] Display the screenshot in the terminal using the
21
27
  # iTerm image protocol (https://iterm2.com/documentation-images.html).
22
28
  # * [+artifact+] Display the screenshot in the terminal, using the terminal
23
- # artifact format (https://buildkite.github.io/terminal/inline-images/).
29
+ # artifact format (https://buildkite.github.io/terminal-to-html/inline-images/).
24
30
  def take_screenshot
31
+ increment_unique
32
+ save_html if save_html?
25
33
  save_image
26
34
  puts display_image
27
35
  end
@@ -38,16 +46,49 @@ module ActionDispatch
38
46
  end
39
47
 
40
48
  private
49
+ attr_accessor :_screenshot_counter
50
+
51
+ def save_html?
52
+ ENV["RAILS_SYSTEM_TESTING_SCREENSHOT_HTML"] == "1"
53
+ end
54
+
55
+ def increment_unique
56
+ @_screenshot_counter ||= 0
57
+ @_screenshot_counter += 1
58
+ end
59
+
60
+ def unique
61
+ failed? ? "failures" : (_screenshot_counter || 0).to_s
62
+ end
63
+
41
64
  def image_name
42
- failed? ? "failures_#{method_name}" : method_name
65
+ sanitized_method_name = method_name.tr("/\\", "--")
66
+ name = "#{unique}_#{sanitized_method_name}"
67
+ name[0...225]
43
68
  end
44
69
 
45
70
  def image_path
46
- @image_path ||= absolute_image_path.relative_path_from(Pathname.pwd).to_s
71
+ absolute_image_path.to_s
72
+ end
73
+
74
+ def html_path
75
+ absolute_html_path.to_s
76
+ end
77
+
78
+ def absolute_path
79
+ Rails.root.join("tmp/screenshots/#{image_name}")
47
80
  end
48
81
 
49
82
  def absolute_image_path
50
- Rails.root.join("tmp/screenshots/#{image_name}.png")
83
+ "#{absolute_path}.png"
84
+ end
85
+
86
+ def absolute_html_path
87
+ "#{absolute_path}.html"
88
+ end
89
+
90
+ def save_html
91
+ page.save_page(absolute_html_path)
51
92
  end
52
93
 
53
94
  def save_image
@@ -65,7 +106,8 @@ module ActionDispatch
65
106
  end
66
107
 
67
108
  def display_image
68
- message = "[Screenshot]: #{image_path}\n".dup
109
+ message = +"[Screenshot Image]: #{image_path}\n"
110
+ message << +"[Screenshot HTML]: #{html_path}\n" if save_html?
69
111
 
70
112
  case output_type
71
113
  when "artifact"
@@ -80,7 +122,7 @@ module ActionDispatch
80
122
  end
81
123
 
82
124
  def inline_base64(path)
83
- Base64.encode64(path).gsub("\n", "")
125
+ Base64.strict_encode64(path)
84
126
  end
85
127
 
86
128
  def failed?
@@ -4,24 +4,22 @@ module ActionDispatch
4
4
  module SystemTesting
5
5
  module TestHelpers
6
6
  module SetupAndTeardown # :nodoc:
7
- DEFAULT_HOST = "http://127.0.0.1"
8
-
9
7
  def host!(host)
10
- super
8
+ ActiveSupport::Deprecation.warn \
9
+ "ActionDispatch::SystemTestCase#host! is deprecated with no replacement. " \
10
+ "Set Capybara.app_host directly or rely on Capybara's default host."
11
+
11
12
  Capybara.app_host = host
12
13
  end
13
14
 
14
- def before_setup
15
- host! DEFAULT_HOST
15
+ def before_teardown
16
+ take_failed_screenshot
17
+ ensure
16
18
  super
17
19
  end
18
20
 
19
21
  def after_teardown
20
- begin
21
- take_failed_screenshot
22
- ensure
23
- Capybara.reset_sessions!
24
- end
22
+ Capybara.reset_sessions!
25
23
  ensure
26
24
  super
27
25
  end
@@ -35,7 +35,6 @@ module ActionDispatch
35
35
  end
36
36
 
37
37
  private
38
-
39
38
  def code_from_name(name)
40
39
  GENERIC_RESPONSE_CODES[name] || Rack::Utils::SYMBOL_TO_STATUS_CODE[name]
41
40
  end
@@ -14,7 +14,7 @@ module ActionDispatch
14
14
  include Rails::Dom::Testing::Assertions
15
15
 
16
16
  def html_document
17
- @html_document ||= if @response.content_type.to_s.end_with?("xml")
17
+ @html_document ||= if @response.media_type&.end_with?("xml")
18
18
  Nokogiri::XML::Document.parse(@response.body)
19
19
  else
20
20
  Nokogiri::HTML::Document.parse(@response.body)
@@ -31,15 +31,13 @@ module ActionDispatch
31
31
  message ||= generate_response_message(type)
32
32
 
33
33
  if RESPONSE_PREDICATES.keys.include?(type)
34
- assert @response.send(RESPONSE_PREDICATES[type]), message
34
+ assert @response.public_send(RESPONSE_PREDICATES[type]), message
35
35
  else
36
36
  assert_equal AssertionResponse.new(type).code, @response.response_code, message
37
37
  end
38
38
  end
39
39
 
40
- # Asserts that the redirection options passed in match those of the redirect called in the latest action.
41
- # This match can be partial, such that <tt>assert_redirected_to(controller: "weblog")</tt> will also
42
- # match the redirection of <tt>redirect_to(controller: "weblog", action: "show")</tt> and so on.
40
+ # Asserts that the response is a redirect to a URL matching the given options.
43
41
  #
44
42
  # # Asserts that the redirection was to the "index" action on the WeblogController
45
43
  # assert_redirected_to controller: "weblog", action: "index"
@@ -79,9 +77,8 @@ module ActionDispatch
79
77
  end
80
78
 
81
79
  def generate_response_message(expected, actual = @response.response_code)
82
- "Expected response to be a <#{code_with_name(expected)}>,"\
83
- " but was a <#{code_with_name(actual)}>"
84
- .dup.concat(location_if_redirected).concat(response_body_if_short)
80
+ (+"Expected response to be a <#{code_with_name(expected)}>,"\
81
+ " but was a <#{code_with_name(actual)}>").concat(location_if_redirected).concat(response_body_if_short)
85
82
  end
86
83
 
87
84
  def response_body_if_short