actionpack 4.2.10 → 6.1.4
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 +311 -461
- data/MIT-LICENSE +1 -1
- data/README.rdoc +9 -9
- data/lib/abstract_controller/asset_paths.rb +2 -0
- data/lib/abstract_controller/base.rb +81 -51
- data/lib/{action_controller → abstract_controller}/caching/fragments.rb +64 -17
- data/lib/abstract_controller/caching.rb +66 -0
- data/lib/abstract_controller/callbacks.rb +61 -33
- data/lib/abstract_controller/collector.rb +9 -13
- data/lib/abstract_controller/error.rb +6 -0
- data/lib/abstract_controller/helpers.rb +115 -99
- data/lib/abstract_controller/logger.rb +2 -0
- data/lib/abstract_controller/railties/routes_helpers.rb +21 -3
- data/lib/abstract_controller/rendering.rb +48 -47
- data/lib/abstract_controller/translation.rb +17 -8
- data/lib/abstract_controller/url_for.rb +2 -0
- data/lib/abstract_controller.rb +13 -5
- data/lib/action_controller/api/api_rendering.rb +16 -0
- data/lib/action_controller/api.rb +150 -0
- data/lib/action_controller/base.rb +29 -24
- data/lib/action_controller/caching.rb +12 -57
- data/lib/action_controller/form_builder.rb +50 -0
- data/lib/action_controller/log_subscriber.rb +17 -19
- data/lib/action_controller/metal/basic_implicit_render.rb +13 -0
- data/lib/action_controller/metal/conditional_get.rb +134 -46
- data/lib/action_controller/metal/content_security_policy.rb +51 -0
- data/lib/action_controller/metal/cookies.rb +6 -4
- data/lib/action_controller/metal/data_streaming.rb +30 -50
- data/lib/action_controller/metal/default_headers.rb +17 -0
- data/lib/action_controller/metal/etag_with_flash.rb +18 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +21 -16
- data/lib/action_controller/metal/exceptions.rb +63 -15
- data/lib/action_controller/metal/flash.rb +9 -8
- data/lib/action_controller/metal/head.rb +26 -21
- data/lib/action_controller/metal/helpers.rb +37 -18
- data/lib/action_controller/metal/http_authentication.rb +81 -73
- data/lib/action_controller/metal/implicit_render.rb +53 -9
- data/lib/action_controller/metal/instrumentation.rb +32 -35
- data/lib/action_controller/metal/live.rb +110 -119
- data/lib/action_controller/metal/logging.rb +20 -0
- data/lib/action_controller/metal/mime_responds.rb +49 -47
- data/lib/action_controller/metal/parameter_encoding.rb +82 -0
- data/lib/action_controller/metal/params_wrapper.rb +84 -66
- data/lib/action_controller/metal/permissions_policy.rb +46 -0
- data/lib/action_controller/metal/redirecting.rb +53 -32
- data/lib/action_controller/metal/renderers.rb +87 -44
- data/lib/action_controller/metal/rendering.rb +77 -50
- data/lib/action_controller/metal/request_forgery_protection.rb +267 -103
- data/lib/action_controller/metal/rescue.rb +10 -17
- data/lib/action_controller/metal/streaming.rb +12 -11
- data/lib/action_controller/metal/strong_parameters.rb +714 -186
- data/lib/action_controller/metal/testing.rb +2 -17
- data/lib/action_controller/metal/url_for.rb +19 -10
- data/lib/action_controller/metal.rb +104 -87
- data/lib/action_controller/railtie.rb +28 -10
- data/lib/action_controller/railties/helpers.rb +3 -1
- data/lib/action_controller/renderer.rb +141 -0
- data/lib/action_controller/template_assertions.rb +11 -0
- data/lib/action_controller/test_case.rb +298 -421
- data/lib/action_controller.rb +34 -23
- data/lib/action_dispatch/http/cache.rb +108 -58
- data/lib/action_dispatch/http/content_disposition.rb +45 -0
- data/lib/action_dispatch/http/content_security_policy.rb +286 -0
- data/lib/action_dispatch/http/filter_parameters.rb +32 -25
- data/lib/action_dispatch/http/filter_redirect.rb +10 -12
- data/lib/action_dispatch/http/headers.rb +55 -22
- data/lib/action_dispatch/http/mime_negotiation.rb +82 -50
- data/lib/action_dispatch/http/mime_type.rb +153 -121
- data/lib/action_dispatch/http/mime_types.rb +20 -6
- data/lib/action_dispatch/http/parameters.rb +90 -40
- data/lib/action_dispatch/http/permissions_policy.rb +173 -0
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +226 -121
- data/lib/action_dispatch/http/response.rb +248 -113
- data/lib/action_dispatch/http/upload.rb +21 -7
- data/lib/action_dispatch/http/url.rb +182 -100
- data/lib/action_dispatch/journey/formatter.rb +91 -44
- data/lib/action_dispatch/journey/gtg/builder.rb +28 -41
- data/lib/action_dispatch/journey/gtg/simulator.rb +11 -16
- data/lib/action_dispatch/journey/gtg/transition_table.rb +23 -21
- data/lib/action_dispatch/journey/nfa/dot.rb +3 -14
- data/lib/action_dispatch/journey/nodes/node.rb +29 -15
- data/lib/action_dispatch/journey/parser.rb +17 -16
- data/lib/action_dispatch/journey/parser.y +4 -3
- data/lib/action_dispatch/journey/parser_extras.rb +12 -4
- data/lib/action_dispatch/journey/path/pattern.rb +58 -54
- data/lib/action_dispatch/journey/route.rb +100 -32
- data/lib/action_dispatch/journey/router/utils.rb +29 -18
- data/lib/action_dispatch/journey/router.rb +55 -51
- data/lib/action_dispatch/journey/routes.rb +17 -17
- data/lib/action_dispatch/journey/scanner.rb +26 -17
- data/lib/action_dispatch/journey/visitors.rb +98 -54
- data/lib/action_dispatch/journey.rb +5 -5
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
- data/lib/action_dispatch/middleware/callbacks.rb +3 -6
- data/lib/action_dispatch/middleware/cookies.rb +347 -217
- data/lib/action_dispatch/middleware/debug_exceptions.rb +135 -63
- data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
- data/lib/action_dispatch/middleware/debug_view.rb +66 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +115 -71
- data/lib/action_dispatch/middleware/executor.rb +21 -0
- data/lib/action_dispatch/middleware/flash.rb +78 -54
- data/lib/action_dispatch/middleware/host_authorization.rb +130 -0
- data/lib/action_dispatch/middleware/public_exceptions.rb +32 -27
- data/lib/action_dispatch/middleware/reloader.rb +5 -91
- data/lib/action_dispatch/middleware/remote_ip.rb +53 -45
- data/lib/action_dispatch/middleware/request_id.rb +17 -10
- data/lib/action_dispatch/middleware/session/abstract_store.rb +41 -26
- data/lib/action_dispatch/middleware/session/cache_store.rb +24 -14
- data/lib/action_dispatch/middleware/session/cookie_store.rb +74 -75
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -2
- data/lib/action_dispatch/middleware/show_exceptions.rb +28 -23
- data/lib/action_dispatch/middleware/ssl.rb +118 -35
- data/lib/action_dispatch/middleware/stack.rb +82 -41
- data/lib/action_dispatch/middleware/static.rb +156 -89
- data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
- data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +4 -14
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/{_source.erb → _source.html.erb} +4 -2
- data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +45 -35
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -0
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +23 -4
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +24 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +16 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +105 -8
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.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 +87 -64
- data/lib/action_dispatch/railtie.rb +27 -13
- data/lib/action_dispatch/request/session.rb +109 -61
- data/lib/action_dispatch/request/utils.rb +90 -23
- data/lib/action_dispatch/routing/endpoint.rb +9 -2
- data/lib/action_dispatch/routing/inspector.rb +141 -102
- data/lib/action_dispatch/routing/mapper.rb +811 -473
- data/lib/action_dispatch/routing/polymorphic_routes.rb +167 -143
- data/lib/action_dispatch/routing/redirection.rb +37 -27
- data/lib/action_dispatch/routing/route_set.rb +363 -331
- data/lib/action_dispatch/routing/routes_proxy.rb +32 -5
- data/lib/action_dispatch/routing/url_for.rb +66 -26
- data/lib/action_dispatch/routing.rb +36 -36
- data/lib/action_dispatch/system_test_case.rb +190 -0
- data/lib/action_dispatch/system_testing/browser.rb +86 -0
- data/lib/action_dispatch/system_testing/driver.rb +67 -0
- data/lib/action_dispatch/system_testing/server.rb +31 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +138 -0
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +29 -0
- data/lib/action_dispatch/testing/assertion_response.rb +46 -0
- data/lib/action_dispatch/testing/assertions/response.rb +44 -22
- data/lib/action_dispatch/testing/assertions/routing.rb +47 -31
- data/lib/action_dispatch/testing/assertions.rb +6 -4
- data/lib/action_dispatch/testing/integration.rb +391 -220
- data/lib/action_dispatch/testing/request_encoder.rb +55 -0
- data/lib/action_dispatch/testing/test_process.rb +53 -22
- data/lib/action_dispatch/testing/test_request.rb +27 -34
- data/lib/action_dispatch/testing/test_response.rb +11 -11
- data/lib/action_dispatch.rb +35 -21
- data/lib/action_pack/gem_version.rb +5 -3
- data/lib/action_pack/version.rb +3 -1
- data/lib/action_pack.rb +4 -2
- metadata +75 -46
- data/lib/action_controller/metal/force_ssl.rb +0 -97
- 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/http/parameter_filter.rb +0 -72
- data/lib/action_dispatch/journey/backwards.rb +0 -5
- data/lib/action_dispatch/journey/nfa/builder.rb +0 -76
- data/lib/action_dispatch/journey/nfa/simulator.rb +0 -47
- data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -163
- 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,224 +1,84 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
|
7
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rack/session/abstract/id"
|
4
|
+
require "active_support/core_ext/hash/conversions"
|
5
|
+
require "active_support/core_ext/object/to_query"
|
6
|
+
require "active_support/core_ext/module/anonymous"
|
7
|
+
require "active_support/core_ext/module/redefine_method"
|
8
|
+
require "active_support/core_ext/hash/keys"
|
9
|
+
require "active_support/testing/constant_lookup"
|
10
|
+
require "action_controller/template_assertions"
|
11
|
+
require "rails-dom-testing"
|
8
12
|
|
9
13
|
module ActionController
|
10
|
-
|
11
|
-
|
14
|
+
class Metal
|
15
|
+
include Testing::Functional
|
16
|
+
end
|
12
17
|
|
13
|
-
|
14
|
-
|
15
|
-
|
18
|
+
module Live
|
19
|
+
# Disable controller / rendering threads in tests. User tests can access
|
20
|
+
# the database on the main thread, so they could open a txn, then the
|
21
|
+
# controller thread will open a new connection and try to access data
|
22
|
+
# that's only visible to the main thread's txn. This is the problem in #23483.
|
23
|
+
silence_redefinition_of_method :new_controller_thread
|
24
|
+
def new_controller_thread # :nodoc:
|
25
|
+
yield
|
16
26
|
end
|
17
27
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
RENDER_TEMPLATE_INSTANCE_VARIABLES.each do |instance_variable|
|
22
|
-
instance_variable_set("@_#{instance_variable}", Hash.new(0))
|
23
|
-
end
|
24
|
-
|
25
|
-
@_subscribers = []
|
26
|
-
|
27
|
-
@_subscribers << ActiveSupport::Notifications.subscribe("render_template.action_view") do |_name, _start, _finish, _id, payload|
|
28
|
-
path = payload[:layout]
|
29
|
-
if path
|
30
|
-
@_layouts[path] += 1
|
31
|
-
if path =~ /^layouts\/(.*)/
|
32
|
-
@_layouts[$1] += 1
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
@_subscribers << ActiveSupport::Notifications.subscribe("!render_template.action_view") do |_name, _start, _finish, _id, payload|
|
38
|
-
if virtual_path = payload[:virtual_path]
|
39
|
-
partial = virtual_path =~ /^.*\/_[^\/]*$/
|
28
|
+
# Avoid a deadlock from the queue filling up
|
29
|
+
Buffer.queue_size = nil
|
30
|
+
end
|
40
31
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
32
|
+
# ActionController::TestCase will be deprecated and moved to a gem in the future.
|
33
|
+
# Please use ActionDispatch::IntegrationTest going forward.
|
34
|
+
class TestRequest < ActionDispatch::TestRequest #:nodoc:
|
35
|
+
DEFAULT_ENV = ActionDispatch::TestRequest::DEFAULT_ENV.dup
|
36
|
+
DEFAULT_ENV.delete "PATH_INFO"
|
45
37
|
|
46
|
-
|
47
|
-
|
48
|
-
path = payload[:identifier]
|
49
|
-
if path
|
50
|
-
@_files[path] += 1
|
51
|
-
@_files[path.split("/").last] += 1
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
38
|
+
def self.new_session
|
39
|
+
TestSession.new
|
55
40
|
end
|
56
41
|
|
57
|
-
|
58
|
-
return unless defined?(@_subscribers)
|
42
|
+
attr_reader :controller_class
|
59
43
|
|
60
|
-
|
61
|
-
|
62
|
-
|
44
|
+
# Create a new test request with default `env` values.
|
45
|
+
def self.create(controller_class)
|
46
|
+
env = {}
|
47
|
+
env = Rails.application.env_config.merge(env) if defined?(Rails.application) && Rails.application
|
48
|
+
env["rack.request.cookie_hash"] = {}.with_indifferent_access
|
49
|
+
new(default_env.merge(env), new_session, controller_class)
|
63
50
|
end
|
64
51
|
|
65
|
-
def
|
66
|
-
|
67
|
-
super
|
68
|
-
end
|
69
|
-
|
70
|
-
def reset_template_assertion
|
71
|
-
RENDER_TEMPLATE_INSTANCE_VARIABLES.each do |instance_variable|
|
72
|
-
ivar_name = "@_#{instance_variable}"
|
73
|
-
if instance_variable_defined?(ivar_name)
|
74
|
-
instance_variable_get(ivar_name).clear
|
75
|
-
end
|
76
|
-
end
|
52
|
+
def self.default_env
|
53
|
+
DEFAULT_ENV
|
77
54
|
end
|
55
|
+
private_class_method :default_env
|
78
56
|
|
79
|
-
|
80
|
-
|
81
|
-
# # assert that the "new" view template was rendered
|
82
|
-
# assert_template "new"
|
83
|
-
#
|
84
|
-
# # assert that the exact template "admin/posts/new" was rendered
|
85
|
-
# assert_template %r{\Aadmin/posts/new\Z}
|
86
|
-
#
|
87
|
-
# # assert that the layout 'admin' was rendered
|
88
|
-
# assert_template layout: 'admin'
|
89
|
-
# assert_template layout: 'layouts/admin'
|
90
|
-
# assert_template layout: :admin
|
91
|
-
#
|
92
|
-
# # assert that no layout was rendered
|
93
|
-
# assert_template layout: nil
|
94
|
-
# assert_template layout: false
|
95
|
-
#
|
96
|
-
# # assert that the "_customer" partial was rendered twice
|
97
|
-
# assert_template partial: '_customer', count: 2
|
98
|
-
#
|
99
|
-
# # assert that no partials were rendered
|
100
|
-
# assert_template partial: false
|
101
|
-
#
|
102
|
-
# # assert that a file was rendered
|
103
|
-
# assert_template file: "README.rdoc"
|
104
|
-
#
|
105
|
-
# # assert that no file was rendered
|
106
|
-
# assert_template file: nil
|
107
|
-
# assert_template file: false
|
108
|
-
#
|
109
|
-
# In a view test case, you can also assert that specific locals are passed
|
110
|
-
# to partials:
|
111
|
-
#
|
112
|
-
# # assert that the "_customer" partial was rendered with a specific object
|
113
|
-
# assert_template partial: '_customer', locals: { customer: @customer }
|
114
|
-
def assert_template(options = {}, message = nil)
|
115
|
-
# Force body to be read in case the template is being streamed.
|
116
|
-
response.body
|
117
|
-
|
118
|
-
case options
|
119
|
-
when NilClass, Regexp, String, Symbol
|
120
|
-
options = options.to_s if Symbol === options
|
121
|
-
rendered = @_templates
|
122
|
-
msg = message || sprintf("expecting <%s> but rendering with <%s>",
|
123
|
-
options.inspect, rendered.keys)
|
124
|
-
matches_template =
|
125
|
-
case options
|
126
|
-
when String
|
127
|
-
!options.empty? && rendered.any? do |t, num|
|
128
|
-
options_splited = options.split(File::SEPARATOR)
|
129
|
-
t_splited = t.split(File::SEPARATOR)
|
130
|
-
t_splited.last(options_splited.size) == options_splited
|
131
|
-
end
|
132
|
-
when Regexp
|
133
|
-
rendered.any? { |t,num| t.match(options) }
|
134
|
-
when NilClass
|
135
|
-
rendered.blank?
|
136
|
-
end
|
137
|
-
assert matches_template, msg
|
138
|
-
when Hash
|
139
|
-
options.assert_valid_keys(:layout, :partial, :locals, :count, :file)
|
140
|
-
|
141
|
-
if options.key?(:layout)
|
142
|
-
expected_layout = options[:layout]
|
143
|
-
msg = message || sprintf("expecting layout <%s> but action rendered <%s>",
|
144
|
-
expected_layout, @_layouts.keys)
|
145
|
-
|
146
|
-
case expected_layout
|
147
|
-
when String, Symbol
|
148
|
-
assert_includes @_layouts.keys, expected_layout.to_s, msg
|
149
|
-
when Regexp
|
150
|
-
assert(@_layouts.keys.any? {|l| l =~ expected_layout }, msg)
|
151
|
-
when nil, false
|
152
|
-
assert(@_layouts.empty?, msg)
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
if options[:file]
|
157
|
-
assert_includes @_files.keys, options[:file]
|
158
|
-
elsif options.key?(:file)
|
159
|
-
assert @_files.blank?, "expected no files but #{@_files.keys} was rendered"
|
160
|
-
end
|
161
|
-
|
162
|
-
if expected_partial = options[:partial]
|
163
|
-
if expected_locals = options[:locals]
|
164
|
-
if defined?(@_rendered_views)
|
165
|
-
view = expected_partial.to_s.sub(/^_/, '').sub(/\/_(?=[^\/]+\z)/, '/')
|
57
|
+
def initialize(env, session, controller_class)
|
58
|
+
super(env)
|
166
59
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
assert(@_rendered_views.view_rendered?(view, options[:locals]), msg)
|
174
|
-
else
|
175
|
-
warn "the :locals option to #assert_template is only supported in a ActionView::TestCase"
|
176
|
-
end
|
177
|
-
elsif expected_count = options[:count]
|
178
|
-
actual_count = @_partials[expected_partial]
|
179
|
-
msg = message || sprintf("expecting %s to be rendered %s time(s) but rendered %s time(s)",
|
180
|
-
expected_partial, expected_count, actual_count)
|
181
|
-
assert(actual_count == expected_count.to_i, msg)
|
182
|
-
else
|
183
|
-
msg = message || sprintf("expecting partial <%s> but action rendered <%s>",
|
184
|
-
options[:partial], @_partials.keys)
|
185
|
-
assert_includes @_partials, expected_partial, msg
|
186
|
-
end
|
187
|
-
elsif options.key?(:partial)
|
188
|
-
assert @_partials.empty?,
|
189
|
-
"Expected no partials to be rendered"
|
190
|
-
end
|
191
|
-
else
|
192
|
-
raise ArgumentError, "assert_template only accepts a String, Symbol, Hash, Regexp, or nil"
|
193
|
-
end
|
60
|
+
self.session = session
|
61
|
+
self.session_options = TestSession::DEFAULT_OPTIONS.dup
|
62
|
+
@controller_class = controller_class
|
63
|
+
@custom_param_parsers = {
|
64
|
+
xml: lambda { |raw_post| Hash.from_xml(raw_post)["hash"] }
|
65
|
+
}
|
194
66
|
end
|
195
|
-
end
|
196
67
|
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
def initialize(env = {})
|
202
|
-
super
|
68
|
+
def query_string=(string)
|
69
|
+
set_header Rack::QUERY_STRING, string
|
70
|
+
end
|
203
71
|
|
204
|
-
|
205
|
-
|
72
|
+
def content_type=(type)
|
73
|
+
set_header "CONTENT_TYPE", type
|
206
74
|
end
|
207
75
|
|
208
|
-
def assign_parameters(routes, controller_path, action, parameters
|
209
|
-
|
210
|
-
|
211
|
-
non_path_parameters = get? ? query_parameters : request_parameters
|
212
|
-
parameters.each do |key, value|
|
213
|
-
if value.is_a?(Array) && (value.frozen? || value.any?(&:frozen?))
|
214
|
-
value = value.map{ |v| v.duplicable? ? v.dup : v }
|
215
|
-
elsif value.is_a?(Hash) && (value.frozen? || value.any?{ |k,v| v.frozen? })
|
216
|
-
value = Hash[value.map{ |k,v| [k, v.duplicable? ? v.dup : v] }]
|
217
|
-
elsif value.frozen? && value.duplicable?
|
218
|
-
value = value.dup
|
219
|
-
end
|
76
|
+
def assign_parameters(routes, controller_path, action, parameters, generated_path, query_string_keys)
|
77
|
+
non_path_parameters = {}
|
78
|
+
path_parameters = {}
|
220
79
|
|
221
|
-
|
80
|
+
parameters.each do |key, value|
|
81
|
+
if query_string_keys.include?(key)
|
222
82
|
non_path_parameters[key] = value
|
223
83
|
else
|
224
84
|
if value.is_a?(Array)
|
@@ -227,88 +87,104 @@ module ActionController
|
|
227
87
|
value = value.to_param
|
228
88
|
end
|
229
89
|
|
230
|
-
path_parameters[key] = value
|
90
|
+
path_parameters[key.to_sym] = value
|
231
91
|
end
|
232
92
|
end
|
233
93
|
|
234
|
-
|
235
|
-
|
94
|
+
if get?
|
95
|
+
if query_string.blank?
|
96
|
+
self.query_string = non_path_parameters.to_query
|
97
|
+
end
|
98
|
+
else
|
99
|
+
if ENCODER.should_multipart?(non_path_parameters)
|
100
|
+
self.content_type = ENCODER.content_type
|
101
|
+
data = ENCODER.build_multipart non_path_parameters
|
102
|
+
else
|
103
|
+
fetch_header("CONTENT_TYPE") do |k|
|
104
|
+
set_header k, "application/x-www-form-urlencoded"
|
105
|
+
end
|
106
|
+
|
107
|
+
case content_mime_type.to_sym
|
108
|
+
when nil
|
109
|
+
raise "Unknown Content-Type: #{content_type}"
|
110
|
+
when :json
|
111
|
+
data = ActiveSupport::JSON.encode(non_path_parameters)
|
112
|
+
when :xml
|
113
|
+
data = non_path_parameters.to_xml
|
114
|
+
when :url_encoded_form
|
115
|
+
data = non_path_parameters.to_query
|
116
|
+
else
|
117
|
+
@custom_param_parsers[content_mime_type.symbol] = ->(_) { non_path_parameters }
|
118
|
+
data = non_path_parameters.to_query
|
119
|
+
end
|
120
|
+
end
|
236
121
|
|
237
|
-
|
238
|
-
|
122
|
+
data_stream = StringIO.new(data)
|
123
|
+
set_header "CONTENT_LENGTH", data_stream.length.to_s
|
124
|
+
set_header "rack.input", data_stream
|
125
|
+
end
|
239
126
|
|
240
|
-
|
241
|
-
|
242
|
-
params.delete(k)
|
243
|
-
params.delete(k.to_sym)
|
127
|
+
fetch_header("PATH_INFO") do |k|
|
128
|
+
set_header k, generated_path
|
244
129
|
end
|
245
|
-
|
130
|
+
path_parameters[:controller] = controller_path
|
131
|
+
path_parameters[:action] = action
|
246
132
|
|
247
|
-
|
248
|
-
@env['rack.input'] = StringIO.new(data)
|
133
|
+
self.path_parameters = path_parameters
|
249
134
|
end
|
250
135
|
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
136
|
+
ENCODER = Class.new do
|
137
|
+
include Rack::Test::Utils
|
138
|
+
|
139
|
+
def should_multipart?(params)
|
140
|
+
# FIXME: lifted from Rack-Test. We should push this separation upstream.
|
141
|
+
multipart = false
|
142
|
+
query = lambda { |value|
|
143
|
+
case value
|
144
|
+
when Array
|
145
|
+
value.each(&query)
|
146
|
+
when Hash
|
147
|
+
value.values.each(&query)
|
148
|
+
when Rack::Test::UploadedFile
|
149
|
+
multipart = true
|
150
|
+
end
|
151
|
+
}
|
152
|
+
params.values.each(&query)
|
153
|
+
multipart
|
154
|
+
end
|
267
155
|
|
268
|
-
|
156
|
+
public :build_multipart
|
269
157
|
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
158
|
+
def content_type
|
159
|
+
"multipart/form-data; boundary=#{Rack::Test::MULTIPART_BOUNDARY}"
|
160
|
+
end
|
161
|
+
end.new
|
274
162
|
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
163
|
+
private
|
164
|
+
def params_parsers
|
165
|
+
super.merge @custom_param_parsers
|
166
|
+
end
|
279
167
|
end
|
280
168
|
|
281
169
|
class LiveTestResponse < Live::Response
|
282
|
-
def recycle!
|
283
|
-
@body = nil
|
284
|
-
initialize
|
285
|
-
end
|
286
|
-
|
287
|
-
def body
|
288
|
-
@body ||= super
|
289
|
-
end
|
290
|
-
|
291
170
|
# Was the response successful?
|
292
171
|
alias_method :success?, :successful?
|
293
172
|
|
294
173
|
# Was the URL not found?
|
295
174
|
alias_method :missing?, :not_found?
|
296
175
|
|
297
|
-
# Were we redirected?
|
298
|
-
alias_method :redirect?, :redirection?
|
299
|
-
|
300
176
|
# Was there a server-side error?
|
301
177
|
alias_method :error?, :server_error?
|
302
178
|
end
|
303
179
|
|
304
180
|
# Methods #destroy and #load! are overridden to avoid calling methods on the
|
305
181
|
# @store object, which does not exist for the TestSession class.
|
306
|
-
class TestSession < Rack::Session::Abstract::
|
307
|
-
DEFAULT_OPTIONS = Rack::Session::Abstract::
|
182
|
+
class TestSession < Rack::Session::Abstract::PersistedSecure::SecureSessionHash #:nodoc:
|
183
|
+
DEFAULT_OPTIONS = Rack::Session::Abstract::Persisted::DEFAULT_OPTIONS
|
308
184
|
|
309
185
|
def initialize(session = {})
|
310
186
|
super(nil, nil)
|
311
|
-
@id = SecureRandom.hex(16)
|
187
|
+
@id = Rack::Session::SessionId.new(SecureRandom.hex(16))
|
312
188
|
@data = stringify_keys(session)
|
313
189
|
@loaded = true
|
314
190
|
end
|
@@ -329,22 +205,34 @@ module ActionController
|
|
329
205
|
clear
|
330
206
|
end
|
331
207
|
|
208
|
+
def dig(*keys)
|
209
|
+
keys = keys.map.with_index { |key, i| i.zero? ? key.to_s : key }
|
210
|
+
@data.dig(*keys)
|
211
|
+
end
|
212
|
+
|
332
213
|
def fetch(key, *args, &block)
|
333
214
|
@data.fetch(key.to_s, *args, &block)
|
334
215
|
end
|
335
216
|
|
336
217
|
private
|
337
|
-
|
338
218
|
def load!
|
339
219
|
@id
|
340
220
|
end
|
341
221
|
end
|
342
222
|
|
343
223
|
# Superclass for ActionController functional tests. Functional tests allow you to
|
344
|
-
# test a single controller action per test method.
|
345
|
-
#
|
346
|
-
#
|
347
|
-
#
|
224
|
+
# test a single controller action per test method.
|
225
|
+
#
|
226
|
+
# == Use integration style controller tests over functional style controller tests.
|
227
|
+
#
|
228
|
+
# Rails discourages the use of functional tests in favor of integration tests
|
229
|
+
# (use ActionDispatch::IntegrationTest).
|
230
|
+
#
|
231
|
+
# New Rails applications no longer generate functional style controller tests and they should
|
232
|
+
# only be used for backward compatibility. Integration style controller tests perform actual
|
233
|
+
# requests, whereas functional style controller tests merely simulate a request. Besides,
|
234
|
+
# integration tests are as fast as functional tests and provide lot of helpers such as +as+,
|
235
|
+
# +parsed_body+ for effective testing of controller actions including even API endpoints.
|
348
236
|
#
|
349
237
|
# == Basic example
|
350
238
|
#
|
@@ -359,13 +247,13 @@ module ActionController
|
|
359
247
|
# class BooksControllerTest < ActionController::TestCase
|
360
248
|
# def test_create
|
361
249
|
# # Simulate a POST response with the given HTTP parameters.
|
362
|
-
# post(:create, book: { title: "Love Hina" })
|
250
|
+
# post(:create, params: { book: { title: "Love Hina" }})
|
363
251
|
#
|
364
|
-
# #
|
252
|
+
# # Asserts that the controller tried to redirect us to
|
365
253
|
# # the created book's URI.
|
366
254
|
# assert_response :found
|
367
255
|
#
|
368
|
-
# #
|
256
|
+
# # Asserts that the controller really put the book in the database.
|
369
257
|
# assert_not_nil Book.find_by(title: "Love Hina")
|
370
258
|
# end
|
371
259
|
# end
|
@@ -374,7 +262,7 @@ module ActionController
|
|
374
262
|
#
|
375
263
|
# def test_create
|
376
264
|
# json = {book: { title: "Love Hina" }}.to_json
|
377
|
-
# post :create, json
|
265
|
+
# post :create, body: json
|
378
266
|
# end
|
379
267
|
#
|
380
268
|
# == Special instance variables
|
@@ -389,14 +277,11 @@ module ActionController
|
|
389
277
|
# request. You can modify this object before sending the HTTP request. For example,
|
390
278
|
# you might want to set some session properties before sending a GET request.
|
391
279
|
# <b>@response</b>::
|
392
|
-
# An
|
280
|
+
# An ActionDispatch::TestResponse object, representing the response
|
393
281
|
# of the last HTTP response. In the above example, <tt>@response</tt> becomes valid
|
394
282
|
# after calling +post+. If the various assert methods are not sufficient, then you
|
395
283
|
# may use this object to inspect the HTTP response in detail.
|
396
284
|
#
|
397
|
-
# (Earlier versions of \Rails required each functional test to subclass
|
398
|
-
# Test::Unit::TestCase and define @controller, @request, @response in +setup+.)
|
399
|
-
#
|
400
285
|
# == Controller is automatically inferred
|
401
286
|
#
|
402
287
|
# ActionController::TestCase will automatically infer the controller under test
|
@@ -412,22 +297,16 @@ module ActionController
|
|
412
297
|
# In addition to these specific assertions, you also have easy access to various collections that the regular test/unit assertions
|
413
298
|
# can be used against. These collections are:
|
414
299
|
#
|
415
|
-
# * assigns: Instance variables assigned in the action that are available for the view.
|
416
300
|
# * session: Objects being saved in the session.
|
417
301
|
# * flash: The flash objects currently in the session.
|
418
302
|
# * cookies: \Cookies being sent to the user on this request.
|
419
303
|
#
|
420
304
|
# These collections can be used just like any other hash:
|
421
305
|
#
|
422
|
-
# assert_not_nil assigns(:person) # makes sure that a @person instance variable was set
|
423
306
|
# assert_equal "Dave", cookies[:name] # makes sure that a cookie called :name was set as "Dave"
|
424
307
|
# assert flash.empty? # makes sure that there's nothing in the flash
|
425
308
|
#
|
426
|
-
#
|
427
|
-
# appease our yearning for symbols, though, an alternative accessor has been devised using a method call instead of index referencing.
|
428
|
-
# So <tt>assigns(:person)</tt> will work just like <tt>assigns["person"]</tt>, but again, <tt>assigns[:person]</tt> will not work.
|
429
|
-
#
|
430
|
-
# On top of the collections, you have the complete url that a given action redirected to available in <tt>redirect_to_url</tt>.
|
309
|
+
# On top of the collections, you have the complete URL that a given action redirected to available in <tt>redirect_to_url</tt>.
|
431
310
|
#
|
432
311
|
# For redirects within the same controller, you can even call follow_redirect and the redirect will be followed, triggering another
|
433
312
|
# action call which can then be asserted against.
|
@@ -459,7 +338,6 @@ module ActionController
|
|
459
338
|
attr_reader :response, :request
|
460
339
|
|
461
340
|
module ClassMethods
|
462
|
-
|
463
341
|
# Sets the controller class name. Useful if the name can't be inferred from test class.
|
464
342
|
# Normalizes +controller_class+ before using.
|
465
343
|
#
|
@@ -482,7 +360,7 @@ module ActionController
|
|
482
360
|
end
|
483
361
|
|
484
362
|
def controller_class
|
485
|
-
if current_controller_class =
|
363
|
+
if current_controller_class = _controller_class
|
486
364
|
current_controller_class
|
487
365
|
else
|
488
366
|
self.controller_class = determine_default_controller_class(name)
|
@@ -499,169 +377,148 @@ module ActionController
|
|
499
377
|
# Simulate a GET request with the given parameters.
|
500
378
|
#
|
501
379
|
# - +action+: The controller action to call.
|
502
|
-
# - +
|
503
|
-
#
|
380
|
+
# - +params+: The hash with HTTP parameters that you want to pass. This may be +nil+.
|
381
|
+
# - +body+: The request body with a string that is appropriately encoded
|
504
382
|
# (<tt>application/x-www-form-urlencoded</tt> or <tt>multipart/form-data</tt>).
|
505
383
|
# - +session+: A hash of parameters to store in the session. This may be +nil+.
|
506
384
|
# - +flash+: A hash of parameters to store in the flash. This may be +nil+.
|
507
385
|
#
|
508
386
|
# You can also simulate POST, PATCH, PUT, DELETE, and HEAD requests with
|
509
387
|
# +post+, +patch+, +put+, +delete+, and +head+.
|
388
|
+
# Example sending parameters, session and setting a flash message:
|
389
|
+
#
|
390
|
+
# get :show,
|
391
|
+
# params: { id: 7 },
|
392
|
+
# session: { user_id: 1 },
|
393
|
+
# flash: { notice: 'This is flash message' }
|
510
394
|
#
|
511
395
|
# Note that the request method is not verified. The different methods are
|
512
396
|
# available to make the tests more expressive.
|
513
|
-
def get(action,
|
514
|
-
process(action, "GET",
|
397
|
+
def get(action, **args)
|
398
|
+
res = process(action, method: "GET", **args)
|
399
|
+
cookies.update res.cookies
|
400
|
+
res
|
515
401
|
end
|
516
402
|
|
517
403
|
# Simulate a POST request with the given parameters and set/volley the response.
|
518
404
|
# See +get+ for more details.
|
519
|
-
def post(action,
|
520
|
-
process(action, "POST",
|
405
|
+
def post(action, **args)
|
406
|
+
process(action, method: "POST", **args)
|
521
407
|
end
|
522
408
|
|
523
409
|
# Simulate a PATCH request with the given parameters and set/volley the response.
|
524
410
|
# See +get+ for more details.
|
525
|
-
def patch(action,
|
526
|
-
process(action, "PATCH",
|
411
|
+
def patch(action, **args)
|
412
|
+
process(action, method: "PATCH", **args)
|
527
413
|
end
|
528
414
|
|
529
415
|
# Simulate a PUT request with the given parameters and set/volley the response.
|
530
416
|
# See +get+ for more details.
|
531
|
-
def put(action,
|
532
|
-
process(action, "PUT",
|
417
|
+
def put(action, **args)
|
418
|
+
process(action, method: "PUT", **args)
|
533
419
|
end
|
534
420
|
|
535
421
|
# Simulate a DELETE request with the given parameters and set/volley the response.
|
536
422
|
# See +get+ for more details.
|
537
|
-
def delete(action,
|
538
|
-
process(action, "DELETE",
|
423
|
+
def delete(action, **args)
|
424
|
+
process(action, method: "DELETE", **args)
|
539
425
|
end
|
540
426
|
|
541
427
|
# Simulate a HEAD request with the given parameters and set/volley the response.
|
542
428
|
# See +get+ for more details.
|
543
|
-
def head(action,
|
544
|
-
process(action, "HEAD",
|
429
|
+
def head(action, **args)
|
430
|
+
process(action, method: "HEAD", **args)
|
545
431
|
end
|
546
432
|
|
547
|
-
|
548
|
-
@request.env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
|
549
|
-
@request.env['HTTP_ACCEPT'] ||= [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ')
|
550
|
-
__send__(request_method, action, parameters, session, flash).tap do
|
551
|
-
@request.env.delete 'HTTP_X_REQUESTED_WITH'
|
552
|
-
@request.env.delete 'HTTP_ACCEPT'
|
553
|
-
end
|
554
|
-
end
|
555
|
-
alias xhr :xml_http_request
|
556
|
-
|
557
|
-
def paramify_values(hash_or_array_or_value)
|
558
|
-
case hash_or_array_or_value
|
559
|
-
when Hash
|
560
|
-
Hash[hash_or_array_or_value.map{|key, value| [key, paramify_values(value)] }]
|
561
|
-
when Array
|
562
|
-
hash_or_array_or_value.map {|i| paramify_values(i)}
|
563
|
-
when Rack::Test::UploadedFile, ActionDispatch::Http::UploadedFile
|
564
|
-
hash_or_array_or_value
|
565
|
-
else
|
566
|
-
hash_or_array_or_value.to_param
|
567
|
-
end
|
568
|
-
end
|
569
|
-
|
570
|
-
# Simulate a HTTP request to +action+ by specifying request method,
|
433
|
+
# Simulate an HTTP request to +action+ by specifying request method,
|
571
434
|
# parameters and set/volley the response.
|
572
435
|
#
|
573
436
|
# - +action+: The controller action to call.
|
574
|
-
# - +
|
575
|
-
# are +GET+, +POST+, +PATCH+, +PUT+, +DELETE+, +HEAD+. Defaults to +GET+.
|
576
|
-
# - +
|
577
|
-
#
|
578
|
-
# or
|
437
|
+
# - +method+: Request method used to send the HTTP request. Possible values
|
438
|
+
# are +GET+, +POST+, +PATCH+, +PUT+, +DELETE+, +HEAD+. Defaults to +GET+. Can be a symbol.
|
439
|
+
# - +params+: The hash with HTTP parameters that you want to pass. This may be +nil+.
|
440
|
+
# - +body+: The request body with a string that is appropriately encoded
|
441
|
+
# (<tt>application/x-www-form-urlencoded</tt> or <tt>multipart/form-data</tt>).
|
579
442
|
# - +session+: A hash of parameters to store in the session. This may be +nil+.
|
580
443
|
# - +flash+: A hash of parameters to store in the flash. This may be +nil+.
|
444
|
+
# - +format+: Request format. Defaults to +nil+. Can be string or symbol.
|
445
|
+
# - +as+: Content type. Defaults to +nil+. Must be a symbol that corresponds
|
446
|
+
# to a mime type.
|
581
447
|
#
|
582
448
|
# Example calling +create+ action and sending two params:
|
583
449
|
#
|
584
|
-
# process :create,
|
585
|
-
#
|
586
|
-
#
|
587
|
-
#
|
588
|
-
#
|
450
|
+
# process :create,
|
451
|
+
# method: 'POST',
|
452
|
+
# params: {
|
453
|
+
# user: { name: 'Gaurish Sharma', email: 'user@example.com' }
|
454
|
+
# },
|
455
|
+
# session: { user_id: 1 },
|
456
|
+
# flash: { notice: 'This is flash message' }
|
589
457
|
#
|
590
458
|
# To simulate +GET+, +POST+, +PATCH+, +PUT+, +DELETE+ and +HEAD+ requests
|
591
459
|
# prefer using #get, #post, #patch, #put, #delete and #head methods
|
592
460
|
# respectively which will make tests more expressive.
|
593
461
|
#
|
594
462
|
# Note that the request method is not verified.
|
595
|
-
def process(action,
|
463
|
+
def process(action, method: "GET", params: nil, session: nil, body: nil, flash: {}, format: nil, xhr: false, as: nil)
|
596
464
|
check_required_ivars
|
597
465
|
|
598
|
-
|
599
|
-
|
600
|
-
end
|
601
|
-
|
602
|
-
parameters, session, flash = args
|
603
|
-
parameters ||= {}
|
604
|
-
|
605
|
-
# Ensure that numbers and symbols passed as params are converted to
|
606
|
-
# proper params, as is the case when engaging rack.
|
607
|
-
parameters = paramify_values(parameters) if html_format?(parameters)
|
466
|
+
action = +action.to_s
|
467
|
+
http_method = method.to_s.upcase
|
608
468
|
|
609
469
|
@html_document = nil
|
610
|
-
@html_scanner_document = nil
|
611
470
|
|
612
|
-
|
613
|
-
|
614
|
-
|
471
|
+
cookies.update(@request.cookies)
|
472
|
+
cookies.update_cookies_from_jar
|
473
|
+
@request.set_header "HTTP_COOKIE", cookies.to_header
|
474
|
+
@request.delete_header "action_dispatch.cookies"
|
615
475
|
|
616
|
-
@request.
|
617
|
-
@response
|
476
|
+
@request = TestRequest.new scrub_env!(@request.env), @request.session, @controller.class
|
477
|
+
@response = build_response @response_klass
|
478
|
+
@response.request = @request
|
618
479
|
@controller.recycle!
|
619
480
|
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
"anonymous" :
|
624
|
-
@controller.class.controller_path
|
625
|
-
|
626
|
-
@request.assign_parameters(@routes, controller_class_name, action.to_s, parameters)
|
627
|
-
|
628
|
-
@request.session.update(session) if session
|
629
|
-
@request.flash.update(flash || {})
|
481
|
+
if body
|
482
|
+
@request.set_header "RAW_POST_DATA", body
|
483
|
+
end
|
630
484
|
|
631
|
-
@
|
632
|
-
@controller.response = @response
|
485
|
+
@request.set_header "REQUEST_METHOD", http_method
|
633
486
|
|
634
|
-
|
487
|
+
if as
|
488
|
+
@request.content_type = Mime[as].to_s
|
489
|
+
format ||= as
|
490
|
+
end
|
635
491
|
|
636
|
-
|
492
|
+
parameters = (params || {}).symbolize_keys
|
637
493
|
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
if cookies = @request.env['action_dispatch.cookies']
|
642
|
-
unless @response.committed?
|
643
|
-
cookies.write(@response)
|
644
|
-
end
|
494
|
+
if format
|
495
|
+
parameters[:format] = format
|
645
496
|
end
|
646
|
-
@response.prepare!
|
647
497
|
|
648
|
-
|
498
|
+
setup_request(controller_class_name, action, parameters, session, flash, xhr)
|
499
|
+
process_controller_response(action, cookies, xhr)
|
500
|
+
end
|
649
501
|
|
650
|
-
|
651
|
-
|
652
|
-
|
502
|
+
def controller_class_name
|
503
|
+
@controller.class.anonymous? ? "anonymous" : @controller.class.controller_path
|
504
|
+
end
|
653
505
|
|
654
|
-
|
506
|
+
def generated_path(generated_extras)
|
507
|
+
generated_extras[0]
|
508
|
+
end
|
509
|
+
|
510
|
+
def query_parameter_names(generated_extras)
|
511
|
+
generated_extras[1] + [:controller, :action]
|
655
512
|
end
|
656
513
|
|
657
514
|
def setup_controller_request_and_response
|
658
515
|
@controller = nil unless defined? @controller
|
659
516
|
|
660
|
-
response_klass = TestResponse
|
517
|
+
@response_klass = ActionDispatch::TestResponse
|
661
518
|
|
662
519
|
if klass = self.class.controller_class
|
663
520
|
if klass < ActionController::Live
|
664
|
-
response_klass = LiveTestResponse
|
521
|
+
@response_klass = LiveTestResponse
|
665
522
|
end
|
666
523
|
unless @controller
|
667
524
|
begin
|
@@ -672,8 +529,8 @@ module ActionController
|
|
672
529
|
end
|
673
530
|
end
|
674
531
|
|
675
|
-
@request =
|
676
|
-
@response = build_response response_klass
|
532
|
+
@request = TestRequest.create(@controller.class)
|
533
|
+
@response = build_response @response_klass
|
677
534
|
@response.request = @request
|
678
535
|
|
679
536
|
if @controller
|
@@ -682,12 +539,8 @@ module ActionController
|
|
682
539
|
end
|
683
540
|
end
|
684
541
|
|
685
|
-
def build_request
|
686
|
-
TestRequest.new
|
687
|
-
end
|
688
|
-
|
689
542
|
def build_response(klass)
|
690
|
-
klass.
|
543
|
+
klass.create
|
691
544
|
end
|
692
545
|
|
693
546
|
included do
|
@@ -695,65 +548,89 @@ module ActionController
|
|
695
548
|
include ActionDispatch::Assertions
|
696
549
|
class_attribute :_controller_class
|
697
550
|
setup :setup_controller_request_and_response
|
551
|
+
ActiveSupport.run_load_hooks(:action_controller_test_case, self)
|
698
552
|
end
|
699
553
|
|
700
554
|
private
|
555
|
+
def setup_request(controller_class_name, action, parameters, session, flash, xhr)
|
556
|
+
generated_extras = @routes.generate_extras(parameters.merge(controller: controller_class_name, action: action))
|
557
|
+
generated_path = generated_path(generated_extras)
|
558
|
+
query_string_keys = query_parameter_names(generated_extras)
|
701
559
|
|
702
|
-
|
703
|
-
|
704
|
-
|
560
|
+
@request.assign_parameters(@routes, controller_class_name, action, parameters, generated_path, query_string_keys)
|
561
|
+
|
562
|
+
@request.session.update(session) if session
|
563
|
+
@request.flash.update(flash || {})
|
564
|
+
|
565
|
+
if xhr
|
566
|
+
@request.set_header "HTTP_X_REQUESTED_WITH", "XMLHttpRequest"
|
567
|
+
@request.fetch_header("HTTP_ACCEPT") do |k|
|
568
|
+
@request.set_header k, [Mime[:js], Mime[:html], Mime[:xml], "text/xml", "*/*"].join(", ")
|
569
|
+
end
|
570
|
+
end
|
705
571
|
|
706
|
-
|
707
|
-
|
708
|
-
# understandable error message.
|
709
|
-
[:@routes, :@controller, :@request, :@response].each do |iv_name|
|
710
|
-
if !instance_variable_defined?(iv_name) || instance_variable_get(iv_name).nil?
|
711
|
-
raise "#{iv_name} is nil: make sure you set it in your test's setup method."
|
572
|
+
@request.fetch_header("SCRIPT_NAME") do |k|
|
573
|
+
@request.set_header k, @controller.config.relative_url_root
|
712
574
|
end
|
713
575
|
end
|
714
|
-
end
|
715
576
|
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
577
|
+
def process_controller_response(action, cookies, xhr)
|
578
|
+
begin
|
579
|
+
@controller.recycle!
|
580
|
+
@controller.dispatch(action, @request, @response)
|
581
|
+
ensure
|
582
|
+
@request = @controller.request
|
583
|
+
@response = @controller.response
|
584
|
+
|
585
|
+
if @request.have_cookie_jar?
|
586
|
+
unless @request.cookie_jar.committed?
|
587
|
+
@request.cookie_jar.write(@response)
|
588
|
+
cookies.update(@request.cookie_jar.instance_variable_get(:@cookies))
|
589
|
+
end
|
590
|
+
end
|
591
|
+
@response.prepare!
|
592
|
+
|
593
|
+
if flash_value = @request.flash.to_session_value
|
594
|
+
@request.session["flash"] = flash_value
|
595
|
+
else
|
596
|
+
@request.session.delete("flash")
|
597
|
+
end
|
598
|
+
|
599
|
+
if xhr
|
600
|
+
@request.delete_header "HTTP_X_REQUESTED_WITH"
|
601
|
+
@request.delete_header "HTTP_ACCEPT"
|
602
|
+
end
|
603
|
+
@request.query_string = ""
|
604
|
+
|
605
|
+
@response.sent!
|
743
606
|
end
|
744
607
|
|
745
|
-
|
608
|
+
@response
|
609
|
+
end
|
746
610
|
|
747
|
-
|
748
|
-
|
749
|
-
|
611
|
+
def scrub_env!(env)
|
612
|
+
env.delete_if do |k, _|
|
613
|
+
k.start_with?("rack.request", "action_dispatch.request", "action_dispatch.rescue")
|
614
|
+
end
|
615
|
+
env["rack.input"] = StringIO.new
|
616
|
+
env.delete "CONTENT_LENGTH"
|
617
|
+
env.delete "RAW_POST_DATA"
|
618
|
+
env
|
750
619
|
end
|
751
|
-
end
|
752
620
|
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
621
|
+
def document_root_element
|
622
|
+
html_document.root
|
623
|
+
end
|
624
|
+
|
625
|
+
def check_required_ivars
|
626
|
+
# Sanity check for required instance variables so we can give an
|
627
|
+
# understandable error message.
|
628
|
+
[:@routes, :@controller, :@request, :@response].each do |iv_name|
|
629
|
+
if !instance_variable_defined?(iv_name) || instance_variable_get(iv_name).nil?
|
630
|
+
raise "#{iv_name} is nil: make sure you set it in your test's setup method."
|
631
|
+
end
|
632
|
+
end
|
633
|
+
end
|
757
634
|
end
|
758
635
|
|
759
636
|
include Behavior
|