actionpack 3.2.22.5 → 5.2.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 +279 -603
- data/MIT-LICENSE +1 -1
- data/README.rdoc +13 -297
- data/lib/abstract_controller/asset_paths.rb +4 -2
- data/lib/abstract_controller/base.rb +82 -52
- data/lib/abstract_controller/caching/fragments.rb +166 -0
- data/lib/abstract_controller/caching.rb +66 -0
- data/lib/abstract_controller/callbacks.rb +117 -103
- data/lib/abstract_controller/collector.rb +18 -7
- data/lib/abstract_controller/error.rb +6 -0
- data/lib/abstract_controller/helpers.rb +65 -38
- data/lib/abstract_controller/logger.rb +3 -2
- data/lib/abstract_controller/railties/routes_helpers.rb +5 -3
- data/lib/abstract_controller/rendering.rb +77 -129
- data/lib/abstract_controller/translation.rb +21 -3
- data/lib/abstract_controller/url_for.rb +9 -7
- data/lib/abstract_controller.rb +12 -13
- data/lib/action_controller/api/api_rendering.rb +16 -0
- data/lib/action_controller/api.rb +149 -0
- data/lib/action_controller/base.rb +81 -40
- data/lib/action_controller/caching.rb +22 -62
- data/lib/action_controller/form_builder.rb +50 -0
- data/lib/action_controller/log_subscriber.rb +30 -18
- data/lib/action_controller/metal/basic_implicit_render.rb +13 -0
- data/lib/action_controller/metal/conditional_get.rb +190 -47
- 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 +40 -65
- data/lib/action_controller/metal/etag_with_flash.rb +18 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +57 -0
- data/lib/action_controller/metal/exceptions.rb +19 -12
- data/lib/action_controller/metal/flash.rb +42 -9
- data/lib/action_controller/metal/force_ssl.rb +79 -19
- data/lib/action_controller/metal/head.rb +35 -10
- data/lib/action_controller/metal/helpers.rb +31 -21
- data/lib/action_controller/metal/http_authentication.rb +182 -134
- data/lib/action_controller/metal/implicit_render.rb +62 -8
- data/lib/action_controller/metal/instrumentation.rb +28 -26
- data/lib/action_controller/metal/live.rb +312 -0
- data/lib/action_controller/metal/mime_responds.rb +159 -163
- data/lib/action_controller/metal/parameter_encoding.rb +51 -0
- data/lib/action_controller/metal/params_wrapper.rb +146 -93
- data/lib/action_controller/metal/redirecting.rb +80 -56
- data/lib/action_controller/metal/renderers.rb +119 -47
- data/lib/action_controller/metal/rendering.rb +89 -32
- data/lib/action_controller/metal/request_forgery_protection.rb +373 -41
- data/lib/action_controller/metal/rescue.rb +9 -16
- data/lib/action_controller/metal/streaming.rb +39 -45
- data/lib/action_controller/metal/strong_parameters.rb +1086 -0
- data/lib/action_controller/metal/testing.rb +8 -29
- data/lib/action_controller/metal/url_for.rb +43 -32
- data/lib/action_controller/metal.rb +112 -106
- data/lib/action_controller/railtie.rb +56 -18
- data/lib/action_controller/railties/helpers.rb +24 -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 +402 -347
- data/lib/action_controller.rb +31 -30
- data/lib/action_dispatch/http/cache.rb +133 -34
- data/lib/action_dispatch/http/content_security_policy.rb +272 -0
- data/lib/action_dispatch/http/filter_parameters.rb +40 -24
- data/lib/action_dispatch/http/filter_redirect.rb +37 -0
- data/lib/action_dispatch/http/headers.rb +117 -16
- data/lib/action_dispatch/http/mime_negotiation.rb +98 -33
- data/lib/action_dispatch/http/mime_type.rb +198 -146
- data/lib/action_dispatch/http/mime_types.rb +22 -7
- data/lib/action_dispatch/http/parameter_filter.rb +61 -49
- data/lib/action_dispatch/http/parameters.rb +94 -51
- data/lib/action_dispatch/http/rack_cache.rb +4 -3
- data/lib/action_dispatch/http/request.rb +262 -117
- data/lib/action_dispatch/http/response.rb +400 -86
- data/lib/action_dispatch/http/upload.rb +66 -29
- data/lib/action_dispatch/http/url.rb +232 -60
- data/lib/action_dispatch/journey/formatter.rb +189 -0
- data/lib/action_dispatch/journey/gtg/builder.rb +164 -0
- data/lib/action_dispatch/journey/gtg/simulator.rb +41 -0
- data/lib/action_dispatch/journey/gtg/transition_table.rb +158 -0
- data/lib/action_dispatch/journey/nfa/builder.rb +78 -0
- data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
- data/lib/action_dispatch/journey/nfa/simulator.rb +49 -0
- data/lib/action_dispatch/journey/nfa/transition_table.rb +120 -0
- data/lib/action_dispatch/journey/nodes/node.rb +140 -0
- data/lib/action_dispatch/journey/parser.rb +199 -0
- data/lib/action_dispatch/journey/parser.y +50 -0
- data/lib/action_dispatch/journey/parser_extras.rb +31 -0
- data/lib/action_dispatch/journey/path/pattern.rb +199 -0
- data/lib/action_dispatch/journey/route.rb +203 -0
- data/lib/action_dispatch/journey/router/utils.rb +102 -0
- data/lib/action_dispatch/journey/router.rb +156 -0
- data/lib/action_dispatch/journey/routes.rb +82 -0
- data/lib/action_dispatch/journey/scanner.rb +64 -0
- data/lib/action_dispatch/journey/visitors.rb +268 -0
- data/lib/action_dispatch/journey/visualizer/fsm.css +30 -0
- data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
- data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
- data/lib/action_dispatch/journey.rb +7 -0
- data/lib/action_dispatch/middleware/callbacks.rb +17 -13
- data/lib/action_dispatch/middleware/cookies.rb +494 -162
- data/lib/action_dispatch/middleware/debug_exceptions.rb +176 -53
- data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +103 -38
- data/lib/action_dispatch/middleware/executor.rb +21 -0
- data/lib/action_dispatch/middleware/flash.rb +128 -91
- data/lib/action_dispatch/middleware/public_exceptions.rb +43 -16
- data/lib/action_dispatch/middleware/reloader.rb +6 -83
- data/lib/action_dispatch/middleware/remote_ip.rb +151 -49
- data/lib/action_dispatch/middleware/request_id.rb +19 -15
- data/lib/action_dispatch/middleware/session/abstract_store.rb +38 -34
- data/lib/action_dispatch/middleware/session/cache_store.rb +14 -9
- data/lib/action_dispatch/middleware/session/cookie_store.rb +94 -44
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +15 -4
- data/lib/action_dispatch/middleware/show_exceptions.rb +36 -61
- data/lib/action_dispatch/middleware/ssl.rb +150 -0
- data/lib/action_dispatch/middleware/stack.rb +33 -41
- data/lib/action_dispatch/middleware/static.rb +92 -48
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +22 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +27 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +52 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +16 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -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 +134 -5
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +32 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +6 -0
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +200 -0
- data/lib/action_dispatch/railtie.rb +29 -8
- data/lib/action_dispatch/request/session.rb +234 -0
- data/lib/action_dispatch/request/utils.rb +78 -0
- data/lib/action_dispatch/routing/endpoint.rb +17 -0
- data/lib/action_dispatch/routing/inspector.rb +225 -0
- data/lib/action_dispatch/routing/mapper.rb +1329 -582
- data/lib/action_dispatch/routing/polymorphic_routes.rb +237 -94
- data/lib/action_dispatch/routing/redirection.rb +120 -50
- data/lib/action_dispatch/routing/route_set.rb +545 -322
- data/lib/action_dispatch/routing/routes_proxy.rb +37 -7
- data/lib/action_dispatch/routing/url_for.rb +103 -34
- data/lib/action_dispatch/routing.rb +66 -99
- 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/response.rb +53 -42
- data/lib/action_dispatch/testing/assertions/routing.rb +79 -74
- data/lib/action_dispatch/testing/assertions.rb +15 -9
- data/lib/action_dispatch/testing/integration.rb +361 -207
- data/lib/action_dispatch/testing/request_encoder.rb +55 -0
- data/lib/action_dispatch/testing/test_process.rb +28 -19
- data/lib/action_dispatch/testing/test_request.rb +30 -33
- data/lib/action_dispatch/testing/test_response.rb +35 -11
- data/lib/action_dispatch.rb +42 -32
- data/lib/action_pack/gem_version.rb +17 -0
- data/lib/action_pack/version.rb +7 -7
- data/lib/action_pack.rb +4 -2
- metadata +116 -175
- data/lib/abstract_controller/layouts.rb +0 -423
- data/lib/abstract_controller/view_paths.rb +0 -96
- data/lib/action_controller/caching/actions.rb +0 -185
- data/lib/action_controller/caching/fragments.rb +0 -127
- data/lib/action_controller/caching/pages.rb +0 -187
- data/lib/action_controller/caching/sweeping.rb +0 -97
- data/lib/action_controller/deprecated/integration_test.rb +0 -2
- data/lib/action_controller/deprecated/performance_test.rb +0 -1
- data/lib/action_controller/deprecated.rb +0 -3
- data/lib/action_controller/metal/compatibility.rb +0 -65
- data/lib/action_controller/metal/hide_actions.rb +0 -41
- data/lib/action_controller/metal/rack_delegation.rb +0 -26
- data/lib/action_controller/metal/responder.rb +0 -286
- data/lib/action_controller/metal/session_management.rb +0 -14
- data/lib/action_controller/middleware.rb +0 -39
- data/lib/action_controller/railties/paths.rb +0 -25
- data/lib/action_controller/record_identifier.rb +0 -85
- data/lib/action_controller/vendor/html-scanner/html/document.rb +0 -68
- data/lib/action_controller/vendor/html-scanner/html/node.rb +0 -532
- data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +0 -177
- data/lib/action_controller/vendor/html-scanner/html/selector.rb +0 -830
- data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +0 -107
- data/lib/action_controller/vendor/html-scanner/html/version.rb +0 -11
- data/lib/action_controller/vendor/html-scanner.rb +0 -20
- data/lib/action_dispatch/middleware/best_standards_support.rb +0 -30
- data/lib/action_dispatch/middleware/body_proxy.rb +0 -30
- data/lib/action_dispatch/middleware/head.rb +0 -18
- data/lib/action_dispatch/middleware/params_parser.rb +0 -75
- data/lib/action_dispatch/middleware/rescue.rb +0 -26
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +0 -31
- data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +0 -26
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +0 -10
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +0 -2
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +0 -15
- data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +0 -17
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +0 -2
- data/lib/action_dispatch/testing/assertions/dom.rb +0 -37
- data/lib/action_dispatch/testing/assertions/selector.rb +0 -435
- data/lib/action_dispatch/testing/assertions/tag.rb +0 -138
- data/lib/action_dispatch/testing/performance_test.rb +0 -10
- data/lib/action_view/asset_paths.rb +0 -142
- data/lib/action_view/base.rb +0 -220
- data/lib/action_view/buffers.rb +0 -43
- data/lib/action_view/context.rb +0 -36
- data/lib/action_view/flows.rb +0 -79
- data/lib/action_view/helpers/active_model_helper.rb +0 -50
- data/lib/action_view/helpers/asset_paths.rb +0 -7
- data/lib/action_view/helpers/asset_tag_helper.rb +0 -457
- data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +0 -146
- data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +0 -93
- data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +0 -193
- data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +0 -148
- data/lib/action_view/helpers/atom_feed_helper.rb +0 -200
- data/lib/action_view/helpers/cache_helper.rb +0 -64
- data/lib/action_view/helpers/capture_helper.rb +0 -203
- data/lib/action_view/helpers/controller_helper.rb +0 -25
- data/lib/action_view/helpers/csrf_helper.rb +0 -32
- data/lib/action_view/helpers/date_helper.rb +0 -1062
- data/lib/action_view/helpers/debug_helper.rb +0 -40
- data/lib/action_view/helpers/form_helper.rb +0 -1486
- data/lib/action_view/helpers/form_options_helper.rb +0 -658
- data/lib/action_view/helpers/form_tag_helper.rb +0 -685
- data/lib/action_view/helpers/javascript_helper.rb +0 -110
- data/lib/action_view/helpers/number_helper.rb +0 -622
- data/lib/action_view/helpers/output_safety_helper.rb +0 -38
- data/lib/action_view/helpers/record_tag_helper.rb +0 -111
- data/lib/action_view/helpers/rendering_helper.rb +0 -92
- data/lib/action_view/helpers/sanitize_helper.rb +0 -259
- data/lib/action_view/helpers/tag_helper.rb +0 -167
- data/lib/action_view/helpers/text_helper.rb +0 -426
- data/lib/action_view/helpers/translation_helper.rb +0 -91
- data/lib/action_view/helpers/url_helper.rb +0 -693
- data/lib/action_view/helpers.rb +0 -60
- data/lib/action_view/locale/en.yml +0 -160
- data/lib/action_view/log_subscriber.rb +0 -28
- data/lib/action_view/lookup_context.rb +0 -258
- data/lib/action_view/path_set.rb +0 -101
- data/lib/action_view/railtie.rb +0 -55
- data/lib/action_view/renderer/abstract_renderer.rb +0 -41
- data/lib/action_view/renderer/partial_renderer.rb +0 -415
- data/lib/action_view/renderer/renderer.rb +0 -61
- data/lib/action_view/renderer/streaming_template_renderer.rb +0 -106
- data/lib/action_view/renderer/template_renderer.rb +0 -95
- data/lib/action_view/template/error.rb +0 -128
- data/lib/action_view/template/handlers/builder.rb +0 -26
- data/lib/action_view/template/handlers/erb.rb +0 -125
- data/lib/action_view/template/handlers.rb +0 -50
- data/lib/action_view/template/resolver.rb +0 -298
- data/lib/action_view/template/text.rb +0 -30
- data/lib/action_view/template.rb +0 -337
- data/lib/action_view/test_case.rb +0 -246
- data/lib/action_view/testing/resolvers.rb +0 -49
- data/lib/action_view.rb +0 -84
- data/lib/sprockets/assets.rake +0 -99
- data/lib/sprockets/bootstrap.rb +0 -37
- data/lib/sprockets/compressors.rb +0 -83
- data/lib/sprockets/helpers/isolated_helper.rb +0 -13
- data/lib/sprockets/helpers/rails_helper.rb +0 -182
- data/lib/sprockets/helpers.rb +0 -6
- data/lib/sprockets/railtie.rb +0 -62
- data/lib/sprockets/static_compiler.rb +0 -56
@@ -1,264 +1,237 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
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"
|
6
12
|
|
7
13
|
module ActionController
|
8
|
-
|
9
|
-
|
14
|
+
class Metal
|
15
|
+
include Testing::Functional
|
16
|
+
end
|
10
17
|
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
14
26
|
end
|
27
|
+
end
|
15
28
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
ActiveSupport::Notifications.subscribe("render_template.action_view") do |name, start, finish, id, payload|
|
22
|
-
path = payload[:layout]
|
23
|
-
if path
|
24
|
-
@layouts[path] += 1
|
25
|
-
if path =~ /^layouts\/(.*)/
|
26
|
-
@layouts[$1] += 1
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
29
|
+
# ActionController::TestCase will be deprecated and moved to a gem in Rails 5.1.
|
30
|
+
# Please use ActionDispatch::IntegrationTest going forward.
|
31
|
+
class TestRequest < ActionDispatch::TestRequest #:nodoc:
|
32
|
+
DEFAULT_ENV = ActionDispatch::TestRequest::DEFAULT_ENV.dup
|
33
|
+
DEFAULT_ENV.delete "PATH_INFO"
|
30
34
|
|
31
|
-
|
32
|
-
|
33
|
-
next unless path
|
34
|
-
partial = path =~ /^.*\/_[^\/]*$/
|
35
|
-
if partial
|
36
|
-
@partials[path] += 1
|
37
|
-
@partials[path.split("/").last] += 1
|
38
|
-
@templates[path] += 1
|
39
|
-
else
|
40
|
-
@templates[path] += 1
|
41
|
-
end
|
42
|
-
end
|
35
|
+
def self.new_session
|
36
|
+
TestSession.new
|
43
37
|
end
|
44
38
|
|
45
|
-
|
46
|
-
|
47
|
-
|
39
|
+
attr_reader :controller_class
|
40
|
+
|
41
|
+
# Create a new test request with default `env` values.
|
42
|
+
def self.create(controller_class)
|
43
|
+
env = {}
|
44
|
+
env = Rails.application.env_config.merge(env) if defined?(Rails.application) && Rails.application
|
45
|
+
env["rack.request.cookie_hash"] = {}.with_indifferent_access
|
46
|
+
new(default_env.merge(env), new_session, controller_class)
|
48
47
|
end
|
49
48
|
|
50
|
-
def
|
51
|
-
|
52
|
-
@templates = Hash.new(0)
|
53
|
-
@layouts = Hash.new(0)
|
54
|
-
super
|
49
|
+
def self.default_env
|
50
|
+
DEFAULT_ENV
|
55
51
|
end
|
52
|
+
private_class_method :default_env
|
56
53
|
|
57
|
-
|
58
|
-
|
59
|
-
# ==== Examples
|
60
|
-
#
|
61
|
-
# # assert that the "new" view template was rendered
|
62
|
-
# assert_template "new"
|
63
|
-
#
|
64
|
-
# # assert that the layout 'admin' was rendered
|
65
|
-
# assert_template :layout => 'admin'
|
66
|
-
# assert_template :layout => 'layouts/admin'
|
67
|
-
# assert_template :layout => :admin
|
68
|
-
#
|
69
|
-
# # assert that no layout was rendered
|
70
|
-
# assert_template :layout => nil
|
71
|
-
# assert_template :layout => false
|
72
|
-
#
|
73
|
-
# # assert that the "_customer" partial was rendered twice
|
74
|
-
# assert_template :partial => '_customer', :count => 2
|
75
|
-
#
|
76
|
-
# # assert that no partials were rendered
|
77
|
-
# assert_template :partial => false
|
78
|
-
#
|
79
|
-
# In a view test case, you can also assert that specific locals are passed
|
80
|
-
# to partials:
|
81
|
-
#
|
82
|
-
# # assert that the "_customer" partial was rendered with a specific object
|
83
|
-
# assert_template :partial => '_customer', :locals => { :customer => @customer }
|
84
|
-
#
|
85
|
-
def assert_template(options = {}, message = nil)
|
86
|
-
validate_request!
|
87
|
-
# Force body to be read in case the template is being streamed
|
88
|
-
response.body
|
89
|
-
|
90
|
-
case options
|
91
|
-
when NilClass, String, Symbol
|
92
|
-
options = options.to_s if Symbol === options
|
93
|
-
rendered = @templates
|
94
|
-
msg = build_message(message,
|
95
|
-
"expecting <?> but rendering with <?>",
|
96
|
-
options, rendered.keys.join(', '))
|
97
|
-
assert_block(msg) do
|
98
|
-
if options
|
99
|
-
rendered.any? { |t,num| t.match(options) }
|
100
|
-
else
|
101
|
-
@templates.blank?
|
102
|
-
end
|
103
|
-
end
|
104
|
-
when Hash
|
105
|
-
if options.key?(:layout)
|
106
|
-
expected_layout = options[:layout]
|
107
|
-
msg = build_message(message,
|
108
|
-
"expecting layout <?> but action rendered <?>",
|
109
|
-
expected_layout, @layouts.keys)
|
110
|
-
|
111
|
-
case expected_layout
|
112
|
-
when String, Symbol
|
113
|
-
assert(@layouts.keys.include?(expected_layout.to_s), msg)
|
114
|
-
when Regexp
|
115
|
-
assert(@layouts.keys.any? {|l| l =~ expected_layout }, msg)
|
116
|
-
when nil, false
|
117
|
-
assert(@layouts.empty?, msg)
|
118
|
-
end
|
119
|
-
end
|
54
|
+
def initialize(env, session, controller_class)
|
55
|
+
super(env)
|
120
56
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
end
|
128
|
-
else
|
129
|
-
warn "the :locals option to #assert_template is only supported in a ActionView::TestCase"
|
130
|
-
end
|
131
|
-
elsif expected_count = options[:count]
|
132
|
-
actual_count = @partials[expected_partial]
|
133
|
-
msg = build_message(message,
|
134
|
-
"expecting ? to be rendered ? time(s) but rendered ? time(s)",
|
135
|
-
expected_partial, expected_count, actual_count)
|
136
|
-
assert(actual_count == expected_count.to_i, msg)
|
137
|
-
else
|
138
|
-
msg = build_message(message,
|
139
|
-
"expecting partial <?> but action rendered <?>",
|
140
|
-
options[:partial], @partials.keys)
|
141
|
-
assert(@partials.include?(expected_partial), msg)
|
142
|
-
end
|
143
|
-
elsif options.key?(:partial)
|
144
|
-
assert @partials.empty?,
|
145
|
-
"Expected no partials to be rendered"
|
146
|
-
end
|
147
|
-
end
|
57
|
+
self.session = session
|
58
|
+
self.session_options = TestSession::DEFAULT_OPTIONS.dup
|
59
|
+
@controller_class = controller_class
|
60
|
+
@custom_param_parsers = {
|
61
|
+
xml: lambda { |raw_post| Hash.from_xml(raw_post)["hash"] }
|
62
|
+
}
|
148
63
|
end
|
149
|
-
end
|
150
|
-
|
151
|
-
class TestRequest < ActionDispatch::TestRequest #:nodoc:
|
152
|
-
def initialize(env = {})
|
153
|
-
super
|
154
64
|
|
155
|
-
|
156
|
-
|
65
|
+
def query_string=(string)
|
66
|
+
set_header Rack::QUERY_STRING, string
|
157
67
|
end
|
158
68
|
|
159
|
-
|
160
|
-
|
161
|
-
def self.new_escaped(strings)
|
162
|
-
new strings.collect {|str| uri_parser.unescape str}
|
163
|
-
end
|
69
|
+
def content_type=(type)
|
70
|
+
set_header "CONTENT_TYPE", type
|
164
71
|
end
|
165
72
|
|
166
|
-
def assign_parameters(routes, controller_path, action, parameters
|
167
|
-
|
168
|
-
|
169
|
-
non_path_parameters = get? ? query_parameters : request_parameters
|
170
|
-
parameters.each do |key, value|
|
171
|
-
if value.is_a?(Array) && (value.frozen? || value.any?(&:frozen?))
|
172
|
-
value = value.map{ |v| v.duplicable? ? v.dup : v }
|
173
|
-
elsif value.is_a?(Hash) && (value.frozen? || value.any?{ |k,v| v.frozen? })
|
174
|
-
value = Hash[value.map{ |k,v| [k, v.duplicable? ? v.dup : v] }]
|
175
|
-
elsif value.frozen? && value.duplicable?
|
176
|
-
value = value.dup
|
177
|
-
end
|
73
|
+
def assign_parameters(routes, controller_path, action, parameters, generated_path, query_string_keys)
|
74
|
+
non_path_parameters = {}
|
75
|
+
path_parameters = {}
|
178
76
|
|
179
|
-
|
77
|
+
parameters.each do |key, value|
|
78
|
+
if query_string_keys.include?(key)
|
180
79
|
non_path_parameters[key] = value
|
181
80
|
else
|
182
81
|
if value.is_a?(Array)
|
183
|
-
value =
|
82
|
+
value = value.map(&:to_param)
|
184
83
|
else
|
185
84
|
value = value.to_param
|
186
85
|
end
|
187
86
|
|
188
|
-
path_parameters[key
|
87
|
+
path_parameters[key] = value
|
189
88
|
end
|
190
89
|
end
|
191
90
|
|
192
|
-
|
193
|
-
|
91
|
+
if get?
|
92
|
+
if query_string.blank?
|
93
|
+
self.query_string = non_path_parameters.to_query
|
94
|
+
end
|
95
|
+
else
|
96
|
+
if ENCODER.should_multipart?(non_path_parameters)
|
97
|
+
self.content_type = ENCODER.content_type
|
98
|
+
data = ENCODER.build_multipart non_path_parameters
|
99
|
+
else
|
100
|
+
fetch_header("CONTENT_TYPE") do |k|
|
101
|
+
set_header k, "application/x-www-form-urlencoded"
|
102
|
+
end
|
194
103
|
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
104
|
+
case content_mime_type.to_sym
|
105
|
+
when nil
|
106
|
+
raise "Unknown Content-Type: #{content_type}"
|
107
|
+
when :json
|
108
|
+
data = ActiveSupport::JSON.encode(non_path_parameters)
|
109
|
+
when :xml
|
110
|
+
data = non_path_parameters.to_xml
|
111
|
+
when :url_encoded_form
|
112
|
+
data = non_path_parameters.to_query
|
113
|
+
else
|
114
|
+
@custom_param_parsers[content_mime_type.symbol] = ->(_) { non_path_parameters }
|
115
|
+
data = non_path_parameters.to_query
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
data_stream = StringIO.new(data)
|
120
|
+
set_header "CONTENT_LENGTH", data_stream.length.to_s
|
121
|
+
set_header "rack.input", data_stream
|
199
122
|
end
|
200
|
-
data = params.to_query
|
201
123
|
|
202
|
-
|
203
|
-
|
204
|
-
|
124
|
+
fetch_header("PATH_INFO") do |k|
|
125
|
+
set_header k, generated_path
|
126
|
+
end
|
127
|
+
path_parameters[:controller] = controller_path
|
128
|
+
path_parameters[:action] = action
|
205
129
|
|
206
|
-
|
207
|
-
@formats = nil
|
208
|
-
@env.delete_if { |k, v| k =~ /^(action_dispatch|rack)\.request/ }
|
209
|
-
@env.delete_if { |k, v| k =~ /^action_dispatch\.rescue/ }
|
210
|
-
@symbolized_path_params = nil
|
211
|
-
@method = @request_method = nil
|
212
|
-
@fullpath = @ip = @remote_ip = @protocol = nil
|
213
|
-
@env['action_dispatch.request.query_parameters'] = {}
|
214
|
-
@set_cookies ||= {}
|
215
|
-
@set_cookies.update(Hash[cookie_jar.instance_variable_get("@set_cookies").map{ |k,o| [k,o[:value]] }])
|
216
|
-
deleted_cookies = cookie_jar.instance_variable_get("@delete_cookies")
|
217
|
-
@set_cookies.reject!{ |k,v| deleted_cookies.include?(k) }
|
218
|
-
cookie_jar.update(rack_cookies)
|
219
|
-
cookie_jar.update(cookies)
|
220
|
-
cookie_jar.update(@set_cookies)
|
221
|
-
cookie_jar.recycle!
|
130
|
+
self.path_parameters = path_parameters
|
222
131
|
end
|
132
|
+
|
133
|
+
ENCODER = Class.new do
|
134
|
+
include Rack::Test::Utils
|
135
|
+
|
136
|
+
def should_multipart?(params)
|
137
|
+
# FIXME: lifted from Rack-Test. We should push this separation upstream.
|
138
|
+
multipart = false
|
139
|
+
query = lambda { |value|
|
140
|
+
case value
|
141
|
+
when Array
|
142
|
+
value.each(&query)
|
143
|
+
when Hash
|
144
|
+
value.values.each(&query)
|
145
|
+
when Rack::Test::UploadedFile
|
146
|
+
multipart = true
|
147
|
+
end
|
148
|
+
}
|
149
|
+
params.values.each(&query)
|
150
|
+
multipart
|
151
|
+
end
|
152
|
+
|
153
|
+
public :build_multipart
|
154
|
+
|
155
|
+
def content_type
|
156
|
+
"multipart/form-data; boundary=#{Rack::Test::MULTIPART_BOUNDARY}"
|
157
|
+
end
|
158
|
+
end.new
|
159
|
+
|
160
|
+
private
|
161
|
+
|
162
|
+
def params_parsers
|
163
|
+
super.merge @custom_param_parsers
|
164
|
+
end
|
223
165
|
end
|
224
166
|
|
225
|
-
class
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
@request = @template = nil
|
235
|
-
end
|
167
|
+
class LiveTestResponse < Live::Response
|
168
|
+
# Was the response successful?
|
169
|
+
alias_method :success?, :successful?
|
170
|
+
|
171
|
+
# Was the URL not found?
|
172
|
+
alias_method :missing?, :not_found?
|
173
|
+
|
174
|
+
# Was there a server-side error?
|
175
|
+
alias_method :error?, :server_error?
|
236
176
|
end
|
237
177
|
|
178
|
+
# Methods #destroy and #load! are overridden to avoid calling methods on the
|
179
|
+
# @store object, which does not exist for the TestSession class.
|
238
180
|
class TestSession < Rack::Session::Abstract::SessionHash #:nodoc:
|
239
|
-
DEFAULT_OPTIONS = Rack::Session::Abstract::
|
181
|
+
DEFAULT_OPTIONS = Rack::Session::Abstract::Persisted::DEFAULT_OPTIONS
|
240
182
|
|
241
183
|
def initialize(session = {})
|
242
184
|
super(nil, nil)
|
243
|
-
|
185
|
+
@id = SecureRandom.hex(16)
|
186
|
+
@data = stringify_keys(session)
|
244
187
|
@loaded = true
|
245
188
|
end
|
246
189
|
|
247
190
|
def exists?
|
248
191
|
true
|
249
192
|
end
|
193
|
+
|
194
|
+
def keys
|
195
|
+
@data.keys
|
196
|
+
end
|
197
|
+
|
198
|
+
def values
|
199
|
+
@data.values
|
200
|
+
end
|
201
|
+
|
202
|
+
def destroy
|
203
|
+
clear
|
204
|
+
end
|
205
|
+
|
206
|
+
def fetch(key, *args, &block)
|
207
|
+
@data.fetch(key.to_s, *args, &block)
|
208
|
+
end
|
209
|
+
|
210
|
+
private
|
211
|
+
|
212
|
+
def load!
|
213
|
+
@id
|
214
|
+
end
|
250
215
|
end
|
251
216
|
|
252
217
|
# Superclass for ActionController functional tests. Functional tests allow you to
|
253
|
-
# test a single controller action per test method.
|
254
|
-
#
|
255
|
-
#
|
256
|
-
#
|
218
|
+
# test a single controller action per test method.
|
219
|
+
#
|
220
|
+
# == Use integration style controller tests over functional style controller tests.
|
221
|
+
#
|
222
|
+
# Rails discourages the use of functional tests in favor of integration tests
|
223
|
+
# (use ActionDispatch::IntegrationTest).
|
224
|
+
#
|
225
|
+
# New Rails applications no longer generate functional style controller tests and they should
|
226
|
+
# only be used for backward compatibility. Integration style controller tests perform actual
|
227
|
+
# requests, whereas functional style controller tests merely simulate a request. Besides,
|
228
|
+
# integration tests are as fast as functional tests and provide lot of helpers such as +as+,
|
229
|
+
# +parsed_body+ for effective testing of controller actions including even API endpoints.
|
257
230
|
#
|
258
231
|
# == Basic example
|
259
232
|
#
|
260
233
|
# Functional tests are written as follows:
|
261
|
-
# 1. First, one uses the +get+, +post+, +put+, +delete+ or +head+ method to simulate
|
234
|
+
# 1. First, one uses the +get+, +post+, +patch+, +put+, +delete+ or +head+ method to simulate
|
262
235
|
# an HTTP request.
|
263
236
|
# 2. Then, one asserts whether the current state is as expected. "State" can be anything:
|
264
237
|
# the controller's HTTP response, the database contents, etc.
|
@@ -268,17 +241,24 @@ module ActionController
|
|
268
241
|
# class BooksControllerTest < ActionController::TestCase
|
269
242
|
# def test_create
|
270
243
|
# # Simulate a POST response with the given HTTP parameters.
|
271
|
-
# post(:create, :book
|
244
|
+
# post(:create, params: { book: { title: "Love Hina" }})
|
272
245
|
#
|
273
|
-
# #
|
246
|
+
# # Asserts that the controller tried to redirect us to
|
274
247
|
# # the created book's URI.
|
275
248
|
# assert_response :found
|
276
249
|
#
|
277
|
-
# #
|
278
|
-
# assert_not_nil Book.
|
250
|
+
# # Asserts that the controller really put the book in the database.
|
251
|
+
# assert_not_nil Book.find_by(title: "Love Hina")
|
279
252
|
# end
|
280
253
|
# end
|
281
254
|
#
|
255
|
+
# You can also send a real document in the simulated HTTP request.
|
256
|
+
#
|
257
|
+
# def test_create
|
258
|
+
# json = {book: { title: "Love Hina" }}.to_json
|
259
|
+
# post :create, body: json
|
260
|
+
# end
|
261
|
+
#
|
282
262
|
# == Special instance variables
|
283
263
|
#
|
284
264
|
# ActionController::TestCase will also automatically provide the following instance
|
@@ -291,7 +271,7 @@ module ActionController
|
|
291
271
|
# request. You can modify this object before sending the HTTP request. For example,
|
292
272
|
# you might want to set some session properties before sending a GET request.
|
293
273
|
# <b>@response</b>::
|
294
|
-
# An
|
274
|
+
# An ActionDispatch::TestResponse object, representing the response
|
295
275
|
# of the last HTTP response. In the above example, <tt>@response</tt> becomes valid
|
296
276
|
# after calling +post+. If the various assert methods are not sufficient, then you
|
297
277
|
# may use this object to inspect the HTTP response in detail.
|
@@ -314,22 +294,16 @@ module ActionController
|
|
314
294
|
# In addition to these specific assertions, you also have easy access to various collections that the regular test/unit assertions
|
315
295
|
# can be used against. These collections are:
|
316
296
|
#
|
317
|
-
# * assigns: Instance variables assigned in the action that are available for the view.
|
318
297
|
# * session: Objects being saved in the session.
|
319
298
|
# * flash: The flash objects currently in the session.
|
320
299
|
# * cookies: \Cookies being sent to the user on this request.
|
321
300
|
#
|
322
301
|
# These collections can be used just like any other hash:
|
323
302
|
#
|
324
|
-
# assert_not_nil assigns(:person) # makes sure that a @person instance variable was set
|
325
303
|
# assert_equal "Dave", cookies[:name] # makes sure that a cookie called :name was set as "Dave"
|
326
304
|
# assert flash.empty? # makes sure that there's nothing in the flash
|
327
305
|
#
|
328
|
-
#
|
329
|
-
# appease our yearning for symbols, though, an alternative accessor has been devised using a method call instead of index referencing.
|
330
|
-
# So <tt>assigns(:person)</tt> will work just like <tt>assigns["person"]</tt>, but again, <tt>assigns[:person]</tt> will not work.
|
331
|
-
#
|
332
|
-
# On top of the collections, you have the complete url that a given action redirected to available in <tt>redirect_to_url</tt>.
|
306
|
+
# On top of the collections, you have the complete URL that a given action redirected to available in <tt>redirect_to_url</tt>.
|
333
307
|
#
|
334
308
|
# For redirects within the same controller, you can even call follow_redirect and the redirect will be followed, triggering another
|
335
309
|
# action call which can then be asserted against.
|
@@ -349,29 +323,28 @@ module ActionController
|
|
349
323
|
# == \Testing named routes
|
350
324
|
#
|
351
325
|
# If you're using named routes, they can be easily tested using the original named routes' methods straight in the test case.
|
352
|
-
# Example:
|
353
326
|
#
|
354
|
-
# assert_redirected_to page_url(:
|
327
|
+
# assert_redirected_to page_url(title: 'foo')
|
355
328
|
class TestCase < ActiveSupport::TestCase
|
356
329
|
module Behavior
|
357
330
|
extend ActiveSupport::Concern
|
358
331
|
include ActionDispatch::TestProcess
|
332
|
+
include ActiveSupport::Testing::ConstantLookup
|
333
|
+
include Rails::Dom::Testing::Assertions
|
359
334
|
|
360
335
|
attr_reader :response, :request
|
361
336
|
|
362
337
|
module ClassMethods
|
363
|
-
|
364
338
|
# Sets the controller class name. Useful if the name can't be inferred from test class.
|
365
|
-
# Normalizes +controller_class+ before using.
|
339
|
+
# Normalizes +controller_class+ before using.
|
366
340
|
#
|
367
341
|
# tests WidgetController
|
368
342
|
# tests :widget
|
369
343
|
# tests 'widget'
|
370
|
-
#
|
371
344
|
def tests(controller_class)
|
372
345
|
case controller_class
|
373
346
|
when String, Symbol
|
374
|
-
self.controller_class = "#{controller_class.to_s.
|
347
|
+
self.controller_class = "#{controller_class.to_s.camelize}Controller".constantize
|
375
348
|
when Class
|
376
349
|
self.controller_class = controller_class
|
377
350
|
else
|
@@ -380,12 +353,11 @@ module ActionController
|
|
380
353
|
end
|
381
354
|
|
382
355
|
def controller_class=(new_class)
|
383
|
-
prepare_controller_class(new_class) if new_class
|
384
356
|
self._controller_class = new_class
|
385
357
|
end
|
386
358
|
|
387
359
|
def controller_class
|
388
|
-
if current_controller_class =
|
360
|
+
if current_controller_class = _controller_class
|
389
361
|
current_controller_class
|
390
362
|
else
|
391
363
|
self.controller_class = determine_default_controller_class(name)
|
@@ -393,179 +365,262 @@ module ActionController
|
|
393
365
|
end
|
394
366
|
|
395
367
|
def determine_default_controller_class(name)
|
396
|
-
name
|
397
|
-
|
398
|
-
|
399
|
-
def prepare_controller_class(new_class)
|
400
|
-
new_class.send :include, ActionController::TestCase::RaiseActionExceptions
|
368
|
+
determine_constant_from_test_name(name) do |constant|
|
369
|
+
Class === constant && constant < ActionController::Metal
|
370
|
+
end
|
401
371
|
end
|
372
|
+
end
|
402
373
|
|
374
|
+
# Simulate a GET request with the given parameters.
|
375
|
+
#
|
376
|
+
# - +action+: The controller action to call.
|
377
|
+
# - +params+: The hash with HTTP parameters that you want to pass. This may be +nil+.
|
378
|
+
# - +body+: The request body with a string that is appropriately encoded
|
379
|
+
# (<tt>application/x-www-form-urlencoded</tt> or <tt>multipart/form-data</tt>).
|
380
|
+
# - +session+: A hash of parameters to store in the session. This may be +nil+.
|
381
|
+
# - +flash+: A hash of parameters to store in the flash. This may be +nil+.
|
382
|
+
#
|
383
|
+
# You can also simulate POST, PATCH, PUT, DELETE, and HEAD requests with
|
384
|
+
# +post+, +patch+, +put+, +delete+, and +head+.
|
385
|
+
# Example sending parameters, session and setting a flash message:
|
386
|
+
#
|
387
|
+
# get :show,
|
388
|
+
# params: { id: 7 },
|
389
|
+
# session: { user_id: 1 },
|
390
|
+
# flash: { notice: 'This is flash message' }
|
391
|
+
#
|
392
|
+
# Note that the request method is not verified. The different methods are
|
393
|
+
# available to make the tests more expressive.
|
394
|
+
def get(action, **args)
|
395
|
+
res = process(action, method: "GET", **args)
|
396
|
+
cookies.update res.cookies
|
397
|
+
res
|
403
398
|
end
|
404
399
|
|
405
|
-
#
|
406
|
-
|
407
|
-
|
400
|
+
# Simulate a POST request with the given parameters and set/volley the response.
|
401
|
+
# See +get+ for more details.
|
402
|
+
def post(action, **args)
|
403
|
+
process(action, method: "POST", **args)
|
408
404
|
end
|
409
405
|
|
410
|
-
#
|
411
|
-
|
412
|
-
|
406
|
+
# Simulate a PATCH request with the given parameters and set/volley the response.
|
407
|
+
# See +get+ for more details.
|
408
|
+
def patch(action, **args)
|
409
|
+
process(action, method: "PATCH", **args)
|
413
410
|
end
|
414
411
|
|
415
|
-
#
|
416
|
-
|
417
|
-
|
412
|
+
# Simulate a PUT request with the given parameters and set/volley the response.
|
413
|
+
# See +get+ for more details.
|
414
|
+
def put(action, **args)
|
415
|
+
process(action, method: "PUT", **args)
|
418
416
|
end
|
419
417
|
|
420
|
-
#
|
421
|
-
|
422
|
-
|
418
|
+
# Simulate a DELETE request with the given parameters and set/volley the response.
|
419
|
+
# See +get+ for more details.
|
420
|
+
def delete(action, **args)
|
421
|
+
process(action, method: "DELETE", **args)
|
423
422
|
end
|
424
423
|
|
425
|
-
#
|
426
|
-
|
427
|
-
|
424
|
+
# Simulate a HEAD request with the given parameters and set/volley the response.
|
425
|
+
# See +get+ for more details.
|
426
|
+
def head(action, **args)
|
427
|
+
process(action, method: "HEAD", **args)
|
428
428
|
end
|
429
429
|
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
430
|
+
# Simulate an HTTP request to +action+ by specifying request method,
|
431
|
+
# parameters and set/volley the response.
|
432
|
+
#
|
433
|
+
# - +action+: The controller action to call.
|
434
|
+
# - +method+: Request method used to send the HTTP request. Possible values
|
435
|
+
# are +GET+, +POST+, +PATCH+, +PUT+, +DELETE+, +HEAD+. Defaults to +GET+. Can be a symbol.
|
436
|
+
# - +params+: The hash with HTTP parameters that you want to pass. This may be +nil+.
|
437
|
+
# - +body+: The request body with a string that is appropriately encoded
|
438
|
+
# (<tt>application/x-www-form-urlencoded</tt> or <tt>multipart/form-data</tt>).
|
439
|
+
# - +session+: A hash of parameters to store in the session. This may be +nil+.
|
440
|
+
# - +flash+: A hash of parameters to store in the flash. This may be +nil+.
|
441
|
+
# - +format+: Request format. Defaults to +nil+. Can be string or symbol.
|
442
|
+
# - +as+: Content type. Defaults to +nil+. Must be a symbol that corresponds
|
443
|
+
# to a mime type.
|
444
|
+
#
|
445
|
+
# Example calling +create+ action and sending two params:
|
446
|
+
#
|
447
|
+
# process :create,
|
448
|
+
# method: 'POST',
|
449
|
+
# params: {
|
450
|
+
# user: { name: 'Gaurish Sharma', email: 'user@example.com' }
|
451
|
+
# },
|
452
|
+
# session: { user_id: 1 },
|
453
|
+
# flash: { notice: 'This is flash message' }
|
454
|
+
#
|
455
|
+
# To simulate +GET+, +POST+, +PATCH+, +PUT+, +DELETE+ and +HEAD+ requests
|
456
|
+
# prefer using #get, #post, #patch, #put, #delete and #head methods
|
457
|
+
# respectively which will make tests more expressive.
|
458
|
+
#
|
459
|
+
# Note that the request method is not verified.
|
460
|
+
def process(action, method: "GET", params: nil, session: nil, body: nil, flash: {}, format: nil, xhr: false, as: nil)
|
461
|
+
check_required_ivars
|
462
|
+
|
463
|
+
action = action.to_s.dup
|
464
|
+
http_method = method.to_s.upcase
|
465
|
+
|
466
|
+
@html_document = nil
|
467
|
+
|
468
|
+
cookies.update(@request.cookies)
|
469
|
+
cookies.update_cookies_from_jar
|
470
|
+
@request.set_header "HTTP_COOKIE", cookies.to_header
|
471
|
+
@request.delete_header "action_dispatch.cookies"
|
472
|
+
|
473
|
+
@request = TestRequest.new scrub_env!(@request.env), @request.session, @controller.class
|
474
|
+
@response = build_response @response_klass
|
475
|
+
@response.request = @request
|
476
|
+
@controller.recycle!
|
477
|
+
|
478
|
+
if body
|
479
|
+
@request.set_header "RAW_POST_DATA", body
|
436
480
|
end
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
Hash[hash_or_array_or_value.map{|key, value| [key, paramify_values(value)] }]
|
444
|
-
when Array
|
445
|
-
hash_or_array_or_value.map {|i| paramify_values(i)}
|
446
|
-
when Rack::Test::UploadedFile, ActionDispatch::Http::UploadedFile
|
447
|
-
hash_or_array_or_value
|
448
|
-
else
|
449
|
-
hash_or_array_or_value.to_param
|
481
|
+
|
482
|
+
@request.set_header "REQUEST_METHOD", http_method
|
483
|
+
|
484
|
+
if as
|
485
|
+
@request.content_type = Mime[as].to_s
|
486
|
+
format ||= as
|
450
487
|
end
|
451
|
-
end
|
452
488
|
|
453
|
-
|
454
|
-
# Ensure that numbers and symbols passed as params are converted to
|
455
|
-
# proper params, as is the case when engaging rack.
|
456
|
-
parameters = paramify_values(parameters) if html_format?(parameters)
|
489
|
+
parameters = (params || {}).symbolize_keys
|
457
490
|
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
491
|
+
if format
|
492
|
+
parameters[:format] = format
|
493
|
+
end
|
494
|
+
|
495
|
+
generated_extras = @routes.generate_extras(parameters.merge(controller: controller_class_name, action: action))
|
496
|
+
generated_path = generated_path(generated_extras)
|
497
|
+
query_string_keys = query_parameter_names(generated_extras)
|
498
|
+
|
499
|
+
@request.assign_parameters(@routes, controller_class_name, action, parameters, generated_path, query_string_keys)
|
500
|
+
|
501
|
+
@request.session.update(session) if session
|
502
|
+
@request.flash.update(flash || {})
|
503
|
+
|
504
|
+
if xhr
|
505
|
+
@request.set_header "HTTP_X_REQUESTED_WITH", "XMLHttpRequest"
|
506
|
+
@request.fetch_header("HTTP_ACCEPT") do |k|
|
507
|
+
@request.set_header k, [Mime[:js], Mime[:html], Mime[:xml], "text/xml", "*/*"].join(", ")
|
463
508
|
end
|
464
509
|
end
|
465
510
|
|
466
|
-
@request.
|
467
|
-
|
468
|
-
|
469
|
-
@controller.formats = nil
|
470
|
-
@controller.params = nil
|
511
|
+
@request.fetch_header("SCRIPT_NAME") do |k|
|
512
|
+
@request.set_header k, @controller.config.relative_url_root
|
513
|
+
end
|
471
514
|
|
472
|
-
|
473
|
-
|
515
|
+
begin
|
516
|
+
@controller.recycle!
|
517
|
+
@controller.dispatch(action, @request, @response)
|
518
|
+
ensure
|
519
|
+
@request = @controller.request
|
520
|
+
@response = @controller.response
|
521
|
+
|
522
|
+
if @request.have_cookie_jar?
|
523
|
+
unless @request.cookie_jar.committed?
|
524
|
+
@request.cookie_jar.write(@response)
|
525
|
+
cookies.update(@request.cookie_jar.instance_variable_get(:@cookies))
|
526
|
+
end
|
527
|
+
end
|
528
|
+
@response.prepare!
|
474
529
|
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
530
|
+
if flash_value = @request.flash.to_session_value
|
531
|
+
@request.session["flash"] = flash_value
|
532
|
+
else
|
533
|
+
@request.session.delete("flash")
|
534
|
+
end
|
479
535
|
|
480
|
-
|
536
|
+
if xhr
|
537
|
+
@request.delete_header "HTTP_X_REQUESTED_WITH"
|
538
|
+
@request.delete_header "HTTP_ACCEPT"
|
539
|
+
end
|
540
|
+
@request.query_string = ""
|
481
541
|
|
482
|
-
|
483
|
-
|
484
|
-
@request.session["flash"].sweep
|
542
|
+
@response.sent!
|
543
|
+
end
|
485
544
|
|
486
|
-
@controller.request = @request
|
487
|
-
build_request_uri(action, parameters)
|
488
|
-
@controller.class.class_eval { include Testing }
|
489
|
-
@controller.recycle!
|
490
|
-
@controller.process_with_new_base_test(@request, @response)
|
491
|
-
@assigns = @controller.respond_to?(:view_assigns) ? @controller.view_assigns : {}
|
492
|
-
@request.session.delete('flash') if @request.session['flash'].blank?
|
493
545
|
@response
|
494
546
|
end
|
495
547
|
|
548
|
+
def controller_class_name
|
549
|
+
@controller.class.anonymous? ? "anonymous" : @controller.class.controller_path
|
550
|
+
end
|
551
|
+
|
552
|
+
def generated_path(generated_extras)
|
553
|
+
generated_extras[0]
|
554
|
+
end
|
555
|
+
|
556
|
+
def query_parameter_names(generated_extras)
|
557
|
+
generated_extras[1] + [:controller, :action]
|
558
|
+
end
|
559
|
+
|
496
560
|
def setup_controller_request_and_response
|
497
|
-
@
|
498
|
-
|
561
|
+
@controller = nil unless defined? @controller
|
562
|
+
|
563
|
+
@response_klass = ActionDispatch::TestResponse
|
499
564
|
|
500
565
|
if klass = self.class.controller_class
|
501
|
-
|
566
|
+
if klass < ActionController::Live
|
567
|
+
@response_klass = LiveTestResponse
|
568
|
+
end
|
569
|
+
unless @controller
|
570
|
+
begin
|
571
|
+
@controller = klass.new
|
572
|
+
rescue
|
573
|
+
warn "could not construct controller #{klass}" if $VERBOSE
|
574
|
+
end
|
575
|
+
end
|
502
576
|
end
|
503
577
|
|
504
|
-
@request.
|
578
|
+
@request = TestRequest.create(@controller.class)
|
579
|
+
@response = build_response @response_klass
|
580
|
+
@response.request = @request
|
505
581
|
|
506
|
-
if
|
582
|
+
if @controller
|
507
583
|
@controller.request = @request
|
508
584
|
@controller.params = {}
|
509
585
|
end
|
510
586
|
end
|
511
587
|
|
588
|
+
def build_response(klass)
|
589
|
+
klass.create
|
590
|
+
end
|
591
|
+
|
512
592
|
included do
|
513
593
|
include ActionController::TemplateAssertions
|
514
594
|
include ActionDispatch::Assertions
|
515
595
|
class_attribute :_controller_class
|
516
596
|
setup :setup_controller_request_and_response
|
597
|
+
ActiveSupport.run_load_hooks(:action_controller_test_case, self)
|
517
598
|
end
|
518
599
|
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
url, query_string = @routes.url_for(options).split("?", 2)
|
531
|
-
|
532
|
-
@request.env["SCRIPT_NAME"] = @controller.config.relative_url_root
|
533
|
-
@request.env["PATH_INFO"] = url
|
534
|
-
@request.env["QUERY_STRING"] = query_string || ""
|
600
|
+
private
|
601
|
+
|
602
|
+
def scrub_env!(env)
|
603
|
+
env.delete_if { |k, v| k =~ /^(action_dispatch|rack)\.request/ }
|
604
|
+
env.delete_if { |k, v| k =~ /^action_dispatch\.rescue/ }
|
605
|
+
env.delete "action_dispatch.request.query_parameters"
|
606
|
+
env.delete "action_dispatch.request.request_parameters"
|
607
|
+
env["rack.input"] = StringIO.new
|
608
|
+
env.delete "CONTENT_LENGTH"
|
609
|
+
env.delete "RAW_POST_DATA"
|
610
|
+
env
|
535
611
|
end
|
536
|
-
end
|
537
612
|
|
538
|
-
|
539
|
-
|
540
|
-
format = Mime[parameters[:format]]
|
541
|
-
format.nil? || format.html?
|
542
|
-
end
|
543
|
-
end
|
544
|
-
|
545
|
-
# When the request.remote_addr remains the default for testing, which is 0.0.0.0, the exception is simply raised inline
|
546
|
-
# (skipping the regular exception handling from rescue_action). If the request.remote_addr is anything else, the regular
|
547
|
-
# rescue_action process takes place. This means you can test your rescue_action code by setting remote_addr to something else
|
548
|
-
# than 0.0.0.0.
|
549
|
-
#
|
550
|
-
# The exception is stored in the exception accessor for further inspection.
|
551
|
-
module RaiseActionExceptions
|
552
|
-
def self.included(base)
|
553
|
-
unless base.method_defined?(:exception) && base.method_defined?(:exception=)
|
554
|
-
base.class_eval do
|
555
|
-
attr_accessor :exception
|
556
|
-
protected :exception, :exception=
|
557
|
-
end
|
613
|
+
def document_root_element
|
614
|
+
html_document.root
|
558
615
|
end
|
559
|
-
end
|
560
616
|
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
super(e)
|
617
|
+
def check_required_ivars
|
618
|
+
# Sanity check for required instance variables so we can give an
|
619
|
+
# understandable error message.
|
620
|
+
[:@routes, :@controller, :@request, :@response].each do |iv_name|
|
621
|
+
if !instance_variable_defined?(iv_name) || instance_variable_get(iv_name).nil?
|
622
|
+
raise "#{iv_name} is nil: make sure you set it in your test's setup method."
|
623
|
+
end
|
569
624
|
end
|
570
625
|
end
|
571
626
|
end
|