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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +264 -322
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -3
- data/lib/abstract_controller.rb +1 -0
- data/lib/abstract_controller/base.rb +38 -4
- data/lib/abstract_controller/caching.rb +1 -1
- data/lib/abstract_controller/caching/fragments.rb +6 -22
- data/lib/abstract_controller/callbacks.rb +14 -2
- data/lib/abstract_controller/collector.rb +1 -2
- data/lib/abstract_controller/helpers.rb +106 -90
- data/lib/abstract_controller/railties/routes_helpers.rb +1 -1
- data/lib/abstract_controller/rendering.rb +9 -9
- data/lib/abstract_controller/translation.rb +11 -5
- data/lib/action_controller.rb +7 -4
- data/lib/action_controller/api.rb +4 -3
- data/lib/action_controller/base.rb +6 -9
- data/lib/action_controller/caching.rb +1 -3
- data/lib/action_controller/log_subscriber.rb +10 -7
- data/lib/action_controller/metal.rb +10 -8
- data/lib/action_controller/metal/basic_implicit_render.rb +1 -1
- data/lib/action_controller/metal/conditional_get.rb +19 -5
- data/lib/action_controller/metal/content_security_policy.rb +1 -2
- data/lib/action_controller/metal/cookies.rb +3 -1
- data/lib/action_controller/metal/data_streaming.rb +6 -7
- data/lib/action_controller/metal/default_headers.rb +17 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +3 -5
- data/lib/action_controller/metal/exceptions.rb +56 -2
- data/lib/action_controller/metal/flash.rb +5 -5
- data/lib/action_controller/metal/head.rb +7 -4
- data/lib/action_controller/metal/helpers.rb +14 -5
- data/lib/action_controller/metal/http_authentication.rb +24 -23
- data/lib/action_controller/metal/implicit_render.rb +5 -15
- data/lib/action_controller/metal/instrumentation.rb +13 -14
- data/lib/action_controller/metal/live.rb +30 -32
- data/lib/action_controller/metal/logging.rb +20 -0
- data/lib/action_controller/metal/mime_responds.rb +19 -4
- data/lib/action_controller/metal/parameter_encoding.rb +35 -4
- data/lib/action_controller/metal/params_wrapper.rb +31 -22
- data/lib/action_controller/metal/permissions_policy.rb +46 -0
- data/lib/action_controller/metal/redirecting.rb +6 -6
- data/lib/action_controller/metal/renderers.rb +4 -4
- data/lib/action_controller/metal/rendering.rb +8 -3
- data/lib/action_controller/metal/request_forgery_protection.rb +62 -34
- data/lib/action_controller/metal/rescue.rb +1 -1
- data/lib/action_controller/metal/streaming.rb +0 -1
- data/lib/action_controller/metal/strong_parameters.rb +167 -58
- data/lib/action_controller/metal/url_for.rb +1 -1
- data/lib/action_controller/railties/helpers.rb +1 -1
- data/lib/action_controller/renderer.rb +37 -13
- data/lib/action_controller/template_assertions.rb +1 -1
- data/lib/action_controller/test_case.rb +70 -65
- data/lib/action_dispatch.rb +9 -3
- data/lib/action_dispatch/http/cache.rb +26 -21
- data/lib/action_dispatch/http/content_disposition.rb +45 -0
- data/lib/action_dispatch/http/content_security_policy.rb +33 -19
- data/lib/action_dispatch/http/filter_parameters.rb +9 -8
- data/lib/action_dispatch/http/filter_redirect.rb +2 -3
- data/lib/action_dispatch/http/headers.rb +4 -4
- data/lib/action_dispatch/http/mime_negotiation.rb +26 -13
- data/lib/action_dispatch/http/mime_type.rb +42 -23
- data/lib/action_dispatch/http/parameters.rb +14 -23
- data/lib/action_dispatch/http/permissions_policy.rb +173 -0
- data/lib/action_dispatch/http/request.rb +45 -22
- data/lib/action_dispatch/http/response.rb +45 -25
- data/lib/action_dispatch/http/upload.rb +9 -1
- data/lib/action_dispatch/http/url.rb +82 -82
- data/lib/action_dispatch/journey.rb +0 -2
- data/lib/action_dispatch/journey/formatter.rb +54 -30
- data/lib/action_dispatch/journey/gtg/builder.rb +22 -37
- data/lib/action_dispatch/journey/gtg/simulator.rb +8 -7
- data/lib/action_dispatch/journey/gtg/transition_table.rb +6 -5
- data/lib/action_dispatch/journey/nfa/dot.rb +0 -11
- data/lib/action_dispatch/journey/nodes/node.rb +13 -11
- data/lib/action_dispatch/journey/parser.rb +13 -13
- data/lib/action_dispatch/journey/parser.y +1 -1
- data/lib/action_dispatch/journey/path/pattern.rb +19 -21
- data/lib/action_dispatch/journey/route.rb +10 -20
- data/lib/action_dispatch/journey/router.rb +26 -34
- data/lib/action_dispatch/journey/router/utils.rb +14 -12
- data/lib/action_dispatch/journey/routes.rb +0 -2
- data/lib/action_dispatch/journey/scanner.rb +10 -4
- data/lib/action_dispatch/journey/visitors.rb +1 -4
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
- data/lib/action_dispatch/middleware/callbacks.rb +2 -4
- data/lib/action_dispatch/middleware/cookies.rb +128 -109
- data/lib/action_dispatch/middleware/debug_exceptions.rb +43 -66
- data/lib/action_dispatch/middleware/debug_locks.rb +5 -5
- data/lib/action_dispatch/middleware/debug_view.rb +66 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +75 -30
- data/lib/action_dispatch/middleware/flash.rb +1 -1
- data/lib/action_dispatch/middleware/host_authorization.rb +121 -0
- data/lib/action_dispatch/middleware/public_exceptions.rb +6 -3
- data/lib/action_dispatch/middleware/remote_ip.rb +14 -16
- data/lib/action_dispatch/middleware/request_id.rb +5 -6
- data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -3
- data/lib/action_dispatch/middleware/session/cookie_store.rb +3 -9
- data/lib/action_dispatch/middleware/show_exceptions.rb +3 -2
- data/lib/action_dispatch/middleware/ssl.rb +20 -15
- data/lib/action_dispatch/middleware/stack.rb +56 -2
- data/lib/action_dispatch/middleware/static.rb +153 -93
- data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
- data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +3 -1
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +4 -2
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +45 -35
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -0
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +23 -4
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +6 -3
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +3 -1
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +104 -8
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +24 -1
- data/lib/action_dispatch/railtie.rb +8 -2
- data/lib/action_dispatch/request/session.rb +10 -9
- data/lib/action_dispatch/request/utils.rb +26 -2
- data/lib/action_dispatch/routing.rb +21 -20
- data/lib/action_dispatch/routing/inspector.rb +100 -52
- data/lib/action_dispatch/routing/mapper.rb +155 -103
- data/lib/action_dispatch/routing/polymorphic_routes.rb +13 -15
- data/lib/action_dispatch/routing/redirection.rb +3 -3
- data/lib/action_dispatch/routing/route_set.rb +71 -69
- data/lib/action_dispatch/routing/url_for.rb +2 -2
- data/lib/action_dispatch/system_test_case.rb +54 -11
- data/lib/action_dispatch/system_testing/browser.rb +53 -16
- data/lib/action_dispatch/system_testing/driver.rb +11 -3
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +49 -7
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +8 -10
- data/lib/action_dispatch/testing/assertion_response.rb +0 -1
- data/lib/action_dispatch/testing/assertions.rb +1 -1
- data/lib/action_dispatch/testing/assertions/response.rb +4 -7
- data/lib/action_dispatch/testing/assertions/routing.rb +20 -8
- data/lib/action_dispatch/testing/integration.rb +61 -28
- data/lib/action_dispatch/testing/request_encoder.rb +2 -2
- data/lib/action_dispatch/testing/test_process.rb +29 -4
- data/lib/action_dispatch/testing/test_request.rb +3 -3
- data/lib/action_dispatch/testing/test_response.rb +4 -32
- data/lib/action_pack.rb +1 -1
- data/lib/action_pack/gem_version.rb +4 -4
- metadata +38 -26
- data/lib/action_controller/metal/force_ssl.rb +0 -99
- data/lib/action_dispatch/http/parameter_filter.rb +0 -86
- data/lib/action_dispatch/journey/nfa/builder.rb +0 -78
- data/lib/action_dispatch/journey/nfa/simulator.rb +0 -49
- data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -120
- 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", ">=
|
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
|
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 <
|
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
|
-
|
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
|
-
|
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
|
-
|
144
|
-
|
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
|
-
|
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
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
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
|
34
|
-
options
|
35
|
-
|
36
|
-
|
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
|
-
|
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
|
42
|
-
|
43
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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"
|
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.
|
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
|
-
|
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
|
15
|
-
|
15
|
+
def before_teardown
|
16
|
+
take_failed_screenshot
|
17
|
+
ensure
|
16
18
|
super
|
17
19
|
end
|
18
20
|
|
19
21
|
def after_teardown
|
20
|
-
|
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
|
@@ -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.
|
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.
|
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
|
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
|