actionpack 4.2.8 → 5.2.4.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +285 -444
- data/MIT-LICENSE +1 -1
- data/README.rdoc +6 -7
- data/lib/abstract_controller.rb +12 -5
- data/lib/abstract_controller/asset_paths.rb +2 -0
- data/lib/abstract_controller/base.rb +45 -49
- data/lib/abstract_controller/caching.rb +66 -0
- data/lib/{action_controller → abstract_controller}/caching/fragments.rb +78 -15
- data/lib/abstract_controller/callbacks.rb +47 -31
- data/lib/abstract_controller/collector.rb +8 -11
- data/lib/abstract_controller/error.rb +6 -0
- data/lib/abstract_controller/helpers.rb +25 -25
- data/lib/abstract_controller/logger.rb +2 -0
- data/lib/abstract_controller/railties/routes_helpers.rb +4 -2
- data/lib/abstract_controller/rendering.rb +42 -41
- data/lib/abstract_controller/translation.rb +10 -7
- data/lib/abstract_controller/url_for.rb +2 -0
- data/lib/action_controller.rb +29 -21
- data/lib/action_controller/api.rb +149 -0
- data/lib/action_controller/api/api_rendering.rb +16 -0
- data/lib/action_controller/base.rb +27 -19
- data/lib/action_controller/caching.rb +14 -57
- data/lib/action_controller/form_builder.rb +50 -0
- data/lib/action_controller/log_subscriber.rb +10 -15
- data/lib/action_controller/metal.rb +98 -83
- data/lib/action_controller/metal/basic_implicit_render.rb +13 -0
- data/lib/action_controller/metal/conditional_get.rb +118 -44
- data/lib/action_controller/metal/content_security_policy.rb +52 -0
- data/lib/action_controller/metal/cookies.rb +3 -3
- data/lib/action_controller/metal/data_streaming.rb +27 -46
- data/lib/action_controller/metal/etag_with_flash.rb +18 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +20 -13
- data/lib/action_controller/metal/exceptions.rb +8 -14
- data/lib/action_controller/metal/flash.rb +4 -3
- data/lib/action_controller/metal/force_ssl.rb +23 -21
- data/lib/action_controller/metal/head.rb +21 -19
- data/lib/action_controller/metal/helpers.rb +24 -14
- data/lib/action_controller/metal/http_authentication.rb +64 -57
- data/lib/action_controller/metal/implicit_render.rb +62 -8
- data/lib/action_controller/metal/instrumentation.rb +19 -21
- data/lib/action_controller/metal/live.rb +90 -106
- data/lib/action_controller/metal/mime_responds.rb +33 -46
- data/lib/action_controller/metal/parameter_encoding.rb +51 -0
- data/lib/action_controller/metal/params_wrapper.rb +61 -53
- data/lib/action_controller/metal/redirecting.rb +49 -28
- data/lib/action_controller/metal/renderers.rb +87 -44
- data/lib/action_controller/metal/rendering.rb +72 -50
- data/lib/action_controller/metal/request_forgery_protection.rb +203 -92
- data/lib/action_controller/metal/rescue.rb +9 -16
- data/lib/action_controller/metal/streaming.rb +12 -10
- data/lib/action_controller/metal/strong_parameters.rb +582 -165
- data/lib/action_controller/metal/testing.rb +2 -17
- data/lib/action_controller/metal/url_for.rb +19 -10
- data/lib/action_controller/railtie.rb +28 -10
- data/lib/action_controller/railties/helpers.rb +2 -0
- data/lib/action_controller/renderer.rb +117 -0
- data/lib/action_controller/template_assertions.rb +11 -0
- data/lib/action_controller/test_case.rb +280 -411
- data/lib/action_dispatch.rb +27 -19
- data/lib/action_dispatch/http/cache.rb +93 -47
- data/lib/action_dispatch/http/content_security_policy.rb +272 -0
- data/lib/action_dispatch/http/filter_parameters.rb +26 -20
- data/lib/action_dispatch/http/filter_redirect.rb +10 -11
- data/lib/action_dispatch/http/headers.rb +55 -22
- data/lib/action_dispatch/http/mime_negotiation.rb +60 -41
- data/lib/action_dispatch/http/mime_type.rb +134 -121
- data/lib/action_dispatch/http/mime_types.rb +20 -6
- data/lib/action_dispatch/http/parameter_filter.rb +25 -11
- data/lib/action_dispatch/http/parameters.rb +98 -39
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +200 -118
- data/lib/action_dispatch/http/response.rb +225 -110
- data/lib/action_dispatch/http/upload.rb +12 -6
- data/lib/action_dispatch/http/url.rb +110 -28
- data/lib/action_dispatch/journey.rb +7 -5
- data/lib/action_dispatch/journey/formatter.rb +55 -32
- data/lib/action_dispatch/journey/gtg/builder.rb +7 -5
- data/lib/action_dispatch/journey/gtg/simulator.rb +3 -9
- data/lib/action_dispatch/journey/gtg/transition_table.rb +17 -16
- data/lib/action_dispatch/journey/nfa/builder.rb +5 -3
- data/lib/action_dispatch/journey/nfa/dot.rb +13 -13
- data/lib/action_dispatch/journey/nfa/simulator.rb +3 -1
- data/lib/action_dispatch/journey/nfa/transition_table.rb +5 -48
- data/lib/action_dispatch/journey/nodes/node.rb +18 -6
- data/lib/action_dispatch/journey/parser.rb +23 -22
- data/lib/action_dispatch/journey/parser.y +3 -2
- data/lib/action_dispatch/journey/parser_extras.rb +12 -4
- data/lib/action_dispatch/journey/path/pattern.rb +50 -44
- data/lib/action_dispatch/journey/route.rb +106 -28
- data/lib/action_dispatch/journey/router.rb +35 -23
- data/lib/action_dispatch/journey/router/utils.rb +20 -11
- data/lib/action_dispatch/journey/routes.rb +18 -16
- data/lib/action_dispatch/journey/scanner.rb +18 -15
- data/lib/action_dispatch/journey/visitors.rb +99 -52
- data/lib/action_dispatch/middleware/callbacks.rb +1 -2
- data/lib/action_dispatch/middleware/cookies.rb +304 -193
- data/lib/action_dispatch/middleware/debug_exceptions.rb +152 -57
- data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +68 -69
- data/lib/action_dispatch/middleware/executor.rb +21 -0
- data/lib/action_dispatch/middleware/flash.rb +78 -54
- data/lib/action_dispatch/middleware/public_exceptions.rb +27 -25
- data/lib/action_dispatch/middleware/reloader.rb +5 -91
- data/lib/action_dispatch/middleware/remote_ip.rb +41 -31
- data/lib/action_dispatch/middleware/request_id.rb +17 -9
- data/lib/action_dispatch/middleware/session/abstract_store.rb +41 -25
- data/lib/action_dispatch/middleware/session/cache_store.rb +24 -14
- data/lib/action_dispatch/middleware/session/cookie_store.rb +72 -67
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -2
- data/lib/action_dispatch/middleware/show_exceptions.rb +26 -22
- data/lib/action_dispatch/middleware/ssl.rb +114 -36
- data/lib/action_dispatch/middleware/stack.rb +31 -44
- data/lib/action_dispatch/middleware/static.rb +57 -50
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +2 -14
- data/lib/action_dispatch/middleware/templates/rescues/{_source.erb → _source.html.erb} +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +21 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +13 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +64 -64
- data/lib/action_dispatch/railtie.rb +19 -11
- data/lib/action_dispatch/request/session.rb +106 -59
- data/lib/action_dispatch/request/utils.rb +67 -24
- data/lib/action_dispatch/routing.rb +17 -18
- data/lib/action_dispatch/routing/endpoint.rb +9 -2
- data/lib/action_dispatch/routing/inspector.rb +58 -67
- data/lib/action_dispatch/routing/mapper.rb +734 -447
- data/lib/action_dispatch/routing/polymorphic_routes.rb +161 -139
- data/lib/action_dispatch/routing/redirection.rb +36 -26
- data/lib/action_dispatch/routing/route_set.rb +321 -291
- data/lib/action_dispatch/routing/routes_proxy.rb +32 -5
- data/lib/action_dispatch/routing/url_for.rb +65 -25
- data/lib/action_dispatch/system_test_case.rb +147 -0
- data/lib/action_dispatch/system_testing/browser.rb +49 -0
- data/lib/action_dispatch/system_testing/driver.rb +59 -0
- data/lib/action_dispatch/system_testing/server.rb +31 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +96 -0
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +31 -0
- data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +26 -0
- data/lib/action_dispatch/testing/assertion_response.rb +47 -0
- data/lib/action_dispatch/testing/assertions.rb +6 -4
- data/lib/action_dispatch/testing/assertions/response.rb +45 -20
- data/lib/action_dispatch/testing/assertions/routing.rb +30 -26
- data/lib/action_dispatch/testing/integration.rb +347 -209
- data/lib/action_dispatch/testing/request_encoder.rb +55 -0
- data/lib/action_dispatch/testing/test_process.rb +28 -22
- data/lib/action_dispatch/testing/test_request.rb +27 -34
- data/lib/action_dispatch/testing/test_response.rb +35 -7
- data/lib/action_pack.rb +4 -2
- data/lib/action_pack/gem_version.rb +5 -3
- data/lib/action_pack/version.rb +3 -1
- metadata +56 -39
- data/lib/action_controller/metal/hide_actions.rb +0 -40
- data/lib/action_controller/metal/rack_delegation.rb +0 -32
- data/lib/action_controller/middleware.rb +0 -39
- data/lib/action_controller/model_naming.rb +0 -12
- data/lib/action_dispatch/journey/backwards.rb +0 -5
- data/lib/action_dispatch/journey/router/strexp.rb +0 -27
- data/lib/action_dispatch/middleware/params_parser.rb +0 -60
- data/lib/action_dispatch/testing/assertions/dom.rb +0 -3
- data/lib/action_dispatch/testing/assertions/selector.rb +0 -3
- data/lib/action_dispatch/testing/assertions/tag.rb +0 -3
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActionDispatch
|
4
|
+
module SystemTesting
|
5
|
+
class Server # :nodoc:
|
6
|
+
class << self
|
7
|
+
attr_accessor :silence_puma
|
8
|
+
end
|
9
|
+
|
10
|
+
self.silence_puma = false
|
11
|
+
|
12
|
+
def run
|
13
|
+
setup
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
def setup
|
18
|
+
set_server
|
19
|
+
set_port
|
20
|
+
end
|
21
|
+
|
22
|
+
def set_server
|
23
|
+
Capybara.server = :puma, { Silent: self.class.silence_puma } if Capybara.server == Capybara.servers[:default]
|
24
|
+
end
|
25
|
+
|
26
|
+
def set_port
|
27
|
+
Capybara.always_include_port = true
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActionDispatch
|
4
|
+
module SystemTesting
|
5
|
+
module TestHelpers
|
6
|
+
# Screenshot helper for system testing.
|
7
|
+
module ScreenshotHelper
|
8
|
+
# Takes a screenshot of the current page in the browser.
|
9
|
+
#
|
10
|
+
# +take_screenshot+ can be used at any point in your system tests to take
|
11
|
+
# a screenshot of the current state. This can be useful for debugging or
|
12
|
+
# automating visual testing.
|
13
|
+
#
|
14
|
+
# The screenshot will be displayed in your console, if supported.
|
15
|
+
#
|
16
|
+
# You can set the +RAILS_SYSTEM_TESTING_SCREENSHOT+ environment variable to
|
17
|
+
# control the output. Possible values are:
|
18
|
+
# * [+simple+ (default)] Only displays the screenshot path.
|
19
|
+
# This is the default value.
|
20
|
+
# * [+inline+] Display the screenshot in the terminal using the
|
21
|
+
# iTerm image protocol (https://iterm2.com/documentation-images.html).
|
22
|
+
# * [+artifact+] Display the screenshot in the terminal, using the terminal
|
23
|
+
# artifact format (https://buildkite.github.io/terminal/inline-images/).
|
24
|
+
def take_screenshot
|
25
|
+
save_image
|
26
|
+
puts display_image
|
27
|
+
end
|
28
|
+
|
29
|
+
# Takes a screenshot of the current page in the browser if the test
|
30
|
+
# failed.
|
31
|
+
#
|
32
|
+
# +take_failed_screenshot+ is included in <tt>application_system_test_case.rb</tt>
|
33
|
+
# that is generated with the application. To take screenshots when a test
|
34
|
+
# fails add +take_failed_screenshot+ to the teardown block before clearing
|
35
|
+
# sessions.
|
36
|
+
def take_failed_screenshot
|
37
|
+
take_screenshot if failed? && supports_screenshot?
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
def image_name
|
42
|
+
failed? ? "failures_#{method_name}" : method_name
|
43
|
+
end
|
44
|
+
|
45
|
+
def image_path
|
46
|
+
@image_path ||= absolute_image_path.relative_path_from(Pathname.pwd).to_s
|
47
|
+
end
|
48
|
+
|
49
|
+
def absolute_image_path
|
50
|
+
Rails.root.join("tmp/screenshots/#{image_name}.png")
|
51
|
+
end
|
52
|
+
|
53
|
+
def save_image
|
54
|
+
page.save_screenshot(absolute_image_path)
|
55
|
+
end
|
56
|
+
|
57
|
+
def output_type
|
58
|
+
# Environment variables have priority
|
59
|
+
output_type = ENV["RAILS_SYSTEM_TESTING_SCREENSHOT"] || ENV["CAPYBARA_INLINE_SCREENSHOT"]
|
60
|
+
|
61
|
+
# Default to outputting a path to the screenshot
|
62
|
+
output_type ||= "simple"
|
63
|
+
|
64
|
+
output_type
|
65
|
+
end
|
66
|
+
|
67
|
+
def display_image
|
68
|
+
message = "[Screenshot]: #{image_path}\n".dup
|
69
|
+
|
70
|
+
case output_type
|
71
|
+
when "artifact"
|
72
|
+
message << "\e]1338;url=artifact://#{absolute_image_path}\a\n"
|
73
|
+
when "inline"
|
74
|
+
name = inline_base64(File.basename(absolute_image_path))
|
75
|
+
image = inline_base64(File.read(absolute_image_path))
|
76
|
+
message << "\e]1337;File=name=#{name};height=400px;inline=1:#{image}\a\n"
|
77
|
+
end
|
78
|
+
|
79
|
+
message
|
80
|
+
end
|
81
|
+
|
82
|
+
def inline_base64(path)
|
83
|
+
Base64.encode64(path).gsub("\n", "")
|
84
|
+
end
|
85
|
+
|
86
|
+
def failed?
|
87
|
+
!passed? && !skipped?
|
88
|
+
end
|
89
|
+
|
90
|
+
def supports_screenshot?
|
91
|
+
Capybara.current_driver != :rack_test
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActionDispatch
|
4
|
+
module SystemTesting
|
5
|
+
module TestHelpers
|
6
|
+
module SetupAndTeardown # :nodoc:
|
7
|
+
DEFAULT_HOST = "http://127.0.0.1"
|
8
|
+
|
9
|
+
def host!(host)
|
10
|
+
super
|
11
|
+
Capybara.app_host = host
|
12
|
+
end
|
13
|
+
|
14
|
+
def before_setup
|
15
|
+
host! DEFAULT_HOST
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
def after_teardown
|
20
|
+
begin
|
21
|
+
take_failed_screenshot
|
22
|
+
ensure
|
23
|
+
Capybara.reset_sessions!
|
24
|
+
end
|
25
|
+
ensure
|
26
|
+
super
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActionDispatch
|
4
|
+
module SystemTesting
|
5
|
+
module TestHelpers
|
6
|
+
module UndefMethods # :nodoc:
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
included do
|
9
|
+
METHODS = %i(get post put patch delete).freeze
|
10
|
+
|
11
|
+
METHODS.each do |verb|
|
12
|
+
undef_method verb
|
13
|
+
end
|
14
|
+
|
15
|
+
def method_missing(method, *args, &block)
|
16
|
+
if METHODS.include?(method)
|
17
|
+
raise NoMethodError, "System tests cannot make direct requests via ##{method}; use #visit and #click_on instead. See http://www.rubydoc.info/github/teamcapybara/capybara/master#The_DSL for more information."
|
18
|
+
else
|
19
|
+
super
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActionDispatch
|
4
|
+
# This is a class that abstracts away an asserted response. It purposely
|
5
|
+
# does not inherit from Response because it doesn't need it. That means it
|
6
|
+
# does not have headers or a body.
|
7
|
+
class AssertionResponse
|
8
|
+
attr_reader :code, :name
|
9
|
+
|
10
|
+
GENERIC_RESPONSE_CODES = { # :nodoc:
|
11
|
+
success: "2XX",
|
12
|
+
missing: "404",
|
13
|
+
redirect: "3XX",
|
14
|
+
error: "5XX"
|
15
|
+
}
|
16
|
+
|
17
|
+
# Accepts a specific response status code as an Integer (404) or String
|
18
|
+
# ('404') or a response status range as a Symbol pseudo-code (:success,
|
19
|
+
# indicating any 200-299 status code).
|
20
|
+
def initialize(code_or_name)
|
21
|
+
if code_or_name.is_a?(Symbol)
|
22
|
+
@name = code_or_name
|
23
|
+
@code = code_from_name(code_or_name)
|
24
|
+
else
|
25
|
+
@name = name_from_code(code_or_name)
|
26
|
+
@code = code_or_name
|
27
|
+
end
|
28
|
+
|
29
|
+
raise ArgumentError, "Invalid response name: #{name}" if @code.nil?
|
30
|
+
raise ArgumentError, "Invalid response code: #{code}" if @name.nil?
|
31
|
+
end
|
32
|
+
|
33
|
+
def code_and_name
|
34
|
+
"#{code}: #{name}"
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def code_from_name(name)
|
40
|
+
GENERIC_RESPONSE_CODES[name] || Rack::Utils::SYMBOL_TO_STATUS_CODE[name]
|
41
|
+
end
|
42
|
+
|
43
|
+
def name_from_code(code)
|
44
|
+
GENERIC_RESPONSE_CODES.invert[code] || Rack::Utils::HTTP_STATUS_CODES[code]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -1,9 +1,11 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails-dom-testing"
|
2
4
|
|
3
5
|
module ActionDispatch
|
4
6
|
module Assertions
|
5
|
-
autoload :ResponseAssertions,
|
6
|
-
autoload :RoutingAssertions,
|
7
|
+
autoload :ResponseAssertions, "action_dispatch/testing/assertions/response"
|
8
|
+
autoload :RoutingAssertions, "action_dispatch/testing/assertions/routing"
|
7
9
|
|
8
10
|
extend ActiveSupport::Concern
|
9
11
|
|
@@ -12,7 +14,7 @@ module ActionDispatch
|
|
12
14
|
include Rails::Dom::Testing::Assertions
|
13
15
|
|
14
16
|
def html_document
|
15
|
-
@html_document ||= if @response.content_type.to_s
|
17
|
+
@html_document ||= if @response.content_type.to_s.end_with?("xml")
|
16
18
|
Nokogiri::XML::Document.parse(@response.body)
|
17
19
|
else
|
18
20
|
Nokogiri::HTML::Document.parse(@response.body)
|
@@ -1,8 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
|
2
3
|
module ActionDispatch
|
3
4
|
module Assertions
|
4
5
|
# A small suite of assertions that test responses from \Rails applications.
|
5
6
|
module ResponseAssertions
|
7
|
+
RESPONSE_PREDICATES = { # :nodoc:
|
8
|
+
success: :successful?,
|
9
|
+
missing: :not_found?,
|
10
|
+
redirect: :redirection?,
|
11
|
+
error: :server_error?,
|
12
|
+
}
|
13
|
+
|
6
14
|
# Asserts that the response is one of the following types:
|
7
15
|
#
|
8
16
|
# * <tt>:success</tt> - Status code was in the 200-299 range
|
@@ -14,45 +22,37 @@ module ActionDispatch
|
|
14
22
|
# or its symbolic equivalent <tt>assert_response(:not_implemented)</tt>.
|
15
23
|
# See Rack::Utils::SYMBOL_TO_STATUS_CODE for a full list.
|
16
24
|
#
|
17
|
-
# #
|
25
|
+
# # Asserts that the response was a redirection
|
18
26
|
# assert_response :redirect
|
19
27
|
#
|
20
|
-
# #
|
28
|
+
# # Asserts that the response code was status code 401 (unauthorized)
|
21
29
|
# assert_response 401
|
22
30
|
def assert_response(type, message = nil)
|
23
|
-
message ||=
|
31
|
+
message ||= generate_response_message(type)
|
24
32
|
|
25
|
-
if
|
26
|
-
|
27
|
-
assert @response.send("#{type}?"), message
|
28
|
-
else
|
29
|
-
code = Rack::Utils::SYMBOL_TO_STATUS_CODE[type]
|
30
|
-
if code.nil?
|
31
|
-
raise ArgumentError, "Invalid response type :#{type}"
|
32
|
-
end
|
33
|
-
assert_equal code, @response.response_code, message
|
34
|
-
end
|
33
|
+
if RESPONSE_PREDICATES.keys.include?(type)
|
34
|
+
assert @response.send(RESPONSE_PREDICATES[type]), message
|
35
35
|
else
|
36
|
-
assert_equal type, @response.response_code, message
|
36
|
+
assert_equal AssertionResponse.new(type).code, @response.response_code, message
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
-
#
|
40
|
+
# Asserts that the redirection options passed in match those of the redirect called in the latest action.
|
41
41
|
# This match can be partial, such that <tt>assert_redirected_to(controller: "weblog")</tt> will also
|
42
42
|
# match the redirection of <tt>redirect_to(controller: "weblog", action: "show")</tt> and so on.
|
43
43
|
#
|
44
|
-
# #
|
44
|
+
# # Asserts that the redirection was to the "index" action on the WeblogController
|
45
45
|
# assert_redirected_to controller: "weblog", action: "index"
|
46
46
|
#
|
47
|
-
# #
|
47
|
+
# # Asserts that the redirection was to the named route login_url
|
48
48
|
# assert_redirected_to login_url
|
49
49
|
#
|
50
|
-
# #
|
50
|
+
# # Asserts that the redirection was to the URL for @customer
|
51
51
|
# assert_redirected_to @customer
|
52
52
|
#
|
53
|
-
# #
|
53
|
+
# # Asserts that the redirection matches the regular expression
|
54
54
|
# assert_redirected_to %r(\Ahttp://example.org)
|
55
|
-
def assert_redirected_to(options = {}, message=nil)
|
55
|
+
def assert_redirected_to(options = {}, message = nil)
|
56
56
|
assert_response(:redirect, message)
|
57
57
|
return true if options === @response.location
|
58
58
|
|
@@ -77,6 +77,31 @@ module ActionDispatch
|
|
77
77
|
handle._compute_redirect_to_location(@request, fragment)
|
78
78
|
end
|
79
79
|
end
|
80
|
+
|
81
|
+
def generate_response_message(expected, actual = @response.response_code)
|
82
|
+
"Expected response to be a <#{code_with_name(expected)}>,"\
|
83
|
+
" but was a <#{code_with_name(actual)}>"
|
84
|
+
.dup.concat(location_if_redirected).concat(response_body_if_short)
|
85
|
+
end
|
86
|
+
|
87
|
+
def response_body_if_short
|
88
|
+
return "" if @response.body.size > 500
|
89
|
+
"\nResponse body: #{@response.body}"
|
90
|
+
end
|
91
|
+
|
92
|
+
def location_if_redirected
|
93
|
+
return "" unless @response.redirection? && @response.location.present?
|
94
|
+
location = normalize_argument_to_redirection(@response.location)
|
95
|
+
" redirect to <#{location}>"
|
96
|
+
end
|
97
|
+
|
98
|
+
def code_with_name(code_or_name)
|
99
|
+
if RESPONSE_PREDICATES.values.include?("#{code_or_name}?".to_sym)
|
100
|
+
code_or_name = RESPONSE_PREDICATES.invert["#{code_or_name}?".to_sym]
|
101
|
+
end
|
102
|
+
|
103
|
+
AssertionResponse.new(code_or_name).code_and_name
|
104
|
+
end
|
80
105
|
end
|
81
106
|
end
|
82
107
|
end
|
@@ -1,7 +1,9 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "uri"
|
4
|
+
require "active_support/core_ext/hash/indifferent_access"
|
5
|
+
require "active_support/core_ext/string/access"
|
6
|
+
require "action_controller/metal/exceptions"
|
5
7
|
|
6
8
|
module ActionDispatch
|
7
9
|
module Assertions
|
@@ -14,14 +16,14 @@ module ActionDispatch
|
|
14
16
|
# requiring a specific HTTP method. The hash should contain a :path with the incoming request path
|
15
17
|
# and a :method containing the required HTTP verb.
|
16
18
|
#
|
17
|
-
# #
|
19
|
+
# # Asserts that POSTing to /items will call the create action on ItemsController
|
18
20
|
# assert_recognizes({controller: 'items', action: 'create'}, {path: 'items', method: :post})
|
19
21
|
#
|
20
22
|
# You can also pass in +extras+ with a hash containing URL parameters that would normally be in the query string. This can be used
|
21
|
-
# to assert that values in the query string
|
22
|
-
#
|
23
|
+
# to assert that values in the query string will end up in the params hash correctly. To test query strings you must use the extras
|
24
|
+
# argument because appending the query string on the path directly will not work. For example:
|
23
25
|
#
|
24
|
-
# #
|
26
|
+
# # Asserts that a path of '/items/list/1?view=print' returns the correct options
|
25
27
|
# assert_recognizes({controller: 'items', action: 'list', id: '1', view: 'print'}, 'items/list/1', { view: "print" })
|
26
28
|
#
|
27
29
|
# The +message+ parameter allows you to pass in an error message that is displayed upon failure.
|
@@ -37,7 +39,7 @@ module ActionDispatch
|
|
37
39
|
#
|
38
40
|
# # Test a custom route
|
39
41
|
# assert_recognizes({controller: 'items', action: 'show', id: '1'}, 'view/item1')
|
40
|
-
def assert_recognizes(expected_options, path, extras={}, msg=nil)
|
42
|
+
def assert_recognizes(expected_options, path, extras = {}, msg = nil)
|
41
43
|
if path.is_a?(Hash) && path[:method].to_s == "all"
|
42
44
|
[:get, :post, :put, :delete].each do |method|
|
43
45
|
assert_recognizes(expected_options, path.merge(method: method), extras, msg)
|
@@ -75,19 +77,20 @@ module ActionDispatch
|
|
75
77
|
#
|
76
78
|
# # Asserts that the generated route gives us our custom route
|
77
79
|
# assert_generates "changesets/12", { controller: 'scm', action: 'show_diff', revision: "12" }
|
78
|
-
def assert_generates(expected_path, options, defaults={}, extras={}, message=nil)
|
80
|
+
def assert_generates(expected_path, options, defaults = {}, extras = {}, message = nil)
|
79
81
|
if expected_path =~ %r{://}
|
80
82
|
fail_on(URI::InvalidURIError, message) do
|
81
83
|
uri = URI.parse(expected_path)
|
82
84
|
expected_path = uri.path.to_s.empty? ? "/" : uri.path
|
83
85
|
end
|
84
86
|
else
|
85
|
-
expected_path = "/#{expected_path}" unless expected_path.first ==
|
87
|
+
expected_path = "/#{expected_path}" unless expected_path.first == "/"
|
86
88
|
end
|
87
89
|
# Load routes.rb if it hasn't been loaded.
|
88
90
|
|
89
|
-
|
90
|
-
|
91
|
+
options = options.clone
|
92
|
+
generated_path, query_string_keys = @routes.generate_extras(options, defaults)
|
93
|
+
found_extras = options.reject { |k, _| ! query_string_keys.include? k }
|
91
94
|
|
92
95
|
msg = message || sprintf("found extras <%s>, not <%s>", found_extras, extras)
|
93
96
|
assert_equal(extras, found_extras, msg)
|
@@ -104,21 +107,21 @@ module ActionDispatch
|
|
104
107
|
# The +extras+ hash allows you to specify options that would normally be provided as a query string to the action. The
|
105
108
|
# +message+ parameter allows you to specify a custom error message to display upon failure.
|
106
109
|
#
|
107
|
-
# #
|
110
|
+
# # Asserts a basic route: a controller with the default action (index)
|
108
111
|
# assert_routing '/home', controller: 'home', action: 'index'
|
109
112
|
#
|
110
113
|
# # Test a route generated with a specific controller, action, and parameter (id)
|
111
114
|
# assert_routing '/entries/show/23', controller: 'entries', action: 'show', id: 23
|
112
115
|
#
|
113
|
-
# #
|
116
|
+
# # Asserts a basic route (controller + default action), with an error message if it fails
|
114
117
|
# assert_routing '/store', { controller: 'store', action: 'index' }, {}, {}, 'Route for store index not generated properly'
|
115
118
|
#
|
116
119
|
# # Tests a route, providing a defaults hash
|
117
120
|
# assert_routing 'controller/action/9', {id: "9", item: "square"}, {controller: "controller", action: "action"}, {}, {item: "square"}
|
118
121
|
#
|
119
|
-
# # Tests a route with
|
122
|
+
# # Tests a route with an HTTP method
|
120
123
|
# assert_routing({ method: 'put', path: '/product/321' }, { controller: "product", action: "update", id: "321" })
|
121
|
-
def assert_routing(path, options, defaults={}, extras={}, message=nil)
|
124
|
+
def assert_routing(path, options, defaults = {}, extras = {}, message = nil)
|
122
125
|
assert_recognizes(options, path, extras, message)
|
123
126
|
|
124
127
|
controller, default_controller = options[:controller], defaults[:controller]
|
@@ -126,13 +129,12 @@ module ActionDispatch
|
|
126
129
|
options[:controller] = "/#{controller}"
|
127
130
|
end
|
128
131
|
|
129
|
-
generate_options = options.dup.delete_if{ |k, _| defaults.key?(k) }
|
132
|
+
generate_options = options.dup.delete_if { |k, _| defaults.key?(k) }
|
130
133
|
assert_generates(path.is_a?(Hash) ? path[:path] : path, generate_options, defaults, extras, message)
|
131
134
|
end
|
132
135
|
|
133
136
|
# A helper to make it easier to test different route configurations.
|
134
|
-
# This method temporarily replaces @routes
|
135
|
-
# with a new RouteSet instance.
|
137
|
+
# This method temporarily replaces @routes with a new RouteSet instance.
|
136
138
|
#
|
137
139
|
# The new instance is yielded to the passed block. Typically the block
|
138
140
|
# will create some routes using <tt>set.draw { match ... }</tt>:
|
@@ -150,9 +152,12 @@ module ActionDispatch
|
|
150
152
|
old_controller, @controller = @controller, @controller.clone
|
151
153
|
_routes = @routes
|
152
154
|
|
153
|
-
@controller.singleton_class.
|
154
|
-
|
155
|
-
|
155
|
+
@controller.singleton_class.include(_routes.url_helpers)
|
156
|
+
|
157
|
+
if @controller.respond_to? :view_context_class
|
158
|
+
@controller.view_context_class = Class.new(@controller.view_context_class) do
|
159
|
+
include _routes.url_helpers
|
160
|
+
end
|
156
161
|
end
|
157
162
|
end
|
158
163
|
yield @routes
|
@@ -182,8 +187,7 @@ module ActionDispatch
|
|
182
187
|
method = :get
|
183
188
|
end
|
184
189
|
|
185
|
-
|
186
|
-
request = ActionController::TestRequest.new
|
190
|
+
request = ActionController::TestRequest.create @controller.class
|
187
191
|
|
188
192
|
if path =~ %r{://}
|
189
193
|
fail_on(URI::InvalidURIError, msg) do
|
@@ -201,7 +205,7 @@ module ActionDispatch
|
|
201
205
|
request.request_method = method if method
|
202
206
|
|
203
207
|
params = fail_on(ActionController::RoutingError, msg) do
|
204
|
-
@routes.recognize_path(path,
|
208
|
+
@routes.recognize_path(path, method: method, extras: extras)
|
205
209
|
end
|
206
210
|
request.path_parameters = params.with_indifferent_access
|
207
211
|
|