actionpack 4.2.8 → 5.2.4.2
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 +5 -5
- data/CHANGELOG.md +285 -444
- data/MIT-LICENSE +1 -1
- data/README.rdoc +6 -7
- data/lib/abstract_controller.rb +12 -5
- data/lib/abstract_controller/asset_paths.rb +2 -0
- data/lib/abstract_controller/base.rb +45 -49
- data/lib/abstract_controller/caching.rb +66 -0
- data/lib/{action_controller → abstract_controller}/caching/fragments.rb +78 -15
- data/lib/abstract_controller/callbacks.rb +47 -31
- data/lib/abstract_controller/collector.rb +8 -11
- data/lib/abstract_controller/error.rb +6 -0
- data/lib/abstract_controller/helpers.rb +25 -25
- data/lib/abstract_controller/logger.rb +2 -0
- data/lib/abstract_controller/railties/routes_helpers.rb +4 -2
- data/lib/abstract_controller/rendering.rb +42 -41
- data/lib/abstract_controller/translation.rb +10 -7
- data/lib/abstract_controller/url_for.rb +2 -0
- data/lib/action_controller.rb +29 -21
- data/lib/action_controller/api.rb +149 -0
- data/lib/action_controller/api/api_rendering.rb +16 -0
- data/lib/action_controller/base.rb +27 -19
- data/lib/action_controller/caching.rb +14 -57
- data/lib/action_controller/form_builder.rb +50 -0
- data/lib/action_controller/log_subscriber.rb +10 -15
- data/lib/action_controller/metal.rb +98 -83
- data/lib/action_controller/metal/basic_implicit_render.rb +13 -0
- data/lib/action_controller/metal/conditional_get.rb +118 -44
- data/lib/action_controller/metal/content_security_policy.rb +52 -0
- data/lib/action_controller/metal/cookies.rb +3 -3
- data/lib/action_controller/metal/data_streaming.rb +27 -46
- data/lib/action_controller/metal/etag_with_flash.rb +18 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +20 -13
- data/lib/action_controller/metal/exceptions.rb +8 -14
- data/lib/action_controller/metal/flash.rb +4 -3
- data/lib/action_controller/metal/force_ssl.rb +23 -21
- data/lib/action_controller/metal/head.rb +21 -19
- data/lib/action_controller/metal/helpers.rb +24 -14
- data/lib/action_controller/metal/http_authentication.rb +64 -57
- data/lib/action_controller/metal/implicit_render.rb +62 -8
- data/lib/action_controller/metal/instrumentation.rb +19 -21
- data/lib/action_controller/metal/live.rb +90 -106
- data/lib/action_controller/metal/mime_responds.rb +33 -46
- data/lib/action_controller/metal/parameter_encoding.rb +51 -0
- data/lib/action_controller/metal/params_wrapper.rb +61 -53
- data/lib/action_controller/metal/redirecting.rb +49 -28
- data/lib/action_controller/metal/renderers.rb +87 -44
- data/lib/action_controller/metal/rendering.rb +72 -50
- data/lib/action_controller/metal/request_forgery_protection.rb +203 -92
- data/lib/action_controller/metal/rescue.rb +9 -16
- data/lib/action_controller/metal/streaming.rb +12 -10
- data/lib/action_controller/metal/strong_parameters.rb +582 -165
- data/lib/action_controller/metal/testing.rb +2 -17
- data/lib/action_controller/metal/url_for.rb +19 -10
- data/lib/action_controller/railtie.rb +28 -10
- data/lib/action_controller/railties/helpers.rb +2 -0
- data/lib/action_controller/renderer.rb +117 -0
- data/lib/action_controller/template_assertions.rb +11 -0
- data/lib/action_controller/test_case.rb +280 -411
- data/lib/action_dispatch.rb +27 -19
- data/lib/action_dispatch/http/cache.rb +93 -47
- data/lib/action_dispatch/http/content_security_policy.rb +272 -0
- data/lib/action_dispatch/http/filter_parameters.rb +26 -20
- data/lib/action_dispatch/http/filter_redirect.rb +10 -11
- data/lib/action_dispatch/http/headers.rb +55 -22
- data/lib/action_dispatch/http/mime_negotiation.rb +60 -41
- data/lib/action_dispatch/http/mime_type.rb +134 -121
- data/lib/action_dispatch/http/mime_types.rb +20 -6
- data/lib/action_dispatch/http/parameter_filter.rb +25 -11
- data/lib/action_dispatch/http/parameters.rb +98 -39
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +200 -118
- data/lib/action_dispatch/http/response.rb +225 -110
- data/lib/action_dispatch/http/upload.rb +12 -6
- data/lib/action_dispatch/http/url.rb +110 -28
- data/lib/action_dispatch/journey.rb +7 -5
- data/lib/action_dispatch/journey/formatter.rb +55 -32
- data/lib/action_dispatch/journey/gtg/builder.rb +7 -5
- data/lib/action_dispatch/journey/gtg/simulator.rb +3 -9
- data/lib/action_dispatch/journey/gtg/transition_table.rb +17 -16
- data/lib/action_dispatch/journey/nfa/builder.rb +5 -3
- data/lib/action_dispatch/journey/nfa/dot.rb +13 -13
- data/lib/action_dispatch/journey/nfa/simulator.rb +3 -1
- data/lib/action_dispatch/journey/nfa/transition_table.rb +5 -48
- data/lib/action_dispatch/journey/nodes/node.rb +18 -6
- data/lib/action_dispatch/journey/parser.rb +23 -22
- data/lib/action_dispatch/journey/parser.y +3 -2
- data/lib/action_dispatch/journey/parser_extras.rb +12 -4
- data/lib/action_dispatch/journey/path/pattern.rb +50 -44
- data/lib/action_dispatch/journey/route.rb +106 -28
- data/lib/action_dispatch/journey/router.rb +35 -23
- data/lib/action_dispatch/journey/router/utils.rb +20 -11
- data/lib/action_dispatch/journey/routes.rb +18 -16
- data/lib/action_dispatch/journey/scanner.rb +18 -15
- data/lib/action_dispatch/journey/visitors.rb +99 -52
- data/lib/action_dispatch/middleware/callbacks.rb +1 -2
- data/lib/action_dispatch/middleware/cookies.rb +304 -193
- data/lib/action_dispatch/middleware/debug_exceptions.rb +152 -57
- data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +68 -69
- data/lib/action_dispatch/middleware/executor.rb +21 -0
- data/lib/action_dispatch/middleware/flash.rb +78 -54
- data/lib/action_dispatch/middleware/public_exceptions.rb +27 -25
- data/lib/action_dispatch/middleware/reloader.rb +5 -91
- data/lib/action_dispatch/middleware/remote_ip.rb +41 -31
- data/lib/action_dispatch/middleware/request_id.rb +17 -9
- data/lib/action_dispatch/middleware/session/abstract_store.rb +41 -25
- data/lib/action_dispatch/middleware/session/cache_store.rb +24 -14
- data/lib/action_dispatch/middleware/session/cookie_store.rb +72 -67
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -2
- data/lib/action_dispatch/middleware/show_exceptions.rb +26 -22
- data/lib/action_dispatch/middleware/ssl.rb +114 -36
- data/lib/action_dispatch/middleware/stack.rb +31 -44
- data/lib/action_dispatch/middleware/static.rb +57 -50
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +2 -14
- data/lib/action_dispatch/middleware/templates/rescues/{_source.erb → _source.html.erb} +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +21 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +13 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +64 -64
- data/lib/action_dispatch/railtie.rb +19 -11
- data/lib/action_dispatch/request/session.rb +106 -59
- data/lib/action_dispatch/request/utils.rb +67 -24
- data/lib/action_dispatch/routing.rb +17 -18
- data/lib/action_dispatch/routing/endpoint.rb +9 -2
- data/lib/action_dispatch/routing/inspector.rb +58 -67
- data/lib/action_dispatch/routing/mapper.rb +734 -447
- data/lib/action_dispatch/routing/polymorphic_routes.rb +161 -139
- data/lib/action_dispatch/routing/redirection.rb +36 -26
- data/lib/action_dispatch/routing/route_set.rb +321 -291
- data/lib/action_dispatch/routing/routes_proxy.rb +32 -5
- data/lib/action_dispatch/routing/url_for.rb +65 -25
- data/lib/action_dispatch/system_test_case.rb +147 -0
- data/lib/action_dispatch/system_testing/browser.rb +49 -0
- data/lib/action_dispatch/system_testing/driver.rb +59 -0
- data/lib/action_dispatch/system_testing/server.rb +31 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +96 -0
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +31 -0
- data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +26 -0
- data/lib/action_dispatch/testing/assertion_response.rb +47 -0
- data/lib/action_dispatch/testing/assertions.rb +6 -4
- data/lib/action_dispatch/testing/assertions/response.rb +45 -20
- data/lib/action_dispatch/testing/assertions/routing.rb +30 -26
- data/lib/action_dispatch/testing/integration.rb +347 -209
- data/lib/action_dispatch/testing/request_encoder.rb +55 -0
- data/lib/action_dispatch/testing/test_process.rb +28 -22
- data/lib/action_dispatch/testing/test_request.rb +27 -34
- data/lib/action_dispatch/testing/test_response.rb +35 -7
- data/lib/action_pack.rb +4 -2
- data/lib/action_pack/gem_version.rb +5 -3
- data/lib/action_pack/version.rb +3 -1
- metadata +56 -39
- data/lib/action_controller/metal/hide_actions.rb +0 -40
- data/lib/action_controller/metal/rack_delegation.rb +0 -32
- data/lib/action_controller/middleware.rb +0 -39
- data/lib/action_controller/model_naming.rb +0 -12
- data/lib/action_dispatch/journey/backwards.rb +0 -5
- data/lib/action_dispatch/journey/router/strexp.rb +0 -27
- data/lib/action_dispatch/middleware/params_parser.rb +0 -60
- data/lib/action_dispatch/testing/assertions/dom.rb +0 -3
- data/lib/action_dispatch/testing/assertions/selector.rb +0 -3
- data/lib/action_dispatch/testing/assertions/tag.rb +0 -3
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/array/extract_options"
|
2
4
|
|
3
5
|
module ActionDispatch
|
4
6
|
module Routing
|
@@ -8,9 +10,10 @@ module ActionDispatch
|
|
8
10
|
attr_accessor :scope, :routes
|
9
11
|
alias :_routes :routes
|
10
12
|
|
11
|
-
def initialize(routes, scope, helpers)
|
13
|
+
def initialize(routes, scope, helpers, script_namer = nil)
|
12
14
|
@routes, @scope = routes, scope
|
13
15
|
@helpers = helpers
|
16
|
+
@script_namer = script_namer
|
14
17
|
end
|
15
18
|
|
16
19
|
def url_options
|
@@ -19,7 +22,8 @@ module ActionDispatch
|
|
19
22
|
end
|
20
23
|
end
|
21
24
|
|
22
|
-
|
25
|
+
private
|
26
|
+
def respond_to_missing?(method, _)
|
23
27
|
super || @helpers.respond_to?(method)
|
24
28
|
end
|
25
29
|
|
@@ -28,15 +32,38 @@ module ActionDispatch
|
|
28
32
|
self.class.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
29
33
|
def #{method}(*args)
|
30
34
|
options = args.extract_options!
|
31
|
-
|
35
|
+
options = url_options.merge((options || {}).symbolize_keys)
|
36
|
+
|
37
|
+
if @script_namer
|
38
|
+
options[:script_name] = merge_script_names(
|
39
|
+
options[:script_name],
|
40
|
+
@script_namer.call(options)
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
args << options
|
32
45
|
@helpers.#{method}(*args)
|
33
46
|
end
|
34
47
|
RUBY
|
35
|
-
|
48
|
+
public_send(method, *args)
|
36
49
|
else
|
37
50
|
super
|
38
51
|
end
|
39
52
|
end
|
53
|
+
|
54
|
+
# Keeps the part of the script name provided by the global
|
55
|
+
# context via ENV["SCRIPT_NAME"], which `mount` doesn't know
|
56
|
+
# about since it depends on the specific request, but use our
|
57
|
+
# script name resolver for the mount point dependent part.
|
58
|
+
def merge_script_names(previous_script_name, new_script_name)
|
59
|
+
return new_script_name unless previous_script_name
|
60
|
+
|
61
|
+
resolved_parts = new_script_name.count("/")
|
62
|
+
previous_parts = previous_script_name.count("/")
|
63
|
+
context_parts = previous_parts - resolved_parts + 1
|
64
|
+
|
65
|
+
(previous_script_name.split("/").slice(0, context_parts).join("/")) + new_script_name
|
66
|
+
end
|
40
67
|
end
|
41
68
|
end
|
42
69
|
end
|
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActionDispatch
|
2
4
|
module Routing
|
3
5
|
# In <tt>config/routes.rb</tt> you define URL-to-controller mappings, but the reverse
|
4
|
-
# is also possible:
|
6
|
+
# is also possible: a URL can be generated from one of your routing definitions.
|
5
7
|
# URL generation functionality is centralized in this module.
|
6
8
|
#
|
7
9
|
# See ActionDispatch::Routing for general information about routing and routes.rb.
|
@@ -52,9 +54,11 @@ module ActionDispatch
|
|
52
54
|
# argument.
|
53
55
|
#
|
54
56
|
# For convenience reasons, mailers provide a shortcut for ActionController::UrlFor#url_for.
|
55
|
-
# So within mailers, you only have to type
|
56
|
-
# in full. However, mailers don't have hostname information, and
|
57
|
-
#
|
57
|
+
# So within mailers, you only have to type +url_for+ instead of 'ActionController::UrlFor#url_for'
|
58
|
+
# in full. However, mailers don't have hostname information, and you still have to provide
|
59
|
+
# the +:host+ argument or set the default host that will be used in all mailers using the
|
60
|
+
# configuration option +config.action_mailer.default_url_options+. For more information on
|
61
|
+
# url_for in mailers read the ActionMailer#Base documentation.
|
58
62
|
#
|
59
63
|
#
|
60
64
|
# == URL generation for named routes
|
@@ -105,16 +109,16 @@ module ActionDispatch
|
|
105
109
|
end
|
106
110
|
|
107
111
|
# Hook overridden in controller to add request information
|
108
|
-
# with
|
112
|
+
# with +default_url_options+. Application logic should not
|
109
113
|
# go into url_options.
|
110
114
|
def url_options
|
111
115
|
default_url_options
|
112
116
|
end
|
113
117
|
|
114
|
-
# Generate a
|
118
|
+
# Generate a URL based on the options provided, default_url_options and the
|
115
119
|
# routes defined in routes.rb. The following options are supported:
|
116
120
|
#
|
117
|
-
# * <tt>:only_path</tt> - If true, the relative
|
121
|
+
# * <tt>:only_path</tt> - If true, the relative URL is returned. Defaults to +false+.
|
118
122
|
# * <tt>:protocol</tt> - The protocol to connect to. Defaults to 'http'.
|
119
123
|
# * <tt>:host</tt> - Specifies the host the link should be targeted at.
|
120
124
|
# If <tt>:only_path</tt> is false, this option must be
|
@@ -147,14 +151,32 @@ module ActionDispatch
|
|
147
151
|
# # => 'http://somehost.org/myapp/tasks/testing'
|
148
152
|
# url_for controller: 'tasks', action: 'testing', host: 'somehost.org', script_name: "/myapp", only_path: true
|
149
153
|
# # => '/myapp/tasks/testing'
|
154
|
+
#
|
155
|
+
# Missing routes keys may be filled in from the current request's parameters
|
156
|
+
# (e.g. +:controller+, +:action+, +:id+ and any other parameters that are
|
157
|
+
# placed in the path). Given that the current action has been reached
|
158
|
+
# through <tt>GET /users/1</tt>:
|
159
|
+
#
|
160
|
+
# url_for(only_path: true) # => '/users/1'
|
161
|
+
# url_for(only_path: true, action: 'edit') # => '/users/1/edit'
|
162
|
+
# url_for(only_path: true, action: 'edit', id: 2) # => '/users/2/edit'
|
163
|
+
#
|
164
|
+
# Notice that no +:id+ parameter was provided to the first +url_for+ call
|
165
|
+
# and the helper used the one from the route's path. Any path parameter
|
166
|
+
# implicitly used by +url_for+ can always be overwritten like shown on the
|
167
|
+
# last +url_for+ calls.
|
150
168
|
def url_for(options = nil)
|
169
|
+
full_url_for(options)
|
170
|
+
end
|
171
|
+
|
172
|
+
def full_url_for(options = nil) # :nodoc:
|
151
173
|
case options
|
152
174
|
when nil
|
153
175
|
_routes.url_for(url_options.symbolize_keys)
|
154
|
-
when Hash
|
176
|
+
when Hash, ActionController::Parameters
|
155
177
|
route_name = options.delete :use_route
|
156
|
-
|
157
|
-
|
178
|
+
merged_url_options = options.to_h.symbolize_keys.reverse_merge!(url_options)
|
179
|
+
_routes.url_for(merged_url_options, route_name)
|
158
180
|
when String
|
159
181
|
options
|
160
182
|
when Symbol
|
@@ -169,27 +191,45 @@ module ActionDispatch
|
|
169
191
|
end
|
170
192
|
end
|
171
193
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
194
|
+
# Allows calling direct or regular named route.
|
195
|
+
#
|
196
|
+
# resources :buckets
|
197
|
+
#
|
198
|
+
# direct :recordable do |recording|
|
199
|
+
# route_for(:bucket, recording.bucket)
|
200
|
+
# end
|
201
|
+
#
|
202
|
+
# direct :threadable do |threadable|
|
203
|
+
# route_for(:recordable, threadable.parent)
|
204
|
+
# end
|
205
|
+
#
|
206
|
+
# This maintains the context of the original caller on
|
207
|
+
# whether to return a path or full URL, e.g:
|
208
|
+
#
|
209
|
+
# threadable_path(threadable) # => "/buckets/1"
|
210
|
+
# threadable_url(threadable) # => "http://example.com/buckets/1"
|
211
|
+
#
|
212
|
+
def route_for(name, *args)
|
213
|
+
public_send(:"#{name}_url", *args)
|
176
214
|
end
|
177
215
|
|
178
|
-
|
179
|
-
old_routes, @_routes = @_routes, routes
|
180
|
-
yield
|
181
|
-
ensure
|
182
|
-
@_routes = old_routes
|
183
|
-
end
|
216
|
+
protected
|
184
217
|
|
185
|
-
|
186
|
-
|
187
|
-
|
218
|
+
def optimize_routes_generation?
|
219
|
+
_routes.optimize_routes_generation? && default_url_options.empty?
|
220
|
+
end
|
188
221
|
|
189
222
|
private
|
190
223
|
|
191
|
-
def
|
192
|
-
|
224
|
+
def _with_routes(routes) # :doc:
|
225
|
+
old_routes, @_routes = @_routes, routes
|
226
|
+
yield
|
227
|
+
ensure
|
228
|
+
@_routes = old_routes
|
229
|
+
end
|
230
|
+
|
231
|
+
def _routes_context # :doc:
|
232
|
+
self
|
193
233
|
end
|
194
234
|
end
|
195
235
|
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
gem "capybara", ">= 2.15"
|
4
|
+
|
5
|
+
require "capybara/dsl"
|
6
|
+
require "capybara/minitest"
|
7
|
+
require "action_controller"
|
8
|
+
require "action_dispatch/system_testing/driver"
|
9
|
+
require "action_dispatch/system_testing/browser"
|
10
|
+
require "action_dispatch/system_testing/server"
|
11
|
+
require "action_dispatch/system_testing/test_helpers/screenshot_helper"
|
12
|
+
require "action_dispatch/system_testing/test_helpers/setup_and_teardown"
|
13
|
+
require "action_dispatch/system_testing/test_helpers/undef_methods"
|
14
|
+
|
15
|
+
module ActionDispatch
|
16
|
+
# = System Testing
|
17
|
+
#
|
18
|
+
# System tests let you test applications in the browser. Because system
|
19
|
+
# tests use a real browser experience, you can test all of your JavaScript
|
20
|
+
# easily from your test suite.
|
21
|
+
#
|
22
|
+
# To create a system test in your application, extend your test class
|
23
|
+
# from <tt>ApplicationSystemTestCase</tt>. System tests use Capybara as a
|
24
|
+
# base and allow you to configure the settings through your
|
25
|
+
# <tt>application_system_test_case.rb</tt> file that is generated with a new
|
26
|
+
# application or scaffold.
|
27
|
+
#
|
28
|
+
# Here is an example system test:
|
29
|
+
#
|
30
|
+
# require 'application_system_test_case'
|
31
|
+
#
|
32
|
+
# class Users::CreateTest < ApplicationSystemTestCase
|
33
|
+
# test "adding a new user" do
|
34
|
+
# visit users_path
|
35
|
+
# click_on 'New User'
|
36
|
+
#
|
37
|
+
# fill_in 'Name', with: 'Arya'
|
38
|
+
# click_on 'Create User'
|
39
|
+
#
|
40
|
+
# assert_text 'Arya'
|
41
|
+
# end
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# When generating an application or scaffold, an +application_system_test_case.rb+
|
45
|
+
# file will also be generated containing the base class for system testing.
|
46
|
+
# This is where you can change the driver, add Capybara settings, and other
|
47
|
+
# configuration for your system tests.
|
48
|
+
#
|
49
|
+
# require "test_helper"
|
50
|
+
#
|
51
|
+
# class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
|
52
|
+
# driven_by :selenium, using: :chrome, screen_size: [1400, 1400]
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
# By default, <tt>ActionDispatch::SystemTestCase</tt> is driven by the
|
56
|
+
# Selenium driver, with the Chrome browser, and a browser size of 1400x1400.
|
57
|
+
#
|
58
|
+
# Changing the driver configuration options is easy. Let's say you want to use
|
59
|
+
# the Firefox browser instead of Chrome. In your +application_system_test_case.rb+
|
60
|
+
# file add the following:
|
61
|
+
#
|
62
|
+
# require "test_helper"
|
63
|
+
#
|
64
|
+
# class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
|
65
|
+
# driven_by :selenium, using: :firefox
|
66
|
+
# end
|
67
|
+
#
|
68
|
+
# +driven_by+ has a required argument for the driver name. The keyword
|
69
|
+
# arguments are +:using+ for the browser and +:screen_size+ to change the
|
70
|
+
# size of the browser screen. These two options are not applicable for
|
71
|
+
# headless drivers and will be silently ignored if passed.
|
72
|
+
#
|
73
|
+
# Headless browsers such as headless Chrome and headless Firefox are also supported.
|
74
|
+
# You can use these browsers by setting the +:using+ argument to +:headless_chrome+ or +:headless_firefox+.
|
75
|
+
#
|
76
|
+
# To use a headless driver, like Poltergeist, update your Gemfile to use
|
77
|
+
# Poltergeist instead of Selenium and then declare the driver name in the
|
78
|
+
# +application_system_test_case.rb+ file. In this case, you would leave out
|
79
|
+
# the +:using+ option because the driver is headless, but you can still use
|
80
|
+
# +:screen_size+ to change the size of the browser screen, also you can use
|
81
|
+
# +:options+ to pass options supported by the driver. Please refer to your
|
82
|
+
# driver documentation to learn about supported options.
|
83
|
+
#
|
84
|
+
# require "test_helper"
|
85
|
+
# require "capybara/poltergeist"
|
86
|
+
#
|
87
|
+
# class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
|
88
|
+
# driven_by :poltergeist, screen_size: [1400, 1400], options:
|
89
|
+
# { js_errors: true }
|
90
|
+
# end
|
91
|
+
#
|
92
|
+
# Because <tt>ActionDispatch::SystemTestCase</tt> is a shim between Capybara
|
93
|
+
# and Rails, any driver that is supported by Capybara is supported by system
|
94
|
+
# tests as long as you include the required gems and files.
|
95
|
+
class SystemTestCase < IntegrationTest
|
96
|
+
include Capybara::DSL
|
97
|
+
include Capybara::Minitest::Assertions
|
98
|
+
include SystemTesting::TestHelpers::SetupAndTeardown
|
99
|
+
include SystemTesting::TestHelpers::ScreenshotHelper
|
100
|
+
include SystemTesting::TestHelpers::UndefMethods
|
101
|
+
|
102
|
+
def initialize(*) # :nodoc:
|
103
|
+
super
|
104
|
+
self.class.driver.use
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.start_application # :nodoc:
|
108
|
+
Capybara.app = Rack::Builder.new do
|
109
|
+
map "/" do
|
110
|
+
run Rails.application
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
SystemTesting::Server.new.run
|
115
|
+
end
|
116
|
+
|
117
|
+
class_attribute :driver, instance_accessor: false
|
118
|
+
|
119
|
+
# System Test configuration options
|
120
|
+
#
|
121
|
+
# The default settings are Selenium, using Chrome, with a screen size
|
122
|
+
# of 1400x1400.
|
123
|
+
#
|
124
|
+
# Examples:
|
125
|
+
#
|
126
|
+
# driven_by :poltergeist
|
127
|
+
#
|
128
|
+
# driven_by :selenium, screen_size: [800, 800]
|
129
|
+
#
|
130
|
+
# driven_by :selenium, using: :chrome
|
131
|
+
#
|
132
|
+
# driven_by :selenium, using: :headless_chrome
|
133
|
+
#
|
134
|
+
# driven_by :selenium, using: :firefox
|
135
|
+
#
|
136
|
+
# driven_by :selenium, using: :headless_firefox
|
137
|
+
def self.driven_by(driver, using: :chrome, screen_size: [1400, 1400], options: {})
|
138
|
+
self.driver = SystemTesting::Driver.new(driver, using: using, screen_size: screen_size, options: options)
|
139
|
+
end
|
140
|
+
|
141
|
+
driven_by :selenium
|
142
|
+
|
143
|
+
ActiveSupport.run_load_hooks(:action_dispatch_system_test_case, self)
|
144
|
+
end
|
145
|
+
|
146
|
+
SystemTestCase.start_application
|
147
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActionDispatch
|
4
|
+
module SystemTesting
|
5
|
+
class Browser # :nodoc:
|
6
|
+
attr_reader :name
|
7
|
+
|
8
|
+
def initialize(name)
|
9
|
+
@name = name
|
10
|
+
end
|
11
|
+
|
12
|
+
def type
|
13
|
+
case name
|
14
|
+
when :headless_chrome
|
15
|
+
:chrome
|
16
|
+
when :headless_firefox
|
17
|
+
:firefox
|
18
|
+
else
|
19
|
+
name
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def options
|
24
|
+
case name
|
25
|
+
when :headless_chrome
|
26
|
+
headless_chrome_browser_options
|
27
|
+
when :headless_firefox
|
28
|
+
headless_firefox_browser_options
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
def headless_chrome_browser_options
|
34
|
+
options = Selenium::WebDriver::Chrome::Options.new
|
35
|
+
options.args << "--headless"
|
36
|
+
options.args << "--disable-gpu" if Gem.win_platform?
|
37
|
+
|
38
|
+
options
|
39
|
+
end
|
40
|
+
|
41
|
+
def headless_firefox_browser_options
|
42
|
+
options = Selenium::WebDriver::Firefox::Options.new
|
43
|
+
options.args << "-headless"
|
44
|
+
|
45
|
+
options
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActionDispatch
|
4
|
+
module SystemTesting
|
5
|
+
class Driver # :nodoc:
|
6
|
+
def initialize(name, **options)
|
7
|
+
@name = name
|
8
|
+
@browser = Browser.new(options[:using])
|
9
|
+
@screen_size = options[:screen_size]
|
10
|
+
@options = options[:options]
|
11
|
+
end
|
12
|
+
|
13
|
+
def use
|
14
|
+
register if registerable?
|
15
|
+
|
16
|
+
setup
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
def registerable?
|
21
|
+
[:selenium, :poltergeist, :webkit].include?(@name)
|
22
|
+
end
|
23
|
+
|
24
|
+
def register
|
25
|
+
Capybara.register_driver @name do |app|
|
26
|
+
case @name
|
27
|
+
when :selenium then register_selenium(app)
|
28
|
+
when :poltergeist then register_poltergeist(app)
|
29
|
+
when :webkit then register_webkit(app)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def browser_options
|
35
|
+
@options.merge(options: @browser.options).compact
|
36
|
+
end
|
37
|
+
|
38
|
+
def register_selenium(app)
|
39
|
+
Capybara::Selenium::Driver.new(app, { browser: @browser.type }.merge(browser_options)).tap do |driver|
|
40
|
+
driver.browser.manage.window.size = Selenium::WebDriver::Dimension.new(*@screen_size)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def register_poltergeist(app)
|
45
|
+
Capybara::Poltergeist::Driver.new(app, @options.merge(window_size: @screen_size))
|
46
|
+
end
|
47
|
+
|
48
|
+
def register_webkit(app)
|
49
|
+
Capybara::Webkit::Driver.new(app, Capybara::Webkit::Configuration.to_hash.merge(@options)).tap do |driver|
|
50
|
+
driver.resize_window_to(driver.current_window_handle, *@screen_size)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def setup
|
55
|
+
Capybara.current_driver = @name
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|