actionpack 7.0.8 → 7.1.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +360 -353
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -2
- data/lib/abstract_controller/base.rb +20 -11
- data/lib/abstract_controller/caching/fragments.rb +2 -0
- data/lib/abstract_controller/callbacks.rb +31 -6
- data/lib/abstract_controller/deprecator.rb +7 -0
- data/lib/abstract_controller/helpers.rb +61 -18
- data/lib/abstract_controller/railties/routes_helpers.rb +1 -16
- data/lib/abstract_controller/rendering.rb +3 -3
- data/lib/abstract_controller/translation.rb +7 -4
- data/lib/abstract_controller/url_for.rb +2 -0
- data/lib/abstract_controller.rb +6 -0
- data/lib/action_controller/api.rb +5 -3
- data/lib/action_controller/base.rb +3 -17
- data/lib/action_controller/caching.rb +2 -0
- data/lib/action_controller/deprecator.rb +7 -0
- data/lib/action_controller/form_builder.rb +2 -0
- data/lib/action_controller/log_subscriber.rb +16 -4
- data/lib/action_controller/metal/content_security_policy.rb +1 -1
- data/lib/action_controller/metal/data_streaming.rb +2 -0
- data/lib/action_controller/metal/default_headers.rb +2 -0
- data/lib/action_controller/metal/etag_with_flash.rb +2 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +2 -0
- data/lib/action_controller/metal/exceptions.rb +8 -0
- data/lib/action_controller/metal/head.rb +8 -6
- data/lib/action_controller/metal/helpers.rb +3 -14
- data/lib/action_controller/metal/http_authentication.rb +17 -8
- data/lib/action_controller/metal/implicit_render.rb +5 -3
- data/lib/action_controller/metal/instrumentation.rb +8 -1
- data/lib/action_controller/metal/live.rb +24 -0
- data/lib/action_controller/metal/mime_responds.rb +2 -2
- data/lib/action_controller/metal/params_wrapper.rb +4 -2
- data/lib/action_controller/metal/permissions_policy.rb +1 -1
- data/lib/action_controller/metal/redirecting.rb +7 -7
- data/lib/action_controller/metal/renderers.rb +2 -2
- data/lib/action_controller/metal/rendering.rb +0 -7
- data/lib/action_controller/metal/request_forgery_protection.rb +139 -50
- data/lib/action_controller/metal/rescue.rb +2 -0
- data/lib/action_controller/metal/streaming.rb +70 -30
- data/lib/action_controller/metal/strong_parameters.rb +132 -52
- data/lib/action_controller/metal/url_for.rb +7 -0
- data/lib/action_controller/metal.rb +79 -21
- data/lib/action_controller/railtie.rb +22 -9
- data/lib/action_controller/renderer.rb +98 -65
- data/lib/action_controller/test_case.rb +15 -5
- data/lib/action_controller.rb +8 -1
- data/lib/action_dispatch/constants.rb +32 -0
- data/lib/action_dispatch/deprecator.rb +7 -0
- data/lib/action_dispatch/http/cache.rb +1 -3
- data/lib/action_dispatch/http/content_security_policy.rb +9 -8
- data/lib/action_dispatch/http/filter_parameters.rb +11 -5
- data/lib/action_dispatch/http/headers.rb +2 -0
- data/lib/action_dispatch/http/mime_negotiation.rb +22 -22
- data/lib/action_dispatch/http/mime_type.rb +35 -12
- data/lib/action_dispatch/http/mime_types.rb +3 -1
- data/lib/action_dispatch/http/parameters.rb +1 -1
- data/lib/action_dispatch/http/permissions_policy.rb +40 -18
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +48 -14
- data/lib/action_dispatch/http/response.rb +80 -59
- data/lib/action_dispatch/http/upload.rb +2 -0
- data/lib/action_dispatch/journey/formatter.rb +8 -2
- data/lib/action_dispatch/journey/path/pattern.rb +14 -14
- data/lib/action_dispatch/journey/route.rb +3 -2
- data/lib/action_dispatch/journey/router.rb +9 -8
- data/lib/action_dispatch/journey/routes.rb +2 -2
- data/lib/action_dispatch/log_subscriber.rb +23 -0
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +5 -6
- data/lib/action_dispatch/middleware/assume_ssl.rb +24 -0
- data/lib/action_dispatch/middleware/callbacks.rb +2 -0
- data/lib/action_dispatch/middleware/cookies.rb +81 -98
- data/lib/action_dispatch/middleware/debug_exceptions.rb +26 -25
- data/lib/action_dispatch/middleware/debug_locks.rb +4 -1
- data/lib/action_dispatch/middleware/debug_view.rb +7 -2
- data/lib/action_dispatch/middleware/exception_wrapper.rb +186 -27
- data/lib/action_dispatch/middleware/executor.rb +1 -1
- data/lib/action_dispatch/middleware/flash.rb +7 -0
- data/lib/action_dispatch/middleware/host_authorization.rb +6 -3
- data/lib/action_dispatch/middleware/public_exceptions.rb +5 -3
- data/lib/action_dispatch/middleware/reloader.rb +7 -5
- data/lib/action_dispatch/middleware/remote_ip.rb +17 -16
- data/lib/action_dispatch/middleware/request_id.rb +2 -0
- data/lib/action_dispatch/middleware/server_timing.rb +4 -4
- data/lib/action_dispatch/middleware/session/abstract_store.rb +5 -0
- data/lib/action_dispatch/middleware/session/cache_store.rb +2 -0
- data/lib/action_dispatch/middleware/session/cookie_store.rb +11 -5
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +3 -1
- data/lib/action_dispatch/middleware/show_exceptions.rb +19 -15
- data/lib/action_dispatch/middleware/ssl.rb +18 -6
- data/lib/action_dispatch/middleware/stack.rb +7 -2
- data/lib/action_dispatch/middleware/static.rb +12 -8
- data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +8 -1
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +7 -7
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +17 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +16 -12
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +3 -0
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +46 -37
- data/lib/action_dispatch/railtie.rb +14 -4
- data/lib/action_dispatch/request/session.rb +16 -6
- data/lib/action_dispatch/request/utils.rb +8 -3
- data/lib/action_dispatch/routing/inspector.rb +54 -6
- data/lib/action_dispatch/routing/mapper.rb +35 -24
- data/lib/action_dispatch/routing/polymorphic_routes.rb +2 -0
- data/lib/action_dispatch/routing/redirection.rb +15 -6
- data/lib/action_dispatch/routing/route_set.rb +52 -22
- data/lib/action_dispatch/routing/routes_proxy.rb +10 -15
- data/lib/action_dispatch/routing/url_for.rb +5 -1
- data/lib/action_dispatch/routing.rb +7 -7
- data/lib/action_dispatch/system_test_case.rb +3 -3
- data/lib/action_dispatch/system_testing/browser.rb +20 -19
- data/lib/action_dispatch/system_testing/driver.rb +13 -21
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +27 -16
- data/lib/action_dispatch/testing/assertion_response.rb +1 -1
- data/lib/action_dispatch/testing/assertions/response.rb +13 -6
- data/lib/action_dispatch/testing/assertions/routing.rb +67 -28
- data/lib/action_dispatch/testing/assertions.rb +3 -1
- data/lib/action_dispatch/testing/integration.rb +27 -17
- data/lib/action_dispatch/testing/request_encoder.rb +4 -1
- data/lib/action_dispatch/testing/test_process.rb +4 -3
- data/lib/action_dispatch/testing/test_request.rb +1 -1
- data/lib/action_dispatch/testing/test_response.rb +23 -9
- data/lib/action_dispatch.rb +37 -4
- data/lib/action_pack/gem_version.rb +4 -4
- data/lib/action_pack/version.rb +1 -1
- data/lib/action_pack.rb +1 -1
- metadata +64 -28
@@ -34,20 +34,20 @@ module ActionDispatch
|
|
34
34
|
if @raise_on_name_error
|
35
35
|
raise
|
36
36
|
else
|
37
|
-
[404, {
|
37
|
+
[404, { Constants::X_CASCADE => "pass" }, []]
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
41
|
+
private
|
42
|
+
def controller(req)
|
43
|
+
req.controller_class
|
44
|
+
rescue NameError => e
|
45
|
+
raise ActionController::RoutingError, e.message, e.backtrace
|
46
|
+
end
|
47
47
|
|
48
|
-
|
49
|
-
|
50
|
-
|
48
|
+
def dispatch(controller, action, req, res)
|
49
|
+
controller.dispatch(action, req, res)
|
50
|
+
end
|
51
51
|
end
|
52
52
|
|
53
53
|
class StaticDispatcher < Dispatcher
|
@@ -282,7 +282,7 @@ module ActionDispatch
|
|
282
282
|
|
283
283
|
if args.size < path_params_size
|
284
284
|
path_params -= controller_options.keys
|
285
|
-
path_params -= result.keys
|
285
|
+
path_params -= (result[:path_params] || {}).merge(result).keys
|
286
286
|
else
|
287
287
|
path_params = path_params.dup
|
288
288
|
end
|
@@ -375,6 +375,7 @@ module ActionDispatch
|
|
375
375
|
@disable_clear_and_finalize = false
|
376
376
|
@finalized = false
|
377
377
|
@env_key = "ROUTES_#{object_id}_SCRIPT_NAME"
|
378
|
+
@default_env = nil
|
378
379
|
|
379
380
|
@set = Journey::Routes.new
|
380
381
|
@router = Journey::Router.new @set
|
@@ -405,6 +406,25 @@ module ActionDispatch
|
|
405
406
|
end
|
406
407
|
private :make_request
|
407
408
|
|
409
|
+
def default_env
|
410
|
+
if default_url_options != @default_env&.[]("action_dispatch.routes.default_url_options")
|
411
|
+
url_options = default_url_options.dup.freeze
|
412
|
+
uri = URI(ActionDispatch::Http::URL.full_url_for(host: "example.org", **url_options))
|
413
|
+
|
414
|
+
@default_env = {
|
415
|
+
"action_dispatch.routes" => self,
|
416
|
+
"action_dispatch.routes.default_url_options" => url_options,
|
417
|
+
"HTTPS" => uri.scheme == "https" ? "on" : "off",
|
418
|
+
"rack.url_scheme" => uri.scheme,
|
419
|
+
"HTTP_HOST" => uri.port == uri.default_port ? uri.host : "#{uri.host}:#{uri.port}",
|
420
|
+
"SCRIPT_NAME" => uri.path.chomp("/"),
|
421
|
+
"rack.input" => "",
|
422
|
+
}.freeze
|
423
|
+
end
|
424
|
+
|
425
|
+
@default_env
|
426
|
+
end
|
427
|
+
|
408
428
|
def draw(&block)
|
409
429
|
clear! unless @disable_clear_and_finalize
|
410
430
|
eval_block(block)
|
@@ -574,6 +594,20 @@ module ActionDispatch
|
|
574
594
|
end
|
575
595
|
|
576
596
|
private :_generate_paths_by_default
|
597
|
+
|
598
|
+
# If the module is included more than once (for example, in a subclass
|
599
|
+
# of an ancestor that includes the module), ensure that the `_routes`
|
600
|
+
# singleton and instance methods return the desired route set by
|
601
|
+
# including a new copy of the module (recursively if necessary). Note
|
602
|
+
# that this method is called for each inclusion, whereas the above
|
603
|
+
# `included` block is run only for the initial inclusion of each copy.
|
604
|
+
def self.included(base)
|
605
|
+
super
|
606
|
+
if base.respond_to?(:_routes) && !base._routes.equal?(@_proxy._routes)
|
607
|
+
@dup_for_reinclude ||= self.dup
|
608
|
+
base.include @dup_for_reinclude
|
609
|
+
end
|
610
|
+
end
|
577
611
|
end
|
578
612
|
end
|
579
613
|
|
@@ -596,16 +630,16 @@ module ActionDispatch
|
|
596
630
|
named_routes[name] = route if name
|
597
631
|
|
598
632
|
if route.segment_keys.include?(:controller)
|
599
|
-
|
633
|
+
ActionDispatch.deprecator.warn(<<-MSG.squish)
|
600
634
|
Using a dynamic :controller segment in a route is deprecated and
|
601
|
-
will be removed in Rails 7.
|
635
|
+
will be removed in Rails 7.2.
|
602
636
|
MSG
|
603
637
|
end
|
604
638
|
|
605
639
|
if route.segment_keys.include?(:action)
|
606
|
-
|
640
|
+
ActionDispatch.deprecator.warn(<<-MSG.squish)
|
607
641
|
Using a dynamic :action segment in a route is deprecated and
|
608
|
-
will be removed in Rails 7.
|
642
|
+
will be removed in Rails 7.2.
|
609
643
|
MSG
|
610
644
|
end
|
611
645
|
|
@@ -779,18 +813,14 @@ module ActionDispatch
|
|
779
813
|
|
780
814
|
RESERVED_OPTIONS = [:host, :protocol, :port, :subdomain, :domain, :tld_length,
|
781
815
|
:trailing_slash, :anchor, :params, :only_path, :script_name,
|
782
|
-
:original_script_name
|
816
|
+
:original_script_name]
|
783
817
|
|
784
818
|
def optimize_routes_generation?
|
785
819
|
default_url_options.empty?
|
786
820
|
end
|
787
821
|
|
788
822
|
def find_script_name(options)
|
789
|
-
options.delete(:script_name) ||
|
790
|
-
end
|
791
|
-
|
792
|
-
def find_relative_url_root(options)
|
793
|
-
options.delete(:relative_url_root) || relative_url_root
|
823
|
+
options.delete(:script_name) || relative_url_root || ""
|
794
824
|
end
|
795
825
|
|
796
826
|
def path_for(options, route_name = nil, reserved = RESERVED_OPTIONS)
|
@@ -854,7 +884,7 @@ module ActionDispatch
|
|
854
884
|
|
855
885
|
def recognize_path(path, environment = {})
|
856
886
|
method = (environment[:method] || "GET").to_s.upcase
|
857
|
-
path = Journey::Router::Utils.normalize_path(path) unless
|
887
|
+
path = Journey::Router::Utils.normalize_path(path) unless path&.include?("://")
|
858
888
|
extras = environment[:extras] || {}
|
859
889
|
|
860
890
|
begin
|
@@ -29,23 +29,18 @@ module ActionDispatch
|
|
29
29
|
|
30
30
|
def method_missing(method, *args)
|
31
31
|
if @helpers.respond_to?(method)
|
32
|
-
|
33
|
-
|
34
|
-
options = args.extract_options!
|
35
|
-
options = url_options.merge((options || {}).symbolize_keys)
|
32
|
+
options = args.extract_options!
|
33
|
+
options = url_options.merge((options || {}).symbolize_keys)
|
36
34
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
35
|
+
if @script_namer
|
36
|
+
options[:script_name] = merge_script_names(
|
37
|
+
options[:script_name],
|
38
|
+
@script_namer.call(options)
|
39
|
+
)
|
40
|
+
end
|
43
41
|
|
44
|
-
|
45
|
-
|
46
|
-
end
|
47
|
-
RUBY
|
48
|
-
public_send(method, *args)
|
42
|
+
args << options
|
43
|
+
@helpers.public_send(method, *args)
|
49
44
|
else
|
50
45
|
super
|
51
46
|
end
|
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
module ActionDispatch
|
4
4
|
module Routing
|
5
|
+
# = Action Dispatch Routing \UrlFor
|
6
|
+
#
|
5
7
|
# In <tt>config/routes.rb</tt> you define URL-to-controller mappings, but the reverse
|
6
8
|
# is also possible: a URL can be generated from one of your routing definitions.
|
7
9
|
# URL generation functionality is centralized in this module.
|
@@ -37,7 +39,7 @@ module ActionDispatch
|
|
37
39
|
# # => "/users/new?message=Welcome%21"
|
38
40
|
#
|
39
41
|
# Notice the <tt>only_path: true</tt> part. This is because UrlFor has no
|
40
|
-
# information about the website hostname that your Rails app is serving. So if you
|
42
|
+
# information about the website hostname that your \Rails app is serving. So if you
|
41
43
|
# want to include the hostname as well, then you must also pass the <tt>:host</tt>
|
42
44
|
# argument:
|
43
45
|
#
|
@@ -134,6 +136,8 @@ module ActionDispatch
|
|
134
136
|
# * <tt>:port</tt> - Optionally specify the port to connect to.
|
135
137
|
# * <tt>:anchor</tt> - An anchor name to be appended to the path.
|
136
138
|
# * <tt>:params</tt> - The query parameters to be appended to the path.
|
139
|
+
# * <tt>:path_params</tt> - The query parameters that will only be used
|
140
|
+
# for the named dynamic segments of path. If unused, they will be discarded.
|
137
141
|
# * <tt>:trailing_slash</tt> - If true, adds a trailing slash, as in <tt>"/archive/2009/"</tt>.
|
138
142
|
# * <tt>:script_name</tt> - Specifies application path relative to domain root. If provided, prepends application path.
|
139
143
|
#
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/core_ext/string/filters"
|
4
|
-
|
5
3
|
module ActionDispatch
|
6
4
|
# The routing module provides URL rewriting in native Ruby. It's a way to
|
7
5
|
# redirect incoming requests to controllers and actions. This replaces
|
@@ -119,9 +117,9 @@ module ActionDispatch
|
|
119
117
|
#
|
120
118
|
# # In config/routes.rb
|
121
119
|
# controller :blog do
|
122
|
-
# get 'blog/show'
|
123
|
-
# get 'blog/delete'
|
124
|
-
# get 'blog/edit'
|
120
|
+
# get 'blog/show' => :list
|
121
|
+
# get 'blog/delete' => :delete
|
122
|
+
# get 'blog/edit' => :edit
|
125
123
|
# end
|
126
124
|
#
|
127
125
|
# # provides named routes for show, delete, and edit
|
@@ -240,7 +238,7 @@ module ActionDispatch
|
|
240
238
|
#
|
241
239
|
# == View a list of all your routes
|
242
240
|
#
|
243
|
-
# rails routes
|
241
|
+
# $ bin/rails routes
|
244
242
|
#
|
245
243
|
# Target a specific controller with <tt>-c</tt>, or grep routes
|
246
244
|
# using <tt>-g</tt>. Useful in conjunction with <tt>--expanded</tt>
|
@@ -250,7 +248,9 @@ module ActionDispatch
|
|
250
248
|
|
251
249
|
autoload :Mapper
|
252
250
|
autoload :RouteSet
|
253
|
-
|
251
|
+
eager_autoload do
|
252
|
+
autoload :RoutesProxy
|
253
|
+
end
|
254
254
|
autoload :UrlFor
|
255
255
|
autoload :PolymorphicRoutes
|
256
256
|
|
@@ -51,7 +51,7 @@ module ActionDispatch
|
|
51
51
|
# driven_by :selenium, using: :chrome, screen_size: [1400, 1400]
|
52
52
|
# end
|
53
53
|
#
|
54
|
-
# By default,
|
54
|
+
# By default, +ActionDispatch::SystemTestCase+ is driven by the
|
55
55
|
# Selenium driver, with the Chrome browser, and a browser size of 1400x1400.
|
56
56
|
#
|
57
57
|
# Changing the driver configuration options is easy. Let's say you want to use
|
@@ -106,8 +106,8 @@ module ActionDispatch
|
|
106
106
|
# end
|
107
107
|
# end
|
108
108
|
#
|
109
|
-
# Because
|
110
|
-
# and Rails, any driver that is supported by Capybara is supported by system
|
109
|
+
# Because +ActionDispatch::SystemTestCase+ is a shim between Capybara
|
110
|
+
# and \Rails, any driver that is supported by Capybara is supported by system
|
111
111
|
# tests as long as you include the required gems and files.
|
112
112
|
class SystemTestCase < ActiveSupport::TestCase
|
113
113
|
include Capybara::DSL
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module ActionDispatch
|
4
4
|
module SystemTesting
|
5
5
|
class Browser # :nodoc:
|
6
|
-
attr_reader :name
|
6
|
+
attr_reader :name
|
7
7
|
|
8
8
|
def initialize(name)
|
9
9
|
@name = name
|
@@ -21,35 +21,32 @@ module ActionDispatch
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
+
def options
|
25
|
+
@options ||=
|
26
|
+
case type
|
27
|
+
when :chrome
|
28
|
+
::Selenium::WebDriver::Chrome::Options.new
|
29
|
+
when :firefox
|
30
|
+
::Selenium::WebDriver::Firefox::Options.new
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
24
34
|
def configure
|
25
|
-
|
26
|
-
yield options if block_given? && options
|
35
|
+
yield options if block_given?
|
27
36
|
end
|
28
37
|
|
29
|
-
# driver_path
|
30
|
-
#
|
31
|
-
# update the webdriver once and avoid race conditions when using
|
32
|
-
# parallel tests.
|
38
|
+
# driver_path is lazily initialized by default. Eagerly set it to
|
39
|
+
# avoid race conditions when using parallel tests.
|
33
40
|
def preload
|
34
41
|
case type
|
35
42
|
when :chrome
|
36
|
-
::Selenium::WebDriver::Chrome
|
43
|
+
resolve_driver_path(::Selenium::WebDriver::Chrome)
|
37
44
|
when :firefox
|
38
|
-
::Selenium::WebDriver::Firefox
|
45
|
+
resolve_driver_path(::Selenium::WebDriver::Firefox)
|
39
46
|
end
|
40
47
|
end
|
41
48
|
|
42
49
|
private
|
43
|
-
def initialize_options
|
44
|
-
@options ||=
|
45
|
-
case type
|
46
|
-
when :chrome
|
47
|
-
::Selenium::WebDriver::Chrome::Options.new
|
48
|
-
when :firefox
|
49
|
-
::Selenium::WebDriver::Firefox::Options.new
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
50
|
def set_default_options
|
54
51
|
case name
|
55
52
|
when :headless_chrome
|
@@ -71,6 +68,10 @@ module ActionDispatch
|
|
71
68
|
capabilities.add_argument("-headless")
|
72
69
|
end
|
73
70
|
end
|
71
|
+
|
72
|
+
def resolve_driver_path(namespace)
|
73
|
+
namespace::Service.driver_path = ::Selenium::WebDriver::DriverFinder.path(options, namespace::Service)
|
74
|
+
end
|
74
75
|
end
|
75
76
|
end
|
76
77
|
end
|
@@ -12,14 +12,6 @@ module ActionDispatch
|
|
12
12
|
@name = @options.delete(:name) || driver_type
|
13
13
|
@capabilities = capabilities
|
14
14
|
|
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
15
|
if driver_type == :selenium
|
24
16
|
gem "selenium-webdriver", ">= 4.0.0"
|
25
17
|
require "selenium/webdriver"
|
@@ -38,7 +30,7 @@ module ActionDispatch
|
|
38
30
|
|
39
31
|
private
|
40
32
|
def registerable?
|
41
|
-
[:selenium, :
|
33
|
+
[:selenium, :cuprite, :rack_test, :playwright].include?(@driver_type)
|
42
34
|
end
|
43
35
|
|
44
36
|
def register
|
@@ -47,10 +39,9 @@ module ActionDispatch
|
|
47
39
|
Capybara.register_driver name do |app|
|
48
40
|
case @driver_type
|
49
41
|
when :selenium then register_selenium(app)
|
50
|
-
when :poltergeist then register_poltergeist(app)
|
51
|
-
when :webkit then register_webkit(app)
|
52
42
|
when :cuprite then register_cuprite(app)
|
53
43
|
when :rack_test then register_rack_test(app)
|
44
|
+
when :playwright then register_playwright(app)
|
54
45
|
end
|
55
46
|
end
|
56
47
|
end
|
@@ -65,16 +56,6 @@ module ActionDispatch
|
|
65
56
|
end
|
66
57
|
end
|
67
58
|
|
68
|
-
def register_poltergeist(app)
|
69
|
-
Capybara::Poltergeist::Driver.new(app, @options.merge(window_size: @screen_size))
|
70
|
-
end
|
71
|
-
|
72
|
-
def register_webkit(app)
|
73
|
-
Capybara::Webkit::Driver.new(app, Capybara::Webkit::Configuration.to_hash.merge(@options)).tap do |driver|
|
74
|
-
driver.resize_window_to(driver.current_window_handle, *@screen_size)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
59
|
def register_cuprite(app)
|
79
60
|
Capybara::Cuprite::Driver.new(app, @options.merge(window_size: @screen_size))
|
80
61
|
end
|
@@ -83,6 +64,17 @@ module ActionDispatch
|
|
83
64
|
Capybara::RackTest::Driver.new(app, respect_data_method: true, **@options)
|
84
65
|
end
|
85
66
|
|
67
|
+
def register_playwright(app)
|
68
|
+
screen = { width: @screen_size[0], height: @screen_size[1] } if @screen_size
|
69
|
+
options = {
|
70
|
+
screen: screen,
|
71
|
+
viewport: screen,
|
72
|
+
**@options
|
73
|
+
}.compact
|
74
|
+
|
75
|
+
Capybara::Playwright::Driver.new(app, **options)
|
76
|
+
end
|
77
|
+
|
86
78
|
def setup
|
87
79
|
Capybara.current_driver = name
|
88
80
|
end
|
@@ -13,28 +13,28 @@ module ActionDispatch
|
|
13
13
|
# to investigate changes at different points during your test. These will be
|
14
14
|
# named with a sequential prefix (or 'failed' for failing tests)
|
15
15
|
#
|
16
|
-
# The screenshot will be displayed in your console, if supported.
|
17
|
-
#
|
18
16
|
# The default screenshots directory is +tmp/screenshots+ but you can set a different
|
19
17
|
# one with +Capybara.save_path+
|
20
18
|
#
|
21
|
-
# You can
|
22
|
-
# save the HTML from the page that is being screenshotted
|
23
|
-
# elements on the page at the time of the screenshot
|
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
|
24
22
|
#
|
25
|
-
# You can
|
26
|
-
# control the output. Possible values are:
|
23
|
+
# You can use the +screenshot+ argument or set the +RAILS_SYSTEM_TESTING_SCREENSHOT+
|
24
|
+
# environment variable to control the output. Possible values are:
|
27
25
|
# * [+simple+ (default)] Only displays the screenshot path.
|
28
26
|
# This is the default value.
|
29
27
|
# * [+inline+] Display the screenshot in the terminal using the
|
30
28
|
# iTerm image protocol (https://iterm2.com/documentation-images.html).
|
31
29
|
# * [+artifact+] Display the screenshot in the terminal, using the terminal
|
32
30
|
# artifact format (https://buildkite.github.io/terminal-to-html/inline-images/).
|
33
|
-
def take_screenshot
|
31
|
+
def take_screenshot(html: false, screenshot: nil)
|
32
|
+
showing_html = html || html_from_env?
|
33
|
+
|
34
34
|
increment_unique
|
35
|
-
save_html if
|
35
|
+
save_html if showing_html
|
36
36
|
save_image
|
37
|
-
|
37
|
+
show display_image(html: showing_html, screenshot_output: screenshot)
|
38
38
|
end
|
39
39
|
|
40
40
|
# Takes a screenshot of the current page in the browser if the test
|
@@ -42,13 +42,16 @@ module ActionDispatch
|
|
42
42
|
#
|
43
43
|
# +take_failed_screenshot+ is called during system test teardown.
|
44
44
|
def take_failed_screenshot
|
45
|
-
|
45
|
+
return unless failed? && supports_screenshot? && Capybara::Session.instance_created?
|
46
|
+
|
47
|
+
take_screenshot
|
48
|
+
metadata[:failure_screenshot_path] = relative_image_path if Minitest::Runnable.method_defined?(:metadata)
|
46
49
|
end
|
47
50
|
|
48
51
|
private
|
49
52
|
attr_accessor :_screenshot_counter
|
50
53
|
|
51
|
-
def
|
54
|
+
def html_from_env?
|
52
55
|
ENV["RAILS_SYSTEM_TESTING_SCREENSHOT_HTML"] == "1"
|
53
56
|
end
|
54
57
|
|
@@ -62,7 +65,7 @@ module ActionDispatch
|
|
62
65
|
end
|
63
66
|
|
64
67
|
def image_name
|
65
|
-
sanitized_method_name = method_name.
|
68
|
+
sanitized_method_name = method_name.gsub(/[^\w]+/, "-")
|
66
69
|
name = "#{unique}_#{sanitized_method_name}"
|
67
70
|
name[0...225]
|
68
71
|
end
|
@@ -87,6 +90,10 @@ module ActionDispatch
|
|
87
90
|
"#{absolute_path}.png"
|
88
91
|
end
|
89
92
|
|
93
|
+
def relative_image_path
|
94
|
+
"#{absolute_path.relative_path_from(Rails.root)}.png"
|
95
|
+
end
|
96
|
+
|
90
97
|
def absolute_html_path
|
91
98
|
"#{absolute_path}.html"
|
92
99
|
end
|
@@ -109,11 +116,15 @@ module ActionDispatch
|
|
109
116
|
output_type
|
110
117
|
end
|
111
118
|
|
112
|
-
def
|
119
|
+
def show(img)
|
120
|
+
puts img
|
121
|
+
end
|
122
|
+
|
123
|
+
def display_image(html:, screenshot_output:)
|
113
124
|
message = +"[Screenshot Image]: #{image_path}\n"
|
114
|
-
message << +"[Screenshot HTML]: #{html_path}\n" if
|
125
|
+
message << +"[Screenshot HTML]: #{html_path}\n" if html
|
115
126
|
|
116
|
-
case output_type
|
127
|
+
case screenshot_output || output_type
|
117
128
|
when "artifact"
|
118
129
|
message << "\e]1338;url=artifact://#{absolute_image_path}\a\n"
|
119
130
|
when "inline"
|
@@ -30,7 +30,7 @@ module ActionDispatch
|
|
30
30
|
def assert_response(type, message = nil)
|
31
31
|
message ||= generate_response_message(type)
|
32
32
|
|
33
|
-
if RESPONSE_PREDICATES.
|
33
|
+
if RESPONSE_PREDICATES.key?(type)
|
34
34
|
assert @response.public_send(RESPONSE_PREDICATES[type]), message
|
35
35
|
else
|
36
36
|
assert_equal AssertionResponse.new(type).code, @response.response_code, message
|
@@ -50,12 +50,19 @@ module ActionDispatch
|
|
50
50
|
#
|
51
51
|
# # Asserts that the redirection matches the regular expression
|
52
52
|
# assert_redirected_to %r(\Ahttp://example.org)
|
53
|
-
|
54
|
-
|
55
|
-
|
53
|
+
#
|
54
|
+
# # Asserts that the redirection has the HTTP status code 301 (Moved
|
55
|
+
# # Permanently).
|
56
|
+
# assert_redirected_to "/some/path", status: :moved_permanently
|
57
|
+
def assert_redirected_to(url_options = {}, options = {}, message = nil)
|
58
|
+
options, message = {}, options unless options.is_a?(Hash)
|
59
|
+
|
60
|
+
status = options[:status] || :redirect
|
61
|
+
assert_response(status, message)
|
62
|
+
return true if url_options === @response.location
|
56
63
|
|
57
64
|
redirect_is = normalize_argument_to_redirection(@response.location)
|
58
|
-
redirect_expected = normalize_argument_to_redirection(
|
65
|
+
redirect_expected = normalize_argument_to_redirection(url_options)
|
59
66
|
|
60
67
|
message ||= "Expected response to be a redirect to <#{redirect_expected}> but was a redirect to <#{redirect_is}>"
|
61
68
|
assert_operator redirect_expected, :===, redirect_is, message
|
@@ -93,7 +100,7 @@ module ActionDispatch
|
|
93
100
|
end
|
94
101
|
|
95
102
|
def code_with_name(code_or_name)
|
96
|
-
if RESPONSE_PREDICATES.
|
103
|
+
if RESPONSE_PREDICATES.value?("#{code_or_name}?".to_sym)
|
97
104
|
code_or_name = RESPONSE_PREDICATES.invert["#{code_or_name}?".to_sym]
|
98
105
|
end
|
99
106
|
|