actionpack 6.1.4.1 → 7.0.0.rc2
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 +191 -378
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -3
- data/lib/abstract_controller/asset_paths.rb +1 -1
- data/lib/abstract_controller/base.rb +7 -21
- data/lib/abstract_controller/caching/fragments.rb +2 -2
- data/lib/abstract_controller/caching.rb +1 -1
- data/lib/abstract_controller/callbacks.rb +21 -7
- data/lib/abstract_controller/collector.rb +4 -2
- data/lib/abstract_controller/error.rb +1 -1
- data/lib/abstract_controller/helpers.rb +3 -2
- data/lib/abstract_controller/logger.rb +1 -1
- data/lib/abstract_controller/railties/routes_helpers.rb +2 -0
- data/lib/abstract_controller/translation.rb +3 -2
- data/lib/abstract_controller/url_for.rb +4 -6
- data/lib/action_controller/api.rb +1 -1
- data/lib/action_controller/log_subscriber.rb +4 -3
- data/lib/action_controller/metal/conditional_get.rb +38 -1
- data/lib/action_controller/metal/content_security_policy.rb +1 -1
- data/lib/action_controller/metal/cookies.rb +1 -1
- data/lib/action_controller/metal/data_streaming.rb +5 -13
- data/lib/action_controller/metal/exceptions.rb +19 -30
- data/lib/action_controller/metal/flash.rb +6 -2
- data/lib/action_controller/metal/helpers.rb +1 -1
- data/lib/action_controller/metal/http_authentication.rb +17 -16
- data/lib/action_controller/metal/instrumentation.rb +57 -52
- data/lib/action_controller/metal/live.rb +42 -2
- data/lib/action_controller/metal/mime_responds.rb +3 -3
- data/lib/action_controller/metal/params_wrapper.rb +20 -11
- data/lib/action_controller/metal/permissions_policy.rb +1 -1
- data/lib/action_controller/metal/redirecting.rb +86 -16
- data/lib/action_controller/metal/rendering.rb +7 -7
- data/lib/action_controller/metal/request_forgery_protection.rb +64 -24
- data/lib/action_controller/metal/rescue.rb +1 -1
- data/lib/action_controller/metal/streaming.rb +1 -3
- data/lib/action_controller/metal/strong_parameters.rb +84 -47
- data/lib/action_controller/metal/testing.rb +0 -2
- data/lib/action_controller/metal.rb +7 -10
- data/lib/action_controller/railtie.rb +49 -6
- data/lib/action_controller/test_case.rb +19 -4
- data/lib/action_controller.rb +1 -5
- data/lib/action_dispatch/http/cache.rb +13 -6
- data/lib/action_dispatch/http/content_security_policy.rb +39 -35
- data/lib/action_dispatch/http/filter_parameters.rb +5 -0
- data/lib/action_dispatch/http/mime_negotiation.rb +13 -3
- data/lib/action_dispatch/http/mime_type.rb +9 -11
- data/lib/action_dispatch/http/parameters.rb +4 -4
- data/lib/action_dispatch/http/permissions_policy.rb +1 -1
- data/lib/action_dispatch/http/request.rb +10 -19
- data/lib/action_dispatch/http/response.rb +1 -13
- data/lib/action_dispatch/http/url.rb +11 -19
- data/lib/action_dispatch/journey/gtg/builder.rb +11 -12
- data/lib/action_dispatch/journey/gtg/simulator.rb +10 -4
- data/lib/action_dispatch/journey/gtg/transition_table.rb +77 -21
- data/lib/action_dispatch/journey/nodes/node.rb +70 -5
- data/lib/action_dispatch/journey/path/pattern.rb +22 -13
- data/lib/action_dispatch/journey/route.rb +6 -13
- data/lib/action_dispatch/journey/router/utils.rb +2 -2
- data/lib/action_dispatch/journey/router.rb +1 -1
- data/lib/action_dispatch/journey/routes.rb +3 -3
- data/lib/action_dispatch/journey/visualizer/fsm.js +49 -24
- data/lib/action_dispatch/journey/visualizer/index.html.erb +1 -1
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +0 -1
- data/lib/action_dispatch/middleware/cookies.rb +8 -4
- data/lib/action_dispatch/middleware/debug_exceptions.rb +6 -4
- data/lib/action_dispatch/middleware/debug_locks.rb +3 -3
- data/lib/action_dispatch/middleware/exception_wrapper.rb +4 -0
- data/lib/action_dispatch/middleware/executor.rb +3 -0
- data/lib/action_dispatch/middleware/flash.rb +9 -11
- data/lib/action_dispatch/middleware/host_authorization.rb +44 -30
- data/lib/action_dispatch/middleware/remote_ip.rb +16 -4
- data/lib/action_dispatch/middleware/server_timing.rb +33 -0
- data/lib/action_dispatch/middleware/session/abstract_store.rb +1 -1
- data/lib/action_dispatch/middleware/show_exceptions.rb +17 -9
- data/lib/action_dispatch/middleware/stack.rb +27 -9
- data/lib/action_dispatch/middleware/static.rb +2 -6
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +4 -11
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +4 -3
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +3 -1
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +28 -18
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +5 -14
- data/lib/action_dispatch/railtie.rb +8 -2
- data/lib/action_dispatch/request/session.rb +43 -13
- data/lib/action_dispatch/routing/inspector.rb +1 -1
- data/lib/action_dispatch/routing/mapper.rb +54 -78
- data/lib/action_dispatch/routing/redirection.rb +0 -2
- data/lib/action_dispatch/routing/route_set.rb +14 -6
- data/lib/action_dispatch/routing/routes_proxy.rb +1 -1
- data/lib/action_dispatch/routing/url_for.rb +1 -2
- data/lib/action_dispatch/routing.rb +2 -2
- data/lib/action_dispatch/system_test_case.rb +12 -6
- data/lib/action_dispatch/system_testing/browser.rb +2 -12
- data/lib/action_dispatch/system_testing/driver.rb +35 -11
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +10 -6
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +0 -8
- data/lib/action_dispatch/testing/assertions.rb +2 -5
- data/lib/action_dispatch/testing/integration.rb +6 -8
- data/lib/action_dispatch/testing/test_process.rb +3 -26
- data/lib/action_dispatch.rb +2 -1
- data/lib/action_pack/gem_version.rb +4 -4
- data/lib/action_pack.rb +1 -1
- metadata +18 -16
@@ -4,7 +4,6 @@ require "active_support/core_ext/hash/slice"
|
|
4
4
|
require "active_support/core_ext/enumerable"
|
5
5
|
require "active_support/core_ext/array/extract_options"
|
6
6
|
require "active_support/core_ext/regexp"
|
7
|
-
require "active_support/core_ext/symbol/starts_ends_with"
|
8
7
|
require "action_dispatch/routing/redirection"
|
9
8
|
require "action_dispatch/routing/endpoint"
|
10
9
|
|
@@ -13,7 +12,7 @@ module ActionDispatch
|
|
13
12
|
class Mapper
|
14
13
|
URL_OPTIONS = [:protocol, :subdomain, :domain, :host, :port]
|
15
14
|
|
16
|
-
class Constraints < Routing::Endpoint
|
15
|
+
class Constraints < Routing::Endpoint # :nodoc:
|
17
16
|
attr_reader :app, :constraints
|
18
17
|
|
19
18
|
SERVE = ->(app, req) { app.serve req }
|
@@ -67,11 +66,11 @@ module ActionDispatch
|
|
67
66
|
end
|
68
67
|
end
|
69
68
|
|
70
|
-
class Mapping
|
69
|
+
class Mapping # :nodoc:
|
71
70
|
ANCHOR_CHARACTERS_REGEX = %r{\A(\\A|\^)|(\\Z|\\z|\$)\Z}
|
72
71
|
OPTIONAL_FORMAT_REGEX = %r{(?:\(\.:format\)+|\.:format|/)\Z}
|
73
72
|
|
74
|
-
attr_reader :requirements, :defaults, :to, :default_controller,
|
73
|
+
attr_reader :path, :requirements, :defaults, :to, :default_controller,
|
75
74
|
:default_action, :required_defaults, :ast, :scope_options
|
76
75
|
|
77
76
|
def self.build(scope, set, ast, controller, default_action, to, via, formatted, options_constraints, anchor, options)
|
@@ -122,31 +121,17 @@ module ActionDispatch
|
|
122
121
|
@to = intern(to)
|
123
122
|
@default_controller = intern(controller)
|
124
123
|
@default_action = intern(default_action)
|
125
|
-
@ast = ast
|
126
124
|
@anchor = anchor
|
127
125
|
@via = via
|
128
126
|
@internal = options.delete(:internal)
|
129
127
|
@scope_options = scope_params[:options]
|
128
|
+
ast = Journey::Ast.new(ast, formatted)
|
130
129
|
|
131
|
-
|
132
|
-
wildcard_options = {}
|
133
|
-
ast.each do |node|
|
134
|
-
if node.symbol?
|
135
|
-
path_params << node.to_sym
|
136
|
-
elsif formatted != false && node.star?
|
137
|
-
# Add a constraint for wildcard route to make it non-greedy and match the
|
138
|
-
# optional format part of the route by default.
|
139
|
-
wildcard_options[node.name.to_sym] ||= /.+?/
|
140
|
-
elsif node.cat?
|
141
|
-
alter_regex_for_custom_routes(node)
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
options = wildcard_options.merge!(options)
|
130
|
+
options = ast.wildcard_options.merge!(options)
|
146
131
|
|
147
|
-
options = normalize_options!(options, path_params, scope_params[:module])
|
132
|
+
options = normalize_options!(options, ast.path_params, scope_params[:module])
|
148
133
|
|
149
|
-
split_options = constraints(options, path_params)
|
134
|
+
split_options = constraints(options, ast.path_params)
|
150
135
|
|
151
136
|
constraints = scope_params[:constraints].merge Hash[split_options[:constraints] || []]
|
152
137
|
|
@@ -160,8 +145,8 @@ module ActionDispatch
|
|
160
145
|
@blocks = blocks(options_constraints)
|
161
146
|
end
|
162
147
|
|
163
|
-
requirements, conditions = split_constraints path_params, constraints
|
164
|
-
verify_regexp_requirements requirements.
|
148
|
+
requirements, conditions = split_constraints ast.path_params, constraints
|
149
|
+
verify_regexp_requirements requirements, ast.wildcard_options
|
165
150
|
|
166
151
|
formats = normalize_format(formatted)
|
167
152
|
|
@@ -169,13 +154,18 @@ module ActionDispatch
|
|
169
154
|
@conditions = Hash[conditions]
|
170
155
|
@defaults = formats[:defaults].merge(@defaults).merge(normalize_defaults(options))
|
171
156
|
|
172
|
-
if path_params.include?(:action) && !@requirements.key?(:action)
|
157
|
+
if ast.path_params.include?(:action) && !@requirements.key?(:action)
|
173
158
|
@defaults[:action] ||= "index"
|
174
159
|
end
|
175
160
|
|
176
161
|
@required_defaults = (split_options[:required_defaults] || []).map(&:first)
|
162
|
+
|
163
|
+
ast.requirements = @requirements
|
164
|
+
@path = Journey::Path::Pattern.new(ast, @requirements, JOINED_SEPARATORS, @anchor)
|
177
165
|
end
|
178
166
|
|
167
|
+
JOINED_SEPARATORS = SEPARATORS.join # :nodoc:
|
168
|
+
|
179
169
|
def make_route(name, precedence)
|
180
170
|
Journey::Route.new(name: name, app: application, path: path, constraints: conditions,
|
181
171
|
required_defaults: required_defaults, defaults: defaults,
|
@@ -187,12 +177,6 @@ module ActionDispatch
|
|
187
177
|
app(@blocks)
|
188
178
|
end
|
189
179
|
|
190
|
-
JOINED_SEPARATORS = SEPARATORS.join # :nodoc:
|
191
|
-
|
192
|
-
def path
|
193
|
-
Journey::Path::Pattern.new(@ast, requirements, JOINED_SEPARATORS, @anchor)
|
194
|
-
end
|
195
|
-
|
196
180
|
def conditions
|
197
181
|
build_conditions @conditions, @set.request_class
|
198
182
|
end
|
@@ -212,24 +196,6 @@ module ActionDispatch
|
|
212
196
|
private :request_method
|
213
197
|
|
214
198
|
private
|
215
|
-
# Find all the symbol nodes that are adjacent to literal nodes and alter
|
216
|
-
# the regexp so that Journey will partition them into custom routes.
|
217
|
-
def alter_regex_for_custom_routes(node)
|
218
|
-
if node.left.literal? && node.right.symbol?
|
219
|
-
symbol = node.right
|
220
|
-
elsif node.left.literal? && node.right.cat? && node.right.left.symbol?
|
221
|
-
symbol = node.right.left
|
222
|
-
elsif node.left.symbol? && node.right.literal?
|
223
|
-
symbol = node.left
|
224
|
-
elsif node.left.symbol? && node.right.cat? && node.right.left.literal?
|
225
|
-
symbol = node.left
|
226
|
-
end
|
227
|
-
|
228
|
-
if symbol
|
229
|
-
symbol.regexp = /(?:#{Regexp.union(symbol.regexp, '-')})+/
|
230
|
-
end
|
231
|
-
end
|
232
|
-
|
233
199
|
def intern(object)
|
234
200
|
object.is_a?(String) ? -object : object
|
235
201
|
end
|
@@ -280,14 +246,18 @@ module ActionDispatch
|
|
280
246
|
end
|
281
247
|
end
|
282
248
|
|
283
|
-
def verify_regexp_requirements(requirements)
|
284
|
-
requirements.each do |requirement|
|
285
|
-
|
249
|
+
def verify_regexp_requirements(requirements, wildcard_options)
|
250
|
+
requirements.each do |requirement, regex|
|
251
|
+
next unless regex.is_a? Regexp
|
252
|
+
|
253
|
+
if ANCHOR_CHARACTERS_REGEX.match?(regex.source)
|
286
254
|
raise ArgumentError, "Regexp anchor characters are not allowed in routing requirements: #{requirement.inspect}"
|
287
255
|
end
|
288
256
|
|
289
|
-
if
|
290
|
-
|
257
|
+
if regex.multiline?
|
258
|
+
next if wildcard_options.key?(requirement)
|
259
|
+
|
260
|
+
raise ArgumentError, "Regexp multiline option is not allowed in routing requirements: #{regex.inspect}"
|
291
261
|
end
|
292
262
|
end
|
293
263
|
end
|
@@ -956,7 +926,7 @@ module ActionDispatch
|
|
956
926
|
# namespace :admin, as: "sekret" do
|
957
927
|
# resources :posts
|
958
928
|
# end
|
959
|
-
def namespace(path, options = {})
|
929
|
+
def namespace(path, options = {}, &block)
|
960
930
|
path = path.to_s
|
961
931
|
|
962
932
|
defaults = {
|
@@ -967,7 +937,7 @@ module ActionDispatch
|
|
967
937
|
}
|
968
938
|
|
969
939
|
path_scope(options.delete(:path) { path }) do
|
970
|
-
scope(defaults.merge!(options))
|
940
|
+
scope(defaults.merge!(options), &block)
|
971
941
|
end
|
972
942
|
end
|
973
943
|
|
@@ -1026,8 +996,8 @@ module ActionDispatch
|
|
1026
996
|
# constraints(Iphone) do
|
1027
997
|
# resources :iphones
|
1028
998
|
# end
|
1029
|
-
def constraints(constraints = {})
|
1030
|
-
scope(constraints: constraints)
|
999
|
+
def constraints(constraints = {}, &block)
|
1000
|
+
scope(constraints: constraints, &block)
|
1031
1001
|
end
|
1032
1002
|
|
1033
1003
|
# Allows you to set default parameters for a route, such as this:
|
@@ -1156,7 +1126,7 @@ module ActionDispatch
|
|
1156
1126
|
RESOURCE_OPTIONS = [:as, :controller, :path, :only, :except, :param, :concerns]
|
1157
1127
|
CANONICAL_ACTIONS = %w(index create new show update destroy)
|
1158
1128
|
|
1159
|
-
class Resource
|
1129
|
+
class Resource # :nodoc:
|
1160
1130
|
attr_reader :controller, :path, :param
|
1161
1131
|
|
1162
1132
|
def initialize(entities, api_only, shallow, options = {})
|
@@ -1251,7 +1221,7 @@ module ActionDispatch
|
|
1251
1221
|
def singleton?; false; end
|
1252
1222
|
end
|
1253
1223
|
|
1254
|
-
class SingletonResource < Resource
|
1224
|
+
class SingletonResource < Resource # :nodoc:
|
1255
1225
|
def initialize(entities, api_only, shallow, options)
|
1256
1226
|
super
|
1257
1227
|
@as = nil
|
@@ -1307,6 +1277,16 @@ module ActionDispatch
|
|
1307
1277
|
# DELETE /profile
|
1308
1278
|
# POST /profile
|
1309
1279
|
#
|
1280
|
+
# If you want instances of a model to work with this resource via
|
1281
|
+
# record identification (e.g. in +form_with+ or +redirect_to+), you
|
1282
|
+
# will need to call resolve[rdoc-ref:CustomUrls#resolve]:
|
1283
|
+
#
|
1284
|
+
# resource :profile
|
1285
|
+
# resolve('Profile') { [:profile] }
|
1286
|
+
#
|
1287
|
+
# # Enables this to work with singular routes:
|
1288
|
+
# form_with(model: @profile) {}
|
1289
|
+
#
|
1310
1290
|
# === Options
|
1311
1291
|
# Takes same options as resources[rdoc-ref:#resources]
|
1312
1292
|
def resource(*resources, &block)
|
@@ -1517,15 +1497,13 @@ module ActionDispatch
|
|
1517
1497
|
# with GET, and route to the search action of +PhotosController+. It will also
|
1518
1498
|
# create the <tt>search_photos_url</tt> and <tt>search_photos_path</tt>
|
1519
1499
|
# route helpers.
|
1520
|
-
def collection
|
1500
|
+
def collection(&block)
|
1521
1501
|
unless resource_scope?
|
1522
1502
|
raise ArgumentError, "can't use collection outside resource(s) scope"
|
1523
1503
|
end
|
1524
1504
|
|
1525
1505
|
with_scope_level(:collection) do
|
1526
|
-
path_scope(parent_resource.collection_scope)
|
1527
|
-
yield
|
1528
|
-
end
|
1506
|
+
path_scope(parent_resource.collection_scope, &block)
|
1529
1507
|
end
|
1530
1508
|
end
|
1531
1509
|
|
@@ -1540,7 +1518,7 @@ module ActionDispatch
|
|
1540
1518
|
# This will recognize <tt>/photos/1/preview</tt> with GET, and route to the
|
1541
1519
|
# preview action of +PhotosController+. It will also create the
|
1542
1520
|
# <tt>preview_photo_url</tt> and <tt>preview_photo_path</tt> helpers.
|
1543
|
-
def member
|
1521
|
+
def member(&block)
|
1544
1522
|
unless resource_scope?
|
1545
1523
|
raise ArgumentError, "can't use member outside resource(s) scope"
|
1546
1524
|
end
|
@@ -1548,27 +1526,25 @@ module ActionDispatch
|
|
1548
1526
|
with_scope_level(:member) do
|
1549
1527
|
if shallow?
|
1550
1528
|
shallow_scope {
|
1551
|
-
path_scope(parent_resource.member_scope)
|
1529
|
+
path_scope(parent_resource.member_scope, &block)
|
1552
1530
|
}
|
1553
1531
|
else
|
1554
|
-
path_scope(parent_resource.member_scope)
|
1532
|
+
path_scope(parent_resource.member_scope, &block)
|
1555
1533
|
end
|
1556
1534
|
end
|
1557
1535
|
end
|
1558
1536
|
|
1559
|
-
def new
|
1537
|
+
def new(&block)
|
1560
1538
|
unless resource_scope?
|
1561
1539
|
raise ArgumentError, "can't use new outside resource(s) scope"
|
1562
1540
|
end
|
1563
1541
|
|
1564
1542
|
with_scope_level(:new) do
|
1565
|
-
path_scope(parent_resource.new_scope(action_path(:new)))
|
1566
|
-
yield
|
1567
|
-
end
|
1543
|
+
path_scope(parent_resource.new_scope(action_path(:new)), &block)
|
1568
1544
|
end
|
1569
1545
|
end
|
1570
1546
|
|
1571
|
-
def nested
|
1547
|
+
def nested(&block)
|
1572
1548
|
unless resource_scope?
|
1573
1549
|
raise ArgumentError, "can't use nested outside resource(s) scope"
|
1574
1550
|
end
|
@@ -1577,12 +1553,12 @@ module ActionDispatch
|
|
1577
1553
|
if shallow? && shallow_nesting_depth >= 1
|
1578
1554
|
shallow_scope do
|
1579
1555
|
path_scope(parent_resource.nested_scope) do
|
1580
|
-
scope(nested_options)
|
1556
|
+
scope(nested_options, &block)
|
1581
1557
|
end
|
1582
1558
|
end
|
1583
1559
|
else
|
1584
1560
|
path_scope(parent_resource.nested_scope) do
|
1585
|
-
scope(nested_options)
|
1561
|
+
scope(nested_options, &block)
|
1586
1562
|
end
|
1587
1563
|
end
|
1588
1564
|
end
|
@@ -1768,10 +1744,10 @@ module ActionDispatch
|
|
1768
1744
|
@scope = @scope.parent
|
1769
1745
|
end
|
1770
1746
|
|
1771
|
-
def resource_scope(resource)
|
1747
|
+
def resource_scope(resource, &block)
|
1772
1748
|
@scope = @scope.new(scope_level_resource: resource)
|
1773
1749
|
|
1774
|
-
controller(resource.resource_scope)
|
1750
|
+
controller(resource.resource_scope, &block)
|
1775
1751
|
ensure
|
1776
1752
|
@scope = @scope.parent
|
1777
1753
|
end
|
@@ -1889,7 +1865,7 @@ module ActionDispatch
|
|
1889
1865
|
end
|
1890
1866
|
|
1891
1867
|
def map_match(paths, options)
|
1892
|
-
if options[:on] && !VALID_ON_OPTIONS.include?(
|
1868
|
+
if (on = options[:on]) && !VALID_ON_OPTIONS.include?(on)
|
1893
1869
|
raise ArgumentError, "Unknown scope #{on.inspect} given to :on"
|
1894
1870
|
end
|
1895
1871
|
|
@@ -2300,7 +2276,7 @@ module ActionDispatch
|
|
2300
2276
|
NULL = Scope.new(nil, nil)
|
2301
2277
|
end
|
2302
2278
|
|
2303
|
-
def initialize(set)
|
2279
|
+
def initialize(set) # :nodoc:
|
2304
2280
|
@set = set
|
2305
2281
|
@draw_paths = set.draw_paths
|
2306
2282
|
@scope = Scope.new(path_names: @set.resources_path_names)
|
@@ -6,7 +6,6 @@ require "active_support/core_ext/module/redefine_method"
|
|
6
6
|
require "active_support/core_ext/module/remove_method"
|
7
7
|
require "active_support/core_ext/array/extract_options"
|
8
8
|
require "action_controller/metal/exceptions"
|
9
|
-
require "action_dispatch/http/request"
|
10
9
|
require "action_dispatch/routing/endpoint"
|
11
10
|
|
12
11
|
module ActionDispatch
|
@@ -132,8 +131,8 @@ module ActionDispatch
|
|
132
131
|
alias [] get
|
133
132
|
alias clear clear!
|
134
133
|
|
135
|
-
def each
|
136
|
-
routes.each
|
134
|
+
def each(&block)
|
135
|
+
routes.each(&block)
|
137
136
|
self
|
138
137
|
end
|
139
138
|
|
@@ -597,14 +596,14 @@ module ActionDispatch
|
|
597
596
|
if route.segment_keys.include?(:controller)
|
598
597
|
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
599
598
|
Using a dynamic :controller segment in a route is deprecated and
|
600
|
-
will be removed in Rails
|
599
|
+
will be removed in Rails 7.0.
|
601
600
|
MSG
|
602
601
|
end
|
603
602
|
|
604
603
|
if route.segment_keys.include?(:action)
|
605
604
|
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
606
605
|
Using a dynamic :action segment in a route is deprecated and
|
607
|
-
will be removed in Rails
|
606
|
+
will be removed in Rails 7.0.
|
608
607
|
MSG
|
609
608
|
end
|
610
609
|
|
@@ -821,10 +820,19 @@ module ActionDispatch
|
|
821
820
|
|
822
821
|
route_with_params = generate(route_name, path_options, recall)
|
823
822
|
path = route_with_params.path(method_name)
|
823
|
+
|
824
|
+
if options[:trailing_slash] && !options[:format] && !path.end_with?("/")
|
825
|
+
path += "/"
|
826
|
+
end
|
827
|
+
|
824
828
|
params = route_with_params.params
|
825
829
|
|
826
830
|
if options.key? :params
|
827
|
-
|
831
|
+
if options[:params]&.respond_to?(:to_hash)
|
832
|
+
params.merge! options[:params]
|
833
|
+
else
|
834
|
+
params[:params] = options[:params]
|
835
|
+
end
|
828
836
|
end
|
829
837
|
|
830
838
|
options[:path] = path
|
@@ -103,11 +103,10 @@ module ActionDispatch
|
|
103
103
|
include(*_url_for_modules) if respond_to?(:_url_for_modules)
|
104
104
|
end
|
105
105
|
|
106
|
-
def initialize(
|
106
|
+
def initialize(...)
|
107
107
|
@_routes = nil
|
108
108
|
super
|
109
109
|
end
|
110
|
-
ruby2_keywords(:initialize) if respond_to?(:ruby2_keywords, true)
|
111
110
|
|
112
111
|
# Hook overridden in controller to add request information
|
113
112
|
# with +default_url_options+. Application logic should not
|
@@ -255,7 +255,7 @@ module ActionDispatch
|
|
255
255
|
autoload :UrlFor
|
256
256
|
autoload :PolymorphicRoutes
|
257
257
|
|
258
|
-
SEPARATORS = %w( / . ? )
|
259
|
-
HTTP_METHODS = [:get, :head, :post, :patch, :put, :delete, :options]
|
258
|
+
SEPARATORS = %w( / . ? ) # :nodoc:
|
259
|
+
HTTP_METHODS = [:get, :head, :post, :patch, :put, :delete, :options] # :nodoc:
|
260
260
|
end
|
261
261
|
end
|
@@ -72,8 +72,8 @@ module ActionDispatch
|
|
72
72
|
# Headless browsers such as headless Chrome and headless Firefox are also supported.
|
73
73
|
# You can use these browsers by setting the +:using+ argument to +:headless_chrome+ or +:headless_firefox+.
|
74
74
|
#
|
75
|
-
# To use a headless driver, like
|
76
|
-
#
|
75
|
+
# To use a headless driver, like Cuprite, update your Gemfile to use
|
76
|
+
# Cuprite instead of Selenium and then declare the driver name in the
|
77
77
|
# +application_system_test_case.rb+ file. In this case, you would leave out
|
78
78
|
# the +:using+ option because the driver is headless, but you can still use
|
79
79
|
# +:screen_size+ to change the size of the browser screen, also you can use
|
@@ -81,10 +81,10 @@ module ActionDispatch
|
|
81
81
|
# driver documentation to learn about supported options.
|
82
82
|
#
|
83
83
|
# require "test_helper"
|
84
|
-
# require "capybara/
|
84
|
+
# require "capybara/cuprite"
|
85
85
|
#
|
86
86
|
# class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
|
87
|
-
# driven_by :
|
87
|
+
# driven_by :cuprite, screen_size: [1400, 1400], options:
|
88
88
|
# { js_errors: true }
|
89
89
|
# end
|
90
90
|
#
|
@@ -115,6 +115,8 @@ module ActionDispatch
|
|
115
115
|
include SystemTesting::TestHelpers::SetupAndTeardown
|
116
116
|
include SystemTesting::TestHelpers::ScreenshotHelper
|
117
117
|
|
118
|
+
DEFAULT_HOST = "http://127.0.0.1"
|
119
|
+
|
118
120
|
def initialize(*) # :nodoc:
|
119
121
|
super
|
120
122
|
self.class.driven_by(:selenium) unless self.class.driver?
|
@@ -140,7 +142,7 @@ module ActionDispatch
|
|
140
142
|
#
|
141
143
|
# Examples:
|
142
144
|
#
|
143
|
-
# driven_by :
|
145
|
+
# driven_by :cuprite
|
144
146
|
#
|
145
147
|
# driven_by :selenium, screen_size: [800, 800]
|
146
148
|
#
|
@@ -166,7 +168,11 @@ module ActionDispatch
|
|
166
168
|
include ActionDispatch.test_app.routes.mounted_helpers
|
167
169
|
|
168
170
|
def url_options
|
169
|
-
default_url_options.reverse_merge(host:
|
171
|
+
default_url_options.reverse_merge(host: app_host)
|
172
|
+
end
|
173
|
+
|
174
|
+
def app_host
|
175
|
+
Capybara.app_host || Capybara.current_session.server_url || DEFAULT_HOST
|
170
176
|
end
|
171
177
|
end.new
|
172
178
|
end
|
@@ -33,19 +33,9 @@ module ActionDispatch
|
|
33
33
|
def preload
|
34
34
|
case type
|
35
35
|
when :chrome
|
36
|
-
|
37
|
-
::Selenium::WebDriver::Chrome::Service.driver_path&.call
|
38
|
-
else
|
39
|
-
# Selenium <= v3.141.0
|
40
|
-
::Selenium::WebDriver::Chrome.driver_path
|
41
|
-
end
|
36
|
+
::Selenium::WebDriver::Chrome::Service.driver_path&.call
|
42
37
|
when :firefox
|
43
|
-
|
44
|
-
::Selenium::WebDriver::Firefox::Service.driver_path&.call
|
45
|
-
else
|
46
|
-
# Selenium <= v3.141.0
|
47
|
-
::Selenium::WebDriver::Firefox.driver_path
|
48
|
-
end
|
38
|
+
::Selenium::WebDriver::Firefox::Service.driver_path&.call
|
49
39
|
end
|
50
40
|
end
|
51
41
|
|
@@ -3,16 +3,30 @@
|
|
3
3
|
module ActionDispatch
|
4
4
|
module SystemTesting
|
5
5
|
class Driver # :nodoc:
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
attr_reader :name
|
7
|
+
|
8
|
+
def initialize(driver_type, **options, &capabilities)
|
9
|
+
@driver_type = driver_type
|
9
10
|
@screen_size = options[:screen_size]
|
10
11
|
@options = options[:options] || {}
|
12
|
+
@name = @options.delete(:name) || driver_type
|
11
13
|
@capabilities = capabilities
|
12
14
|
|
13
|
-
if
|
15
|
+
if [:poltergeist, :webkit].include?(driver_type)
|
16
|
+
ActiveSupport::Deprecation.warn <<~MSG.squish
|
17
|
+
Poltergeist and capybara-webkit are not maintained already.
|
18
|
+
Driver registration of :poltergeist or :webkit is deprecated and will be removed in Rails 7.1.
|
19
|
+
You can still use :selenium, and also :cuprite is available for alternative to Poltergeist.
|
20
|
+
MSG
|
21
|
+
end
|
22
|
+
|
23
|
+
if driver_type == :selenium
|
24
|
+
gem "selenium-webdriver", ">= 4.0.0"
|
14
25
|
require "selenium/webdriver"
|
26
|
+
@browser = Browser.new(options[:using])
|
15
27
|
@browser.preload
|
28
|
+
else
|
29
|
+
@browser = nil
|
16
30
|
end
|
17
31
|
end
|
18
32
|
|
@@ -24,27 +38,29 @@ module ActionDispatch
|
|
24
38
|
|
25
39
|
private
|
26
40
|
def registerable?
|
27
|
-
[:selenium, :poltergeist, :webkit].include?(@
|
41
|
+
[:selenium, :poltergeist, :webkit, :cuprite, :rack_test].include?(@driver_type)
|
28
42
|
end
|
29
43
|
|
30
44
|
def register
|
31
|
-
@browser
|
45
|
+
@browser&.configure(&@capabilities)
|
32
46
|
|
33
|
-
Capybara.register_driver
|
34
|
-
case @
|
47
|
+
Capybara.register_driver name do |app|
|
48
|
+
case @driver_type
|
35
49
|
when :selenium then register_selenium(app)
|
36
50
|
when :poltergeist then register_poltergeist(app)
|
37
51
|
when :webkit then register_webkit(app)
|
52
|
+
when :cuprite then register_cuprite(app)
|
53
|
+
when :rack_test then register_rack_test(app)
|
38
54
|
end
|
39
55
|
end
|
40
56
|
end
|
41
57
|
|
42
58
|
def browser_options
|
43
|
-
@options.merge(
|
59
|
+
@options.merge(capabilities: @browser.options).compact
|
44
60
|
end
|
45
61
|
|
46
62
|
def register_selenium(app)
|
47
|
-
Capybara::Selenium::Driver.new(app,
|
63
|
+
Capybara::Selenium::Driver.new(app, browser: @browser.type, **browser_options).tap do |driver|
|
48
64
|
driver.browser.manage.window.size = Selenium::WebDriver::Dimension.new(*@screen_size)
|
49
65
|
end
|
50
66
|
end
|
@@ -59,8 +75,16 @@ module ActionDispatch
|
|
59
75
|
end
|
60
76
|
end
|
61
77
|
|
78
|
+
def register_cuprite(app)
|
79
|
+
Capybara::Cuprite::Driver.new(app, @options.merge(window_size: @screen_size))
|
80
|
+
end
|
81
|
+
|
82
|
+
def register_rack_test(app)
|
83
|
+
Capybara::RackTest::Driver.new(app, respect_data_method: true, **@options)
|
84
|
+
end
|
85
|
+
|
62
86
|
def setup
|
63
|
-
Capybara.current_driver =
|
87
|
+
Capybara.current_driver = name
|
64
88
|
end
|
65
89
|
end
|
66
90
|
end
|
@@ -15,8 +15,11 @@ module ActionDispatch
|
|
15
15
|
#
|
16
16
|
# The screenshot will be displayed in your console, if supported.
|
17
17
|
#
|
18
|
+
# The default screenshots directory is +tmp/screenshots+ but you can set a different
|
19
|
+
# one with +Capybara.save_path+
|
20
|
+
#
|
18
21
|
# You can set the +RAILS_SYSTEM_TESTING_SCREENSHOT_HTML+ environment variable to
|
19
|
-
# save the HTML from the page that is being
|
22
|
+
# save the HTML from the page that is being screenshotted so you can investigate the
|
20
23
|
# elements on the page at the time of the screenshot
|
21
24
|
#
|
22
25
|
# You can set the +RAILS_SYSTEM_TESTING_SCREENSHOT+ environment variable to
|
@@ -37,10 +40,7 @@ module ActionDispatch
|
|
37
40
|
# Takes a screenshot of the current page in the browser if the test
|
38
41
|
# failed.
|
39
42
|
#
|
40
|
-
# +take_failed_screenshot+ is
|
41
|
-
# that is generated with the application. To take screenshots when a test
|
42
|
-
# fails add +take_failed_screenshot+ to the teardown block before clearing
|
43
|
-
# sessions.
|
43
|
+
# +take_failed_screenshot+ is called during system test teardown.
|
44
44
|
def take_failed_screenshot
|
45
45
|
take_screenshot if failed? && supports_screenshot?
|
46
46
|
end
|
@@ -76,7 +76,11 @@ module ActionDispatch
|
|
76
76
|
end
|
77
77
|
|
78
78
|
def absolute_path
|
79
|
-
Rails.root.join(
|
79
|
+
Rails.root.join(screenshots_dir, image_name)
|
80
|
+
end
|
81
|
+
|
82
|
+
def screenshots_dir
|
83
|
+
Capybara.save_path.presence || "tmp/screenshots"
|
80
84
|
end
|
81
85
|
|
82
86
|
def absolute_image_path
|
@@ -4,14 +4,6 @@ module ActionDispatch
|
|
4
4
|
module SystemTesting
|
5
5
|
module TestHelpers
|
6
6
|
module SetupAndTeardown # :nodoc:
|
7
|
-
def host!(host)
|
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
|
-
|
12
|
-
Capybara.app_host = host
|
13
|
-
end
|
14
|
-
|
15
7
|
def before_teardown
|
16
8
|
take_failed_screenshot
|
17
9
|
ensure
|
@@ -1,14 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "rails-dom-testing"
|
4
|
+
require "action_dispatch/testing/assertions/response"
|
5
|
+
require "action_dispatch/testing/assertions/routing"
|
4
6
|
|
5
7
|
module ActionDispatch
|
6
8
|
module Assertions
|
7
|
-
autoload :ResponseAssertions, "action_dispatch/testing/assertions/response"
|
8
|
-
autoload :RoutingAssertions, "action_dispatch/testing/assertions/routing"
|
9
|
-
|
10
|
-
extend ActiveSupport::Concern
|
11
|
-
|
12
9
|
include ResponseAssertions
|
13
10
|
include RoutingAssertions
|
14
11
|
include Rails::Dom::Testing::Assertions
|