actionpack 7.1.5.1 → 8.1.2
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +308 -523
- data/README.rdoc +1 -1
- data/lib/abstract_controller/asset_paths.rb +6 -2
- data/lib/abstract_controller/base.rb +104 -105
- data/lib/abstract_controller/caching/fragments.rb +50 -53
- data/lib/abstract_controller/caching.rb +8 -3
- data/lib/abstract_controller/callbacks.rb +70 -62
- data/lib/abstract_controller/collector.rb +7 -7
- data/lib/abstract_controller/deprecator.rb +2 -0
- data/lib/abstract_controller/error.rb +2 -0
- data/lib/abstract_controller/helpers.rb +71 -84
- data/lib/abstract_controller/logger.rb +4 -1
- data/lib/abstract_controller/railties/routes_helpers.rb +2 -0
- data/lib/abstract_controller/rendering.rb +13 -13
- data/lib/abstract_controller/translation.rb +12 -13
- data/lib/abstract_controller/url_for.rb +8 -6
- data/lib/abstract_controller.rb +2 -0
- data/lib/action_controller/api/api_rendering.rb +2 -0
- data/lib/action_controller/api.rb +76 -72
- data/lib/action_controller/base.rb +199 -126
- data/lib/action_controller/caching.rb +16 -14
- data/lib/action_controller/deprecator.rb +2 -0
- data/lib/action_controller/form_builder.rb +21 -18
- data/lib/action_controller/log_subscriber.rb +23 -2
- data/lib/action_controller/metal/allow_browser.rb +133 -0
- data/lib/action_controller/metal/basic_implicit_render.rb +2 -0
- data/lib/action_controller/metal/conditional_get.rb +217 -175
- data/lib/action_controller/metal/content_security_policy.rb +25 -24
- data/lib/action_controller/metal/cookies.rb +4 -2
- data/lib/action_controller/metal/data_streaming.rb +72 -63
- data/lib/action_controller/metal/default_headers.rb +5 -3
- data/lib/action_controller/metal/etag_with_flash.rb +3 -1
- data/lib/action_controller/metal/etag_with_template_digest.rb +17 -15
- data/lib/action_controller/metal/exceptions.rb +16 -9
- data/lib/action_controller/metal/flash.rb +13 -14
- data/lib/action_controller/metal/head.rb +15 -11
- data/lib/action_controller/metal/helpers.rb +63 -55
- data/lib/action_controller/metal/http_authentication.rb +209 -201
- data/lib/action_controller/metal/implicit_render.rb +17 -15
- data/lib/action_controller/metal/instrumentation.rb +16 -14
- data/lib/action_controller/metal/live.rb +177 -128
- data/lib/action_controller/metal/logging.rb +6 -4
- data/lib/action_controller/metal/mime_responds.rb +151 -142
- data/lib/action_controller/metal/parameter_encoding.rb +34 -32
- data/lib/action_controller/metal/params_wrapper.rb +57 -59
- data/lib/action_controller/metal/permissions_policy.rb +22 -12
- data/lib/action_controller/metal/rate_limiting.rb +92 -0
- data/lib/action_controller/metal/redirecting.rb +213 -94
- data/lib/action_controller/metal/renderers.rb +78 -57
- data/lib/action_controller/metal/rendering.rb +111 -77
- data/lib/action_controller/metal/request_forgery_protection.rb +182 -143
- data/lib/action_controller/metal/rescue.rb +20 -9
- data/lib/action_controller/metal/streaming.rb +118 -195
- data/lib/action_controller/metal/strong_parameters.rb +720 -530
- data/lib/action_controller/metal/testing.rb +2 -0
- data/lib/action_controller/metal/url_for.rb +17 -15
- data/lib/action_controller/metal.rb +86 -60
- data/lib/action_controller/railtie.rb +36 -15
- data/lib/action_controller/railties/helpers.rb +2 -0
- data/lib/action_controller/renderer.rb +41 -36
- data/lib/action_controller/structured_event_subscriber.rb +116 -0
- data/lib/action_controller/template_assertions.rb +4 -2
- data/lib/action_controller/test_case.rb +160 -131
- data/lib/action_controller.rb +5 -1
- data/lib/action_dispatch/constants.rb +8 -0
- data/lib/action_dispatch/deprecator.rb +2 -0
- data/lib/action_dispatch/http/cache.rb +163 -35
- data/lib/action_dispatch/http/content_disposition.rb +2 -0
- data/lib/action_dispatch/http/content_security_policy.rb +54 -39
- data/lib/action_dispatch/http/filter_parameters.rb +14 -8
- data/lib/action_dispatch/http/filter_redirect.rb +22 -1
- data/lib/action_dispatch/http/headers.rb +22 -22
- data/lib/action_dispatch/http/mime_negotiation.rb +89 -41
- data/lib/action_dispatch/http/mime_type.rb +25 -21
- data/lib/action_dispatch/http/mime_types.rb +3 -0
- data/lib/action_dispatch/http/param_builder.rb +187 -0
- data/lib/action_dispatch/http/param_error.rb +26 -0
- data/lib/action_dispatch/http/parameters.rb +14 -12
- data/lib/action_dispatch/http/permissions_policy.rb +25 -36
- data/lib/action_dispatch/http/query_parser.rb +55 -0
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +141 -92
- data/lib/action_dispatch/http/response.rb +137 -77
- data/lib/action_dispatch/http/upload.rb +18 -16
- data/lib/action_dispatch/http/url.rb +187 -89
- data/lib/action_dispatch/journey/formatter.rb +21 -9
- data/lib/action_dispatch/journey/gtg/builder.rb +4 -3
- data/lib/action_dispatch/journey/gtg/simulator.rb +34 -11
- data/lib/action_dispatch/journey/gtg/transition_table.rb +47 -53
- data/lib/action_dispatch/journey/nfa/dot.rb +2 -0
- data/lib/action_dispatch/journey/nodes/node.rb +8 -6
- data/lib/action_dispatch/journey/parser.rb +99 -195
- data/lib/action_dispatch/journey/path/pattern.rb +4 -1
- data/lib/action_dispatch/journey/route.rb +54 -38
- data/lib/action_dispatch/journey/router/utils.rb +22 -27
- data/lib/action_dispatch/journey/router.rb +63 -83
- data/lib/action_dispatch/journey/routes.rb +11 -2
- data/lib/action_dispatch/journey/scanner.rb +46 -42
- data/lib/action_dispatch/journey/visitors.rb +57 -23
- data/lib/action_dispatch/journey/visualizer/fsm.js +4 -6
- data/lib/action_dispatch/journey.rb +2 -0
- data/lib/action_dispatch/log_subscriber.rb +7 -1
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +2 -0
- data/lib/action_dispatch/middleware/assume_ssl.rb +8 -5
- data/lib/action_dispatch/middleware/callbacks.rb +3 -1
- data/lib/action_dispatch/middleware/cookies.rb +125 -106
- data/lib/action_dispatch/middleware/debug_exceptions.rb +37 -8
- data/lib/action_dispatch/middleware/debug_locks.rb +15 -13
- data/lib/action_dispatch/middleware/debug_view.rb +13 -5
- data/lib/action_dispatch/middleware/exception_wrapper.rb +18 -23
- data/lib/action_dispatch/middleware/executor.rb +19 -4
- data/lib/action_dispatch/middleware/flash.rb +63 -51
- data/lib/action_dispatch/middleware/host_authorization.rb +17 -15
- data/lib/action_dispatch/middleware/public_exceptions.rb +14 -12
- data/lib/action_dispatch/middleware/reloader.rb +5 -3
- data/lib/action_dispatch/middleware/remote_ip.rb +87 -77
- data/lib/action_dispatch/middleware/request_id.rb +16 -10
- data/lib/action_dispatch/middleware/server_timing.rb +4 -2
- data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -0
- data/lib/action_dispatch/middleware/session/cache_store.rb +30 -8
- data/lib/action_dispatch/middleware/session/cookie_store.rb +27 -26
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +7 -3
- data/lib/action_dispatch/middleware/show_exceptions.rb +16 -16
- data/lib/action_dispatch/middleware/ssl.rb +53 -40
- data/lib/action_dispatch/middleware/stack.rb +11 -10
- data/lib/action_dispatch/middleware/static.rb +33 -31
- data/lib/action_dispatch/middleware/templates/rescues/_copy_button.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +3 -5
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +9 -5
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +4 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +50 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +1 -1
- data/lib/action_dispatch/railtie.rb +23 -3
- data/lib/action_dispatch/request/session.rb +24 -21
- data/lib/action_dispatch/request/utils.rb +11 -3
- data/lib/action_dispatch/routing/endpoint.rb +2 -0
- data/lib/action_dispatch/routing/inspector.rb +85 -60
- data/lib/action_dispatch/routing/mapper.rb +1031 -851
- data/lib/action_dispatch/routing/polymorphic_routes.rb +69 -62
- data/lib/action_dispatch/routing/redirection.rb +47 -39
- data/lib/action_dispatch/routing/route_set.rb +79 -56
- data/lib/action_dispatch/routing/routes_proxy.rb +7 -4
- data/lib/action_dispatch/routing/url_for.rb +130 -125
- data/lib/action_dispatch/routing.rb +150 -148
- data/lib/action_dispatch/structured_event_subscriber.rb +20 -0
- data/lib/action_dispatch/system_test_case.rb +91 -81
- data/lib/action_dispatch/system_testing/browser.rb +16 -23
- data/lib/action_dispatch/system_testing/driver.rb +2 -0
- data/lib/action_dispatch/system_testing/server.rb +2 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +34 -23
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +2 -0
- data/lib/action_dispatch/testing/assertion_response.rb +9 -7
- data/lib/action_dispatch/testing/assertions/response.rb +52 -25
- data/lib/action_dispatch/testing/assertions/routing.rb +168 -87
- data/lib/action_dispatch/testing/assertions.rb +2 -0
- data/lib/action_dispatch/testing/integration.rb +233 -223
- data/lib/action_dispatch/testing/request_encoder.rb +11 -9
- data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
- data/lib/action_dispatch/testing/test_process.rb +11 -8
- data/lib/action_dispatch/testing/test_request.rb +3 -1
- data/lib/action_dispatch/testing/test_response.rb +27 -26
- data/lib/action_dispatch.rb +36 -32
- data/lib/action_pack/gem_version.rb +6 -4
- data/lib/action_pack/version.rb +3 -1
- data/lib/action_pack.rb +17 -16
- metadata +36 -32
- data/lib/action_dispatch/journey/parser.y +0 -50
- data/lib/action_dispatch/journey/parser_extras.rb +0 -31
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
gem "capybara", ">= 3.26"
|
|
4
6
|
|
|
5
7
|
require "capybara/dsl"
|
|
@@ -12,103 +14,103 @@ require "action_dispatch/system_testing/test_helpers/screenshot_helper"
|
|
|
12
14
|
require "action_dispatch/system_testing/test_helpers/setup_and_teardown"
|
|
13
15
|
|
|
14
16
|
module ActionDispatch
|
|
15
|
-
#
|
|
17
|
+
# # System Testing
|
|
16
18
|
#
|
|
17
|
-
# System tests let you test applications in the browser. Because system
|
|
18
|
-
#
|
|
19
|
-
#
|
|
19
|
+
# System tests let you test applications in the browser. Because system tests
|
|
20
|
+
# use a real browser experience, you can test all of your JavaScript easily from
|
|
21
|
+
# your test suite.
|
|
20
22
|
#
|
|
21
|
-
# To create a system test in your application, extend your test class
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
# application or scaffold.
|
|
23
|
+
# To create a system test in your application, extend your test class from
|
|
24
|
+
# `ApplicationSystemTestCase`. System tests use Capybara as a base and allow you
|
|
25
|
+
# to configure the settings through the `application_system_test_case.rb` file,
|
|
26
|
+
# which is created when you generate your first system test.
|
|
26
27
|
#
|
|
27
28
|
# Here is an example system test:
|
|
28
29
|
#
|
|
29
|
-
#
|
|
30
|
+
# require "application_system_test_case"
|
|
30
31
|
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
32
|
+
# class Users::CreateTest < ApplicationSystemTestCase
|
|
33
|
+
# test "adding a new user" do
|
|
34
|
+
# visit users_path
|
|
35
|
+
# click_on 'New User'
|
|
35
36
|
#
|
|
36
|
-
#
|
|
37
|
-
#
|
|
37
|
+
# fill_in 'Name', with: 'Arya'
|
|
38
|
+
# click_on 'Create User'
|
|
38
39
|
#
|
|
39
|
-
#
|
|
40
|
+
# assert_text 'Arya'
|
|
41
|
+
# end
|
|
40
42
|
# end
|
|
41
|
-
# end
|
|
42
43
|
#
|
|
43
|
-
# When generating
|
|
44
|
-
# file will also be generated containing the
|
|
45
|
-
# This is where you can change the driver, add
|
|
46
|
-
# configuration for your system tests.
|
|
44
|
+
# When generating system tests, an
|
|
45
|
+
# `application_system_test_case.rb` file will also be generated containing the
|
|
46
|
+
# base class for system testing. This is where you can change the driver, add
|
|
47
|
+
# Capybara settings, and other configuration for your system tests.
|
|
47
48
|
#
|
|
48
|
-
#
|
|
49
|
+
# require "test_helper"
|
|
49
50
|
#
|
|
50
|
-
#
|
|
51
|
-
#
|
|
52
|
-
#
|
|
51
|
+
# class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
|
|
52
|
+
# driven_by :selenium, using: :chrome, screen_size: [1400, 1400]
|
|
53
|
+
# end
|
|
53
54
|
#
|
|
54
|
-
# By default,
|
|
55
|
-
#
|
|
55
|
+
# By default, `ActionDispatch::SystemTestCase` is driven by the Selenium driver,
|
|
56
|
+
# with the Chrome browser, and a browser size of 1400x1400.
|
|
56
57
|
#
|
|
57
58
|
# Changing the driver configuration options is easy. Let's say you want to use
|
|
58
|
-
# the Firefox browser instead of Chrome. In your
|
|
59
|
-
# file add the following:
|
|
60
|
-
#
|
|
61
|
-
# require "test_helper"
|
|
59
|
+
# the Firefox browser instead of Chrome. In your
|
|
60
|
+
# `application_system_test_case.rb` file add the following:
|
|
62
61
|
#
|
|
63
|
-
#
|
|
64
|
-
# driven_by :selenium, using: :firefox
|
|
65
|
-
# end
|
|
62
|
+
# require "test_helper"
|
|
66
63
|
#
|
|
67
|
-
#
|
|
68
|
-
#
|
|
69
|
-
#
|
|
70
|
-
# headless drivers and will be silently ignored if passed.
|
|
71
|
-
#
|
|
72
|
-
# Headless browsers such as headless Chrome and headless Firefox are also supported.
|
|
73
|
-
# You can use these browsers by setting the +:using+ argument to +:headless_chrome+ or +:headless_firefox+.
|
|
64
|
+
# class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
|
|
65
|
+
# driven_by :selenium, using: :firefox
|
|
66
|
+
# end
|
|
74
67
|
#
|
|
75
|
-
#
|
|
76
|
-
#
|
|
77
|
-
#
|
|
78
|
-
#
|
|
79
|
-
#
|
|
80
|
-
#
|
|
68
|
+
# `driven_by` has a required argument for the driver name. The keyword arguments
|
|
69
|
+
# are `:using` for the browser and `:screen_size` to change the size of the
|
|
70
|
+
# browser screen. These two options are not applicable for headless drivers and
|
|
71
|
+
# will be silently ignored if passed.
|
|
72
|
+
#
|
|
73
|
+
# Headless browsers such as headless Chrome and headless Firefox are also
|
|
74
|
+
# supported. You can use these browsers by setting the `:using` argument to
|
|
75
|
+
# `:headless_chrome` or `:headless_firefox`.
|
|
76
|
+
#
|
|
77
|
+
# To use a headless driver, like Cuprite, update your Gemfile to use Cuprite
|
|
78
|
+
# instead of Selenium and then declare the driver name in the
|
|
79
|
+
# `application_system_test_case.rb` file. In this case, you would leave out the
|
|
80
|
+
# `:using` option because the driver is headless, but you can still use
|
|
81
|
+
# `:screen_size` to change the size of the browser screen, also you can use
|
|
82
|
+
# `:options` to pass options supported by the driver. Please refer to your
|
|
81
83
|
# driver documentation to learn about supported options.
|
|
82
84
|
#
|
|
83
|
-
#
|
|
84
|
-
#
|
|
85
|
+
# require "test_helper"
|
|
86
|
+
# require "capybara/cuprite"
|
|
85
87
|
#
|
|
86
|
-
#
|
|
87
|
-
#
|
|
88
|
-
#
|
|
89
|
-
#
|
|
88
|
+
# class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
|
|
89
|
+
# driven_by :cuprite, screen_size: [1400, 1400], options:
|
|
90
|
+
# { js_errors: true }
|
|
91
|
+
# end
|
|
90
92
|
#
|
|
91
|
-
# Some drivers require browser capabilities to be passed as a block instead
|
|
92
|
-
#
|
|
93
|
+
# Some drivers require browser capabilities to be passed as a block instead of
|
|
94
|
+
# through the `options` hash.
|
|
93
95
|
#
|
|
94
96
|
# As an example, if you want to add mobile emulation on chrome, you'll have to
|
|
95
|
-
# create an instance of selenium's
|
|
96
|
-
#
|
|
97
|
-
#
|
|
98
|
-
# The block will be passed an instance of
|
|
99
|
-
# define the capabilities you want. Please refer to your driver documentation
|
|
100
|
-
#
|
|
101
|
-
#
|
|
102
|
-
#
|
|
103
|
-
#
|
|
104
|
-
#
|
|
105
|
-
#
|
|
97
|
+
# create an instance of selenium's `Chrome::Options` object and add capabilities
|
|
98
|
+
# with a block.
|
|
99
|
+
#
|
|
100
|
+
# The block will be passed an instance of `<Driver>::Options` where you can
|
|
101
|
+
# define the capabilities you want. Please refer to your driver documentation to
|
|
102
|
+
# learn about supported options.
|
|
103
|
+
#
|
|
104
|
+
# class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
|
|
105
|
+
# driven_by :selenium, using: :chrome, screen_size: [1024, 768] do |driver_option|
|
|
106
|
+
# driver_option.add_emulation(device_name: 'iPhone 6')
|
|
107
|
+
# driver_option.add_extension('path/to/chrome_extension.crx')
|
|
108
|
+
# end
|
|
106
109
|
# end
|
|
107
|
-
# end
|
|
108
110
|
#
|
|
109
|
-
# Because
|
|
110
|
-
#
|
|
111
|
-
#
|
|
111
|
+
# Because `ActionDispatch::SystemTestCase` is a shim between Capybara and Rails,
|
|
112
|
+
# any driver that is supported by Capybara is supported by system tests as long
|
|
113
|
+
# as you include the required gems and files.
|
|
112
114
|
class SystemTestCase < ActiveSupport::TestCase
|
|
113
115
|
include Capybara::DSL
|
|
114
116
|
include Capybara::Minitest::Assertions
|
|
@@ -137,28 +139,36 @@ module ActionDispatch
|
|
|
137
139
|
|
|
138
140
|
# System Test configuration options
|
|
139
141
|
#
|
|
140
|
-
# The default settings are Selenium, using Chrome, with a screen size
|
|
141
|
-
#
|
|
142
|
+
# The default settings are Selenium, using Chrome, with a screen size of
|
|
143
|
+
# 1400x1400.
|
|
142
144
|
#
|
|
143
145
|
# Examples:
|
|
144
146
|
#
|
|
145
|
-
#
|
|
147
|
+
# driven_by :cuprite
|
|
146
148
|
#
|
|
147
|
-
#
|
|
149
|
+
# driven_by :selenium, screen_size: [800, 800]
|
|
148
150
|
#
|
|
149
|
-
#
|
|
151
|
+
# driven_by :selenium, using: :chrome
|
|
150
152
|
#
|
|
151
|
-
#
|
|
153
|
+
# driven_by :selenium, using: :headless_chrome
|
|
152
154
|
#
|
|
153
|
-
#
|
|
155
|
+
# driven_by :selenium, using: :firefox
|
|
154
156
|
#
|
|
155
|
-
#
|
|
157
|
+
# driven_by :selenium, using: :headless_firefox
|
|
156
158
|
def self.driven_by(driver, using: :chrome, screen_size: [1400, 1400], options: {}, &capabilities)
|
|
157
159
|
driver_options = { using: using, screen_size: screen_size, options: options }
|
|
158
160
|
|
|
159
161
|
self.driver = SystemTesting::Driver.new(driver, **driver_options, &capabilities)
|
|
160
162
|
end
|
|
161
163
|
|
|
164
|
+
# Configuration for the System Test application server.
|
|
165
|
+
#
|
|
166
|
+
# By default this is localhost. This method allows the host and port to be specified manually.
|
|
167
|
+
def self.served_by(host:, port:)
|
|
168
|
+
Capybara.server_host = host
|
|
169
|
+
Capybara.server_port = port
|
|
170
|
+
end
|
|
171
|
+
|
|
162
172
|
private
|
|
163
173
|
def url_helpers
|
|
164
174
|
@url_helpers ||=
|
|
@@ -178,9 +188,9 @@ module ActionDispatch
|
|
|
178
188
|
end
|
|
179
189
|
end
|
|
180
190
|
|
|
181
|
-
def method_missing(name,
|
|
191
|
+
def method_missing(name, ...)
|
|
182
192
|
if url_helpers.respond_to?(name)
|
|
183
|
-
url_helpers.public_send(name,
|
|
193
|
+
url_helpers.public_send(name, ...)
|
|
184
194
|
else
|
|
185
195
|
super
|
|
186
196
|
end
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
module ActionDispatch
|
|
4
6
|
module SystemTesting
|
|
5
7
|
class Browser # :nodoc:
|
|
@@ -7,7 +9,6 @@ module ActionDispatch
|
|
|
7
9
|
|
|
8
10
|
def initialize(name)
|
|
9
11
|
@name = name
|
|
10
|
-
set_default_options
|
|
11
12
|
end
|
|
12
13
|
|
|
13
14
|
def type
|
|
@@ -25,9 +26,9 @@ module ActionDispatch
|
|
|
25
26
|
@options ||=
|
|
26
27
|
case type
|
|
27
28
|
when :chrome
|
|
28
|
-
|
|
29
|
+
default_chrome_options
|
|
29
30
|
when :firefox
|
|
30
|
-
|
|
31
|
+
default_firefox_options
|
|
31
32
|
end
|
|
32
33
|
end
|
|
33
34
|
|
|
@@ -35,8 +36,8 @@ module ActionDispatch
|
|
|
35
36
|
yield options if block_given?
|
|
36
37
|
end
|
|
37
38
|
|
|
38
|
-
# driver_path is lazily initialized by default. Eagerly set it to
|
|
39
|
-
#
|
|
39
|
+
# driver_path is lazily initialized by default. Eagerly set it to avoid race
|
|
40
|
+
# conditions when using parallel tests.
|
|
40
41
|
def preload
|
|
41
42
|
case type
|
|
42
43
|
when :chrome
|
|
@@ -47,26 +48,18 @@ module ActionDispatch
|
|
|
47
48
|
end
|
|
48
49
|
|
|
49
50
|
private
|
|
50
|
-
def
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def set_headless_chrome_browser_options
|
|
60
|
-
configure do |capabilities|
|
|
61
|
-
capabilities.add_argument("--headless")
|
|
62
|
-
capabilities.add_argument("--disable-gpu") if Gem.win_platform?
|
|
63
|
-
end
|
|
51
|
+
def default_chrome_options
|
|
52
|
+
options = ::Selenium::WebDriver::Chrome::Options.new
|
|
53
|
+
options.add_argument("--disable-search-engine-choice-screen")
|
|
54
|
+
options.add_argument("--headless") if name == :headless_chrome
|
|
55
|
+
options.add_argument("--disable-gpu") if Gem.win_platform?
|
|
56
|
+
options
|
|
64
57
|
end
|
|
65
58
|
|
|
66
|
-
def
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
59
|
+
def default_firefox_options
|
|
60
|
+
options = ::Selenium::WebDriver::Firefox::Options.new
|
|
61
|
+
options.add_argument("-headless") if name == :headless_firefox
|
|
62
|
+
options
|
|
70
63
|
end
|
|
71
64
|
|
|
72
65
|
def resolve_driver_path(namespace)
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
module ActionDispatch
|
|
4
6
|
module SystemTesting
|
|
5
7
|
module TestHelpers
|
|
@@ -7,27 +9,35 @@ module ActionDispatch
|
|
|
7
9
|
module ScreenshotHelper
|
|
8
10
|
# Takes a screenshot of the current page in the browser.
|
|
9
11
|
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
# automating visual testing. You can take multiple screenshots per test
|
|
13
|
-
#
|
|
14
|
-
#
|
|
12
|
+
# `take_screenshot` can be used at any point in your system tests to take a
|
|
13
|
+
# screenshot of the current state. This can be useful for debugging or
|
|
14
|
+
# automating visual testing. You can take multiple screenshots per test to
|
|
15
|
+
# investigate changes at different points during your test. These will be named
|
|
16
|
+
# with a sequential prefix (or 'failed' for failing tests)
|
|
17
|
+
#
|
|
18
|
+
# The default screenshots directory is `tmp/screenshots` but you can set a
|
|
19
|
+
# different one with `Capybara.save_path`
|
|
20
|
+
#
|
|
21
|
+
# You can use the `html` argument or set the
|
|
22
|
+
# `RAILS_SYSTEM_TESTING_SCREENSHOT_HTML` environment variable to save the HTML
|
|
23
|
+
# from the page that is being screenshotted so you can investigate the elements
|
|
24
|
+
# on the page at the time of the screenshot
|
|
25
|
+
#
|
|
26
|
+
# You can use the `screenshot` argument or set the
|
|
27
|
+
# `RAILS_SYSTEM_TESTING_SCREENSHOT` environment variable to control the output.
|
|
28
|
+
# Possible values are:
|
|
29
|
+
# `simple` (default)
|
|
30
|
+
# : Only displays the screenshot path. This is the default value.
|
|
31
|
+
#
|
|
32
|
+
# `inline`
|
|
33
|
+
# : Display the screenshot in the terminal using the iTerm image protocol
|
|
34
|
+
# (https://iterm2.com/documentation-images.html).
|
|
15
35
|
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
36
|
+
# `artifact`
|
|
37
|
+
# : Display the screenshot in the terminal, using the terminal artifact
|
|
38
|
+
# format (https://buildkite.github.io/terminal-to-html/inline-images/).
|
|
18
39
|
#
|
|
19
|
-
# You can use the +html+ argument or set the +RAILS_SYSTEM_TESTING_SCREENSHOT_HTML+
|
|
20
|
-
# environment variable to save the HTML from the page that is being screenshotted
|
|
21
|
-
# so you can investigate the elements on the page at the time of the screenshot
|
|
22
40
|
#
|
|
23
|
-
# You can use the +screenshot+ argument or set the +RAILS_SYSTEM_TESTING_SCREENSHOT+
|
|
24
|
-
# environment variable to control the output. Possible values are:
|
|
25
|
-
# * [+simple+ (default)] Only displays the screenshot path.
|
|
26
|
-
# This is the default value.
|
|
27
|
-
# * [+inline+] Display the screenshot in the terminal using the
|
|
28
|
-
# iTerm image protocol (https://iterm2.com/documentation-images.html).
|
|
29
|
-
# * [+artifact+] Display the screenshot in the terminal, using the terminal
|
|
30
|
-
# artifact format (https://buildkite.github.io/terminal-to-html/inline-images/).
|
|
31
41
|
def take_screenshot(html: false, screenshot: nil)
|
|
32
42
|
showing_html = html || html_from_env?
|
|
33
43
|
|
|
@@ -37,10 +47,9 @@ module ActionDispatch
|
|
|
37
47
|
show display_image(html: showing_html, screenshot_output: screenshot)
|
|
38
48
|
end
|
|
39
49
|
|
|
40
|
-
# Takes a screenshot of the current page in the browser if the test
|
|
41
|
-
# failed.
|
|
50
|
+
# Takes a screenshot of the current page in the browser if the test failed.
|
|
42
51
|
#
|
|
43
|
-
#
|
|
52
|
+
# `take_failed_screenshot` is called during system test teardown.
|
|
44
53
|
def take_failed_screenshot
|
|
45
54
|
return unless failed? && supports_screenshot? && Capybara::Session.instance_created?
|
|
46
55
|
|
|
@@ -98,6 +107,7 @@ module ActionDispatch
|
|
|
98
107
|
"#{absolute_path}.html"
|
|
99
108
|
end
|
|
100
109
|
|
|
110
|
+
# rubocop:disable Lint/Debugger
|
|
101
111
|
def save_html
|
|
102
112
|
page.save_page(absolute_html_path)
|
|
103
113
|
end
|
|
@@ -105,6 +115,7 @@ module ActionDispatch
|
|
|
105
115
|
def save_image
|
|
106
116
|
page.save_screenshot(absolute_image_path)
|
|
107
117
|
end
|
|
118
|
+
# rubocop:enable Lint/Debugger
|
|
108
119
|
|
|
109
120
|
def output_type
|
|
110
121
|
# Environment variables have priority
|
|
@@ -121,8 +132,8 @@ module ActionDispatch
|
|
|
121
132
|
end
|
|
122
133
|
|
|
123
134
|
def display_image(html:, screenshot_output:)
|
|
124
|
-
message = +"[Screenshot Image]: #{image_path}\n"
|
|
125
|
-
message << +"[Screenshot HTML]: #{html_path}\n" if html
|
|
135
|
+
message = +"[Screenshot Image]: #{image_path} \n"
|
|
136
|
+
message << +"[Screenshot HTML]: #{html_path} \n" if html
|
|
126
137
|
|
|
127
138
|
case screenshot_output || output_type
|
|
128
139
|
when "artifact"
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
module ActionDispatch
|
|
4
|
-
# This is a class that abstracts away an asserted response. It purposely
|
|
5
|
-
#
|
|
6
|
-
#
|
|
6
|
+
# This is a class that abstracts away an asserted response. It purposely does
|
|
7
|
+
# not inherit from Response because it doesn't need it. That means it does not
|
|
8
|
+
# have headers or a body.
|
|
7
9
|
class AssertionResponse
|
|
8
10
|
attr_reader :code, :name
|
|
9
11
|
|
|
@@ -14,9 +16,9 @@ module ActionDispatch
|
|
|
14
16
|
error: "5XX"
|
|
15
17
|
}
|
|
16
18
|
|
|
17
|
-
# Accepts a specific response status code as an Integer (404) or String
|
|
18
|
-
#
|
|
19
|
-
#
|
|
19
|
+
# Accepts a specific response status code as an Integer (404) or String ('404')
|
|
20
|
+
# or a response status range as a Symbol pseudo-code (:success, indicating any
|
|
21
|
+
# 200-299 status code).
|
|
20
22
|
def initialize(code_or_name)
|
|
21
23
|
if code_or_name.is_a?(Symbol)
|
|
22
24
|
@name = code_or_name
|
|
@@ -36,7 +38,7 @@ module ActionDispatch
|
|
|
36
38
|
|
|
37
39
|
private
|
|
38
40
|
def code_from_name(name)
|
|
39
|
-
GENERIC_RESPONSE_CODES[name] ||
|
|
41
|
+
GENERIC_RESPONSE_CODES[name] || ActionDispatch::Response.rack_status_code(name)
|
|
40
42
|
end
|
|
41
43
|
|
|
42
44
|
def name_from_code(code)
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
module ActionDispatch
|
|
4
6
|
module Assertions
|
|
5
|
-
# A small suite of assertions that test responses from
|
|
7
|
+
# A small suite of assertions that test responses from Rails applications.
|
|
6
8
|
module ResponseAssertions
|
|
7
9
|
RESPONSE_PREDICATES = { # :nodoc:
|
|
8
10
|
success: :successful?,
|
|
@@ -13,20 +15,21 @@ module ActionDispatch
|
|
|
13
15
|
|
|
14
16
|
# Asserts that the response is one of the following types:
|
|
15
17
|
#
|
|
16
|
-
# *
|
|
17
|
-
# *
|
|
18
|
-
# *
|
|
19
|
-
# *
|
|
18
|
+
# * `:success` - Status code was in the 200-299 range
|
|
19
|
+
# * `:redirect` - Status code was in the 300-399 range
|
|
20
|
+
# * `:missing` - Status code was 404
|
|
21
|
+
# * `:error` - Status code was in the 500-599 range
|
|
22
|
+
#
|
|
20
23
|
#
|
|
21
|
-
# You can also pass an explicit status number like
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
+
# You can also pass an explicit status number like `assert_response(501)` or its
|
|
25
|
+
# symbolic equivalent `assert_response(:not_implemented)`. See
|
|
26
|
+
# `Rack::Utils::SYMBOL_TO_STATUS_CODE` for a full list.
|
|
24
27
|
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
28
|
+
# # Asserts that the response was a redirection
|
|
29
|
+
# assert_response :redirect
|
|
27
30
|
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
31
|
+
# # Asserts that the response code was status code 401 (unauthorized)
|
|
32
|
+
# assert_response 401
|
|
30
33
|
def assert_response(type, message = nil)
|
|
31
34
|
message ||= generate_response_message(type)
|
|
32
35
|
|
|
@@ -39,21 +42,21 @@ module ActionDispatch
|
|
|
39
42
|
|
|
40
43
|
# Asserts that the response is a redirect to a URL matching the given options.
|
|
41
44
|
#
|
|
42
|
-
#
|
|
43
|
-
#
|
|
45
|
+
# # Asserts that the redirection was to the "index" action on the WeblogController
|
|
46
|
+
# assert_redirected_to controller: "weblog", action: "index"
|
|
44
47
|
#
|
|
45
|
-
#
|
|
46
|
-
#
|
|
48
|
+
# # Asserts that the redirection was to the named route login_url
|
|
49
|
+
# assert_redirected_to login_url
|
|
47
50
|
#
|
|
48
|
-
#
|
|
49
|
-
#
|
|
51
|
+
# # Asserts that the redirection was to the URL for @customer
|
|
52
|
+
# assert_redirected_to @customer
|
|
50
53
|
#
|
|
51
|
-
#
|
|
52
|
-
#
|
|
54
|
+
# # Asserts that the redirection matches the regular expression
|
|
55
|
+
# assert_redirected_to %r(\Ahttp://example.org)
|
|
53
56
|
#
|
|
54
|
-
#
|
|
55
|
-
#
|
|
56
|
-
#
|
|
57
|
+
# # Asserts that the redirection has the HTTP status code 301 (Moved
|
|
58
|
+
# # Permanently).
|
|
59
|
+
# assert_redirected_to "/some/path", status: :moved_permanently
|
|
57
60
|
def assert_redirected_to(url_options = {}, options = {}, message = nil)
|
|
58
61
|
options, message = {}, options unless options.is_a?(Hash)
|
|
59
62
|
|
|
@@ -68,6 +71,20 @@ module ActionDispatch
|
|
|
68
71
|
assert_operator redirect_expected, :===, redirect_is, message
|
|
69
72
|
end
|
|
70
73
|
|
|
74
|
+
# Asserts that the given +text+ is present somewhere in the response body.
|
|
75
|
+
#
|
|
76
|
+
# assert_in_body fixture(:name).description
|
|
77
|
+
def assert_in_body(text)
|
|
78
|
+
assert_match(/#{Regexp.escape(text)}/, @response.body)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Asserts that the given +text+ is not present anywhere in the response body.
|
|
82
|
+
#
|
|
83
|
+
# assert_not_in_body fixture(:name).description
|
|
84
|
+
def assert_not_in_body(text)
|
|
85
|
+
assert_no_match(/#{Regexp.escape(text)}/, @response.body)
|
|
86
|
+
end
|
|
87
|
+
|
|
71
88
|
private
|
|
72
89
|
# Proxy to to_param if the object will respond to it.
|
|
73
90
|
def parameterize(value)
|
|
@@ -84,8 +101,13 @@ module ActionDispatch
|
|
|
84
101
|
end
|
|
85
102
|
|
|
86
103
|
def generate_response_message(expected, actual = @response.response_code)
|
|
87
|
-
|
|
88
|
-
|
|
104
|
+
lambda do
|
|
105
|
+
(+"Expected response to be a <#{code_with_name(expected)}>,"\
|
|
106
|
+
" but was a <#{code_with_name(actual)}>").
|
|
107
|
+
concat(location_if_redirected).
|
|
108
|
+
concat(exception_if_present).
|
|
109
|
+
concat(response_body_if_short)
|
|
110
|
+
end
|
|
89
111
|
end
|
|
90
112
|
|
|
91
113
|
def response_body_if_short
|
|
@@ -93,6 +115,11 @@ module ActionDispatch
|
|
|
93
115
|
"\nResponse body: #{@response.body}"
|
|
94
116
|
end
|
|
95
117
|
|
|
118
|
+
def exception_if_present
|
|
119
|
+
return "" unless ex = @request&.env&.[]("action_dispatch.exception")
|
|
120
|
+
"\n\nException while processing request: #{Minitest::UnexpectedError.new(ex).message}\n"
|
|
121
|
+
end
|
|
122
|
+
|
|
96
123
|
def location_if_redirected
|
|
97
124
|
return "" unless @response.redirection? && @response.location.present?
|
|
98
125
|
location = normalize_argument_to_redirection(@response.location)
|