actionpack 7.1.3.2 → 7.2.0.beta1
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 +4 -4
- data/CHANGELOG.md +70 -530
- data/lib/abstract_controller/asset_paths.rb +2 -0
- data/lib/abstract_controller/base.rb +102 -98
- data/lib/abstract_controller/caching/fragments.rb +50 -53
- data/lib/abstract_controller/caching.rb +2 -0
- data/lib/abstract_controller/callbacks.rb +66 -64
- data/lib/abstract_controller/collector.rb +6 -6
- data/lib/abstract_controller/deprecator.rb +2 -0
- data/lib/abstract_controller/error.rb +2 -0
- data/lib/abstract_controller/helpers.rb +70 -85
- data/lib/abstract_controller/logger.rb +2 -0
- data/lib/abstract_controller/railties/routes_helpers.rb +2 -0
- data/lib/abstract_controller/rendering.rb +13 -12
- data/lib/abstract_controller/translation.rb +11 -10
- data/lib/abstract_controller/url_for.rb +8 -6
- data/lib/abstract_controller.rb +2 -0
- data/lib/action_controller/api/api_rendering.rb +2 -0
- data/lib/action_controller/api.rb +74 -72
- data/lib/action_controller/base.rb +155 -117
- data/lib/action_controller/caching.rb +15 -12
- data/lib/action_controller/deprecator.rb +2 -0
- data/lib/action_controller/form_builder.rb +20 -17
- data/lib/action_controller/log_subscriber.rb +3 -1
- data/lib/action_controller/metal/allow_browser.rb +119 -0
- data/lib/action_controller/metal/basic_implicit_render.rb +2 -0
- data/lib/action_controller/metal/conditional_get.rb +188 -174
- data/lib/action_controller/metal/content_security_policy.rb +25 -24
- data/lib/action_controller/metal/cookies.rb +4 -2
- data/lib/action_controller/metal/data_streaming.rb +64 -55
- data/lib/action_controller/metal/default_headers.rb +5 -3
- data/lib/action_controller/metal/etag_with_flash.rb +3 -1
- data/lib/action_controller/metal/etag_with_template_digest.rb +17 -15
- data/lib/action_controller/metal/exceptions.rb +11 -9
- data/lib/action_controller/metal/flash.rb +12 -10
- data/lib/action_controller/metal/head.rb +12 -10
- data/lib/action_controller/metal/helpers.rb +63 -55
- data/lib/action_controller/metal/http_authentication.rb +209 -201
- data/lib/action_controller/metal/implicit_render.rb +17 -15
- data/lib/action_controller/metal/instrumentation.rb +15 -12
- data/lib/action_controller/metal/live.rb +113 -107
- data/lib/action_controller/metal/logging.rb +6 -4
- data/lib/action_controller/metal/mime_responds.rb +151 -142
- data/lib/action_controller/metal/parameter_encoding.rb +34 -32
- data/lib/action_controller/metal/params_wrapper.rb +57 -59
- data/lib/action_controller/metal/permissions_policy.rb +13 -12
- data/lib/action_controller/metal/rate_limiting.rb +62 -0
- data/lib/action_controller/metal/redirecting.rb +108 -82
- data/lib/action_controller/metal/renderers.rb +50 -49
- data/lib/action_controller/metal/rendering.rb +103 -75
- data/lib/action_controller/metal/request_forgery_protection.rb +162 -133
- data/lib/action_controller/metal/rescue.rb +11 -9
- data/lib/action_controller/metal/streaming.rb +138 -136
- data/lib/action_controller/metal/strong_parameters.rb +525 -480
- data/lib/action_controller/metal/testing.rb +2 -0
- data/lib/action_controller/metal/url_for.rb +17 -15
- data/lib/action_controller/metal.rb +58 -57
- data/lib/action_controller/railtie.rb +3 -0
- data/lib/action_controller/railties/helpers.rb +2 -0
- data/lib/action_controller/renderer.rb +42 -36
- data/lib/action_controller/template_assertions.rb +4 -2
- data/lib/action_controller/test_case.rb +146 -126
- data/lib/action_controller.rb +10 -3
- data/lib/action_dispatch/constants.rb +2 -0
- data/lib/action_dispatch/deprecator.rb +2 -0
- data/lib/action_dispatch/http/cache.rb +27 -26
- data/lib/action_dispatch/http/content_disposition.rb +2 -0
- data/lib/action_dispatch/http/content_security_policy.rb +44 -38
- data/lib/action_dispatch/http/filter_parameters.rb +9 -5
- data/lib/action_dispatch/http/filter_redirect.rb +15 -1
- data/lib/action_dispatch/http/headers.rb +22 -22
- data/lib/action_dispatch/http/mime_negotiation.rb +30 -41
- data/lib/action_dispatch/http/mime_type.rb +29 -22
- data/lib/action_dispatch/http/mime_types.rb +2 -0
- data/lib/action_dispatch/http/parameters.rb +11 -9
- data/lib/action_dispatch/http/permissions_policy.rb +20 -37
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +71 -71
- data/lib/action_dispatch/http/response.rb +61 -61
- data/lib/action_dispatch/http/upload.rb +18 -16
- data/lib/action_dispatch/http/url.rb +75 -73
- data/lib/action_dispatch/journey/formatter.rb +13 -6
- data/lib/action_dispatch/journey/gtg/builder.rb +4 -3
- data/lib/action_dispatch/journey/gtg/simulator.rb +2 -0
- data/lib/action_dispatch/journey/gtg/transition_table.rb +10 -8
- data/lib/action_dispatch/journey/nfa/dot.rb +2 -0
- data/lib/action_dispatch/journey/nodes/node.rb +6 -5
- data/lib/action_dispatch/journey/parser.rb +4 -3
- data/lib/action_dispatch/journey/parser_extras.rb +2 -0
- data/lib/action_dispatch/journey/path/pattern.rb +4 -1
- data/lib/action_dispatch/journey/route.rb +9 -7
- data/lib/action_dispatch/journey/router/utils.rb +16 -15
- data/lib/action_dispatch/journey/router.rb +4 -2
- data/lib/action_dispatch/journey/routes.rb +4 -2
- data/lib/action_dispatch/journey/scanner.rb +4 -2
- data/lib/action_dispatch/journey/visitors.rb +2 -0
- data/lib/action_dispatch/journey.rb +2 -0
- data/lib/action_dispatch/log_subscriber.rb +2 -0
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +2 -0
- data/lib/action_dispatch/middleware/assume_ssl.rb +8 -5
- data/lib/action_dispatch/middleware/callbacks.rb +3 -1
- data/lib/action_dispatch/middleware/cookies.rb +119 -104
- data/lib/action_dispatch/middleware/debug_exceptions.rb +13 -5
- data/lib/action_dispatch/middleware/debug_locks.rb +15 -13
- data/lib/action_dispatch/middleware/debug_view.rb +2 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +6 -11
- data/lib/action_dispatch/middleware/executor.rb +8 -0
- data/lib/action_dispatch/middleware/flash.rb +63 -51
- data/lib/action_dispatch/middleware/host_authorization.rb +17 -15
- data/lib/action_dispatch/middleware/public_exceptions.rb +8 -6
- data/lib/action_dispatch/middleware/reloader.rb +5 -3
- data/lib/action_dispatch/middleware/remote_ip.rb +77 -72
- data/lib/action_dispatch/middleware/request_id.rb +14 -9
- data/lib/action_dispatch/middleware/server_timing.rb +4 -2
- data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -0
- data/lib/action_dispatch/middleware/session/cache_store.rb +13 -8
- data/lib/action_dispatch/middleware/session/cookie_store.rb +27 -26
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +7 -3
- data/lib/action_dispatch/middleware/show_exceptions.rb +31 -21
- data/lib/action_dispatch/middleware/ssl.rb +43 -40
- data/lib/action_dispatch/middleware/stack.rb +11 -10
- data/lib/action_dispatch/middleware/static.rb +33 -31
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +1 -1
- data/lib/action_dispatch/railtie.rb +2 -4
- data/lib/action_dispatch/request/session.rb +23 -21
- data/lib/action_dispatch/request/utils.rb +2 -0
- data/lib/action_dispatch/routing/endpoint.rb +2 -0
- data/lib/action_dispatch/routing/inspector.rb +5 -3
- data/lib/action_dispatch/routing/mapper.rb +670 -635
- data/lib/action_dispatch/routing/polymorphic_routes.rb +69 -62
- data/lib/action_dispatch/routing/redirection.rb +37 -32
- data/lib/action_dispatch/routing/route_set.rb +59 -45
- data/lib/action_dispatch/routing/routes_proxy.rb +6 -4
- data/lib/action_dispatch/routing/url_for.rb +130 -125
- data/lib/action_dispatch/routing.rb +150 -148
- data/lib/action_dispatch/system_test_case.rb +91 -81
- data/lib/action_dispatch/system_testing/browser.rb +10 -3
- data/lib/action_dispatch/system_testing/driver.rb +3 -1
- data/lib/action_dispatch/system_testing/server.rb +2 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +32 -21
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +2 -0
- data/lib/action_dispatch/testing/assertion_response.rb +8 -6
- data/lib/action_dispatch/testing/assertions/response.rb +26 -23
- data/lib/action_dispatch/testing/assertions/routing.rb +153 -84
- data/lib/action_dispatch/testing/assertions.rb +2 -0
- data/lib/action_dispatch/testing/integration.rb +223 -222
- data/lib/action_dispatch/testing/request_encoder.rb +2 -0
- data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
- data/lib/action_dispatch/testing/test_process.rb +12 -8
- data/lib/action_dispatch/testing/test_request.rb +3 -1
- data/lib/action_dispatch/testing/test_response.rb +27 -26
- data/lib/action_dispatch.rb +22 -28
- data/lib/action_pack/gem_version.rb +6 -4
- data/lib/action_pack/version.rb +3 -1
- data/lib/action_pack.rb +17 -16
- metadata +30 -13
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :markup: markdown
|
4
|
+
|
3
5
|
module ActionDispatch
|
4
6
|
module SystemTesting
|
5
7
|
class Browser # :nodoc:
|
@@ -35,8 +37,8 @@ module ActionDispatch
|
|
35
37
|
yield options if block_given?
|
36
38
|
end
|
37
39
|
|
38
|
-
# driver_path is lazily initialized by default. Eagerly set it to
|
39
|
-
#
|
40
|
+
# driver_path is lazily initialized by default. Eagerly set it to avoid race
|
41
|
+
# conditions when using parallel tests.
|
40
42
|
def preload
|
41
43
|
case type
|
42
44
|
when :chrome
|
@@ -70,7 +72,12 @@ module ActionDispatch
|
|
70
72
|
end
|
71
73
|
|
72
74
|
def resolve_driver_path(namespace)
|
73
|
-
|
75
|
+
# The path method has been deprecated in 4.20.0
|
76
|
+
if Gem::Version.new(::Selenium::WebDriver::VERSION) >= Gem::Version.new("4.20.0")
|
77
|
+
namespace::Service.driver_path = ::Selenium::WebDriver::DriverFinder.new(options, namespace::Service.new).driver_path
|
78
|
+
else
|
79
|
+
namespace::Service.driver_path = ::Selenium::WebDriver::DriverFinder.path(options, namespace::Service)
|
80
|
+
end
|
74
81
|
end
|
75
82
|
end
|
76
83
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :markup: markdown
|
4
|
+
|
3
5
|
module ActionDispatch
|
4
6
|
module SystemTesting
|
5
7
|
class Driver # :nodoc:
|
@@ -16,7 +18,7 @@ module ActionDispatch
|
|
16
18
|
gem "selenium-webdriver", ">= 4.0.0"
|
17
19
|
require "selenium/webdriver"
|
18
20
|
@browser = Browser.new(options[:using])
|
19
|
-
@browser.preload
|
21
|
+
@browser.preload unless @options[:browser] == :remote
|
20
22
|
else
|
21
23
|
@browser = nil
|
22
24
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :markup: markdown
|
4
|
+
|
3
5
|
module ActionDispatch
|
4
6
|
module SystemTesting
|
5
7
|
module TestHelpers
|
@@ -7,27 +9,35 @@ module ActionDispatch
|
|
7
9
|
module ScreenshotHelper
|
8
10
|
# Takes a screenshot of the current page in the browser.
|
9
11
|
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
# automating visual testing. You can take multiple screenshots per test
|
13
|
-
#
|
14
|
-
#
|
12
|
+
# `take_screenshot` can be used at any point in your system tests to take a
|
13
|
+
# screenshot of the current state. This can be useful for debugging or
|
14
|
+
# automating visual testing. You can take multiple screenshots per test to
|
15
|
+
# investigate changes at different points during your test. These will be named
|
16
|
+
# with a sequential prefix (or 'failed' for failing tests)
|
17
|
+
#
|
18
|
+
# The default screenshots directory is `tmp/screenshots` but you can set a
|
19
|
+
# different one with `Capybara.save_path`
|
20
|
+
#
|
21
|
+
# You can use the `html` argument or set the
|
22
|
+
# `RAILS_SYSTEM_TESTING_SCREENSHOT_HTML` environment variable to save the HTML
|
23
|
+
# from the page that is being screenshotted so you can investigate the elements
|
24
|
+
# on the page at the time of the screenshot
|
25
|
+
#
|
26
|
+
# You can use the `screenshot` argument or set the
|
27
|
+
# `RAILS_SYSTEM_TESTING_SCREENSHOT` environment variable to control the output.
|
28
|
+
# Possible values are:
|
29
|
+
# `simple` (default)
|
30
|
+
# : Only displays the screenshot path. This is the default value.
|
31
|
+
#
|
32
|
+
# `inline`
|
33
|
+
# : Display the screenshot in the terminal using the iTerm image protocol
|
34
|
+
# (https://iterm2.com/documentation-images.html).
|
15
35
|
#
|
16
|
-
#
|
17
|
-
#
|
36
|
+
# `artifact`
|
37
|
+
# : Display the screenshot in the terminal, using the terminal artifact
|
38
|
+
# format (https://buildkite.github.io/terminal-to-html/inline-images/).
|
18
39
|
#
|
19
|
-
# You can use the +html+ argument or set the +RAILS_SYSTEM_TESTING_SCREENSHOT_HTML+
|
20
|
-
# environment variable to save the HTML from the page that is being screenshotted
|
21
|
-
# so you can investigate the elements on the page at the time of the screenshot
|
22
40
|
#
|
23
|
-
# You can use the +screenshot+ argument or set the +RAILS_SYSTEM_TESTING_SCREENSHOT+
|
24
|
-
# environment variable to control the output. Possible values are:
|
25
|
-
# * [+simple+ (default)] Only displays the screenshot path.
|
26
|
-
# This is the default value.
|
27
|
-
# * [+inline+] Display the screenshot in the terminal using the
|
28
|
-
# iTerm image protocol (https://iterm2.com/documentation-images.html).
|
29
|
-
# * [+artifact+] Display the screenshot in the terminal, using the terminal
|
30
|
-
# artifact format (https://buildkite.github.io/terminal-to-html/inline-images/).
|
31
41
|
def take_screenshot(html: false, screenshot: nil)
|
32
42
|
showing_html = html || html_from_env?
|
33
43
|
|
@@ -37,10 +47,9 @@ module ActionDispatch
|
|
37
47
|
show display_image(html: showing_html, screenshot_output: screenshot)
|
38
48
|
end
|
39
49
|
|
40
|
-
# Takes a screenshot of the current page in the browser if the test
|
41
|
-
# failed.
|
50
|
+
# Takes a screenshot of the current page in the browser if the test failed.
|
42
51
|
#
|
43
|
-
#
|
52
|
+
# `take_failed_screenshot` is called during system test teardown.
|
44
53
|
def take_failed_screenshot
|
45
54
|
return unless failed? && supports_screenshot? && Capybara::Session.instance_created?
|
46
55
|
|
@@ -98,6 +107,7 @@ module ActionDispatch
|
|
98
107
|
"#{absolute_path}.html"
|
99
108
|
end
|
100
109
|
|
110
|
+
# rubocop:disable Lint/Debugger
|
101
111
|
def save_html
|
102
112
|
page.save_page(absolute_html_path)
|
103
113
|
end
|
@@ -105,6 +115,7 @@ module ActionDispatch
|
|
105
115
|
def save_image
|
106
116
|
page.save_screenshot(absolute_image_path)
|
107
117
|
end
|
118
|
+
# rubocop:enable Lint/Debugger
|
108
119
|
|
109
120
|
def output_type
|
110
121
|
# Environment variables have priority
|
@@ -1,9 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :markup: markdown
|
4
|
+
|
3
5
|
module ActionDispatch
|
4
|
-
# This is a class that abstracts away an asserted response. It purposely
|
5
|
-
#
|
6
|
-
#
|
6
|
+
# This is a class that abstracts away an asserted response. It purposely does
|
7
|
+
# not inherit from Response because it doesn't need it. That means it does not
|
8
|
+
# have headers or a body.
|
7
9
|
class AssertionResponse
|
8
10
|
attr_reader :code, :name
|
9
11
|
|
@@ -14,9 +16,9 @@ module ActionDispatch
|
|
14
16
|
error: "5XX"
|
15
17
|
}
|
16
18
|
|
17
|
-
# Accepts a specific response status code as an Integer (404) or String
|
18
|
-
#
|
19
|
-
#
|
19
|
+
# Accepts a specific response status code as an Integer (404) or String ('404')
|
20
|
+
# or a response status range as a Symbol pseudo-code (:success, indicating any
|
21
|
+
# 200-299 status code).
|
20
22
|
def initialize(code_or_name)
|
21
23
|
if code_or_name.is_a?(Symbol)
|
22
24
|
@name = code_or_name
|
@@ -1,8 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :markup: markdown
|
4
|
+
|
3
5
|
module ActionDispatch
|
4
6
|
module Assertions
|
5
|
-
# A small suite of assertions that test responses from
|
7
|
+
# A small suite of assertions that test responses from Rails applications.
|
6
8
|
module ResponseAssertions
|
7
9
|
RESPONSE_PREDICATES = { # :nodoc:
|
8
10
|
success: :successful?,
|
@@ -13,20 +15,21 @@ module ActionDispatch
|
|
13
15
|
|
14
16
|
# Asserts that the response is one of the following types:
|
15
17
|
#
|
16
|
-
# *
|
17
|
-
# *
|
18
|
-
# *
|
19
|
-
# *
|
18
|
+
# * `:success` - Status code was in the 200-299 range
|
19
|
+
# * `:redirect` - Status code was in the 300-399 range
|
20
|
+
# * `:missing` - Status code was 404
|
21
|
+
# * `:error` - Status code was in the 500-599 range
|
22
|
+
#
|
20
23
|
#
|
21
|
-
# You can also pass an explicit status number like
|
22
|
-
#
|
23
|
-
#
|
24
|
+
# You can also pass an explicit status number like `assert_response(501)` or its
|
25
|
+
# symbolic equivalent `assert_response(:not_implemented)`. See
|
26
|
+
# `Rack::Utils::SYMBOL_TO_STATUS_CODE` for a full list.
|
24
27
|
#
|
25
|
-
#
|
26
|
-
#
|
28
|
+
# # Asserts that the response was a redirection
|
29
|
+
# assert_response :redirect
|
27
30
|
#
|
28
|
-
#
|
29
|
-
#
|
31
|
+
# # Asserts that the response code was status code 401 (unauthorized)
|
32
|
+
# assert_response 401
|
30
33
|
def assert_response(type, message = nil)
|
31
34
|
message ||= generate_response_message(type)
|
32
35
|
|
@@ -39,21 +42,21 @@ module ActionDispatch
|
|
39
42
|
|
40
43
|
# Asserts that the response is a redirect to a URL matching the given options.
|
41
44
|
#
|
42
|
-
#
|
43
|
-
#
|
45
|
+
# # Asserts that the redirection was to the "index" action on the WeblogController
|
46
|
+
# assert_redirected_to controller: "weblog", action: "index"
|
44
47
|
#
|
45
|
-
#
|
46
|
-
#
|
48
|
+
# # Asserts that the redirection was to the named route login_url
|
49
|
+
# assert_redirected_to login_url
|
47
50
|
#
|
48
|
-
#
|
49
|
-
#
|
51
|
+
# # Asserts that the redirection was to the URL for @customer
|
52
|
+
# assert_redirected_to @customer
|
50
53
|
#
|
51
|
-
#
|
52
|
-
#
|
54
|
+
# # Asserts that the redirection matches the regular expression
|
55
|
+
# assert_redirected_to %r(\Ahttp://example.org)
|
53
56
|
#
|
54
|
-
#
|
55
|
-
#
|
56
|
-
#
|
57
|
+
# # Asserts that the redirection has the HTTP status code 301 (Moved
|
58
|
+
# # Permanently).
|
59
|
+
# assert_redirected_to "/some/path", status: :moved_permanently
|
57
60
|
def assert_redirected_to(url_options = {}, options = {}, message = nil)
|
58
61
|
options, message = {}, options unless options.is_a?(Hash)
|
59
62
|
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :markup: markdown
|
4
|
+
|
3
5
|
require "uri"
|
4
6
|
require "active_support/core_ext/hash/indifferent_access"
|
5
7
|
require "active_support/core_ext/string/access"
|
@@ -7,23 +9,82 @@ require "action_controller/metal/exceptions"
|
|
7
9
|
|
8
10
|
module ActionDispatch
|
9
11
|
module Assertions
|
10
|
-
# Suite of assertions to test routes generated by
|
12
|
+
# Suite of assertions to test routes generated by Rails and the handling of
|
13
|
+
# requests made to them.
|
11
14
|
module RoutingAssertions
|
12
15
|
extend ActiveSupport::Concern
|
13
16
|
|
17
|
+
module WithIntegrationRouting # :nodoc:
|
18
|
+
extend ActiveSupport::Concern
|
19
|
+
|
20
|
+
module ClassMethods
|
21
|
+
def with_routing(&block)
|
22
|
+
old_routes = nil
|
23
|
+
old_integration_session = nil
|
24
|
+
|
25
|
+
setup do
|
26
|
+
old_routes = app.routes
|
27
|
+
old_integration_session = integration_session
|
28
|
+
create_routes(&block)
|
29
|
+
end
|
30
|
+
|
31
|
+
teardown do
|
32
|
+
reset_routes(old_routes, old_integration_session)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def with_routing(&block)
|
38
|
+
old_routes = app.routes
|
39
|
+
old_integration_session = integration_session
|
40
|
+
create_routes(&block)
|
41
|
+
ensure
|
42
|
+
reset_routes(old_routes, old_integration_session)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
def create_routes
|
47
|
+
app = self.app
|
48
|
+
routes = ActionDispatch::Routing::RouteSet.new
|
49
|
+
rack_app = app.config.middleware.build(routes)
|
50
|
+
https = integration_session.https?
|
51
|
+
host = integration_session.host
|
52
|
+
|
53
|
+
app.instance_variable_set(:@routes, routes)
|
54
|
+
app.instance_variable_set(:@app, rack_app)
|
55
|
+
@integration_session = Class.new(ActionDispatch::Integration::Session) do
|
56
|
+
include app.routes.url_helpers
|
57
|
+
include app.routes.mounted_helpers
|
58
|
+
end.new(app)
|
59
|
+
@integration_session.https! https
|
60
|
+
@integration_session.host! host
|
61
|
+
@routes = routes
|
62
|
+
|
63
|
+
yield routes
|
64
|
+
end
|
65
|
+
|
66
|
+
def reset_routes(old_routes, old_integration_session)
|
67
|
+
old_rack_app = app.config.middleware.build(old_routes)
|
68
|
+
|
69
|
+
app.instance_variable_set(:@routes, old_routes)
|
70
|
+
app.instance_variable_set(:@app, old_rack_app)
|
71
|
+
@integration_session = old_integration_session
|
72
|
+
@routes = old_routes
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
14
76
|
module ClassMethods
|
15
|
-
# A helper to make it easier to test different route configurations.
|
16
|
-
#
|
17
|
-
# before each test.
|
77
|
+
# A helper to make it easier to test different route configurations. This method
|
78
|
+
# temporarily replaces @routes with a new RouteSet instance before each test.
|
18
79
|
#
|
19
|
-
# The new instance is yielded to the passed block. Typically the block
|
20
|
-
#
|
80
|
+
# The new instance is yielded to the passed block. Typically the block will
|
81
|
+
# create some routes using `set.draw { match ... }`:
|
21
82
|
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
83
|
+
# with_routing do |set|
|
84
|
+
# set.draw do
|
85
|
+
# resources :users
|
86
|
+
# end
|
25
87
|
# end
|
26
|
-
# end
|
27
88
|
#
|
28
89
|
def with_routing(&block)
|
29
90
|
old_routes, old_controller = nil
|
@@ -44,36 +105,62 @@ module ActionDispatch
|
|
44
105
|
super
|
45
106
|
end
|
46
107
|
|
47
|
-
#
|
48
|
-
#
|
108
|
+
# A helper to make it easier to test different route configurations. This method
|
109
|
+
# temporarily replaces @routes with a new RouteSet instance.
|
110
|
+
#
|
111
|
+
# The new instance is yielded to the passed block. Typically the block will
|
112
|
+
# create some routes using `set.draw { match ... }`:
|
113
|
+
#
|
114
|
+
# with_routing do |set|
|
115
|
+
# set.draw do
|
116
|
+
# resources :users
|
117
|
+
# end
|
118
|
+
# assert_equal "/users", users_path
|
119
|
+
# end
|
120
|
+
#
|
121
|
+
def with_routing(&block)
|
122
|
+
old_routes, old_controller = @routes, @controller
|
123
|
+
create_routes(&block)
|
124
|
+
ensure
|
125
|
+
reset_routes(old_routes, old_controller)
|
126
|
+
end
|
127
|
+
|
128
|
+
# Asserts that the routing of the given `path` was handled correctly and that
|
129
|
+
# the parsed options (given in the `expected_options` hash) match `path`.
|
130
|
+
# Basically, it asserts that Rails recognizes the route given by
|
131
|
+
# `expected_options`.
|
49
132
|
#
|
50
|
-
# Pass a hash in the second argument (
|
51
|
-
# requiring a specific HTTP method. The hash should
|
52
|
-
#
|
133
|
+
# Pass a hash in the second argument (`path`) to specify the request method.
|
134
|
+
# This is useful for routes requiring a specific HTTP method. The hash should
|
135
|
+
# contain a `:path` with the incoming request path and a `:method` containing
|
136
|
+
# the required HTTP verb.
|
53
137
|
#
|
54
|
-
#
|
55
|
-
#
|
138
|
+
# # Asserts that POSTing to /items will call the create action on ItemsController
|
139
|
+
# assert_recognizes({controller: 'items', action: 'create'}, {path: 'items', method: :post})
|
56
140
|
#
|
57
|
-
# You can also pass in
|
58
|
-
#
|
59
|
-
#
|
141
|
+
# You can also pass in `extras` with a hash containing URL parameters that would
|
142
|
+
# normally be in the query string. This can be used to assert that values in the
|
143
|
+
# query string will end up in the params hash correctly. To test query strings
|
144
|
+
# you must use the extras argument because appending the query string on the
|
145
|
+
# path directly will not work. For example:
|
60
146
|
#
|
61
|
-
#
|
62
|
-
#
|
147
|
+
# # Asserts that a path of '/items/list/1?view=print' returns the correct options
|
148
|
+
# assert_recognizes({controller: 'items', action: 'list', id: '1', view: 'print'}, 'items/list/1', { view: "print" })
|
63
149
|
#
|
64
|
-
# The
|
150
|
+
# The `message` parameter allows you to pass in an error message that is
|
151
|
+
# displayed upon failure.
|
65
152
|
#
|
66
|
-
#
|
67
|
-
#
|
153
|
+
# # Check the default route (i.e., the index action)
|
154
|
+
# assert_recognizes({controller: 'items', action: 'index'}, 'items')
|
68
155
|
#
|
69
|
-
#
|
70
|
-
#
|
156
|
+
# # Test a specific action
|
157
|
+
# assert_recognizes({controller: 'items', action: 'list'}, 'items/list')
|
71
158
|
#
|
72
|
-
#
|
73
|
-
#
|
159
|
+
# # Test an action with a parameter
|
160
|
+
# assert_recognizes({controller: 'items', action: 'destroy', id: '1'}, 'items/destroy/1')
|
74
161
|
#
|
75
|
-
#
|
76
|
-
#
|
162
|
+
# # Test a custom route
|
163
|
+
# assert_recognizes({controller: 'items', action: 'show', id: '1'}, 'view/item1')
|
77
164
|
def assert_recognizes(expected_options, path, extras = {}, msg = nil)
|
78
165
|
if path.is_a?(Hash) && path[:method].to_s == "all"
|
79
166
|
[:get, :post, :put, :delete].each do |method|
|
@@ -95,23 +182,25 @@ module ActionDispatch
|
|
95
182
|
end
|
96
183
|
end
|
97
184
|
|
98
|
-
# Asserts that the provided options can be used to generate the provided path.
|
99
|
-
#
|
100
|
-
#
|
185
|
+
# Asserts that the provided options can be used to generate the provided path.
|
186
|
+
# This is the inverse of `assert_recognizes`. The `extras` parameter is used to
|
187
|
+
# tell the request the names and values of additional request parameters that
|
188
|
+
# would be in a query string. The `message` parameter allows you to specify a
|
189
|
+
# custom error message for assertion failures.
|
101
190
|
#
|
102
|
-
# The
|
191
|
+
# The `defaults` parameter is unused.
|
103
192
|
#
|
104
|
-
#
|
105
|
-
#
|
193
|
+
# # Asserts that the default action is generated for a route with no action
|
194
|
+
# assert_generates "/items", controller: "items", action: "index"
|
106
195
|
#
|
107
|
-
#
|
108
|
-
#
|
196
|
+
# # Tests that the list action is properly routed
|
197
|
+
# assert_generates "/items/list", controller: "items", action: "list"
|
109
198
|
#
|
110
|
-
#
|
111
|
-
#
|
199
|
+
# # Tests the generation of a route with a parameter
|
200
|
+
# assert_generates "/items/list/1", { controller: "items", action: "list", id: "1" }
|
112
201
|
#
|
113
|
-
#
|
114
|
-
#
|
202
|
+
# # Asserts that the generated route gives us our custom route
|
203
|
+
# assert_generates "changesets/12", { controller: 'scm', action: 'show_diff', revision: "12" }
|
115
204
|
def assert_generates(expected_path, options, defaults = {}, extras = {}, message = nil)
|
116
205
|
if expected_path.include?("://")
|
117
206
|
fail_on(URI::InvalidURIError, message) do
|
@@ -134,27 +223,28 @@ module ActionDispatch
|
|
134
223
|
assert_equal(expected_path, generated_path, msg)
|
135
224
|
end
|
136
225
|
|
137
|
-
# Asserts that path and options match both ways; in other words, it verifies
|
138
|
-
#
|
139
|
-
# and
|
226
|
+
# Asserts that path and options match both ways; in other words, it verifies
|
227
|
+
# that `path` generates `options` and then that `options` generates `path`. This
|
228
|
+
# essentially combines `assert_recognizes` and `assert_generates` into one step.
|
140
229
|
#
|
141
|
-
# The
|
142
|
-
#
|
230
|
+
# The `extras` hash allows you to specify options that would normally be
|
231
|
+
# provided as a query string to the action. The `message` parameter allows you
|
232
|
+
# to specify a custom error message to display upon failure.
|
143
233
|
#
|
144
|
-
#
|
145
|
-
#
|
234
|
+
# # Asserts a basic route: a controller with the default action (index)
|
235
|
+
# assert_routing '/home', controller: 'home', action: 'index'
|
146
236
|
#
|
147
|
-
#
|
148
|
-
#
|
237
|
+
# # Test a route generated with a specific controller, action, and parameter (id)
|
238
|
+
# assert_routing '/entries/show/23', controller: 'entries', action: 'show', id: 23
|
149
239
|
#
|
150
|
-
#
|
151
|
-
#
|
240
|
+
# # Asserts a basic route (controller + default action), with an error message if it fails
|
241
|
+
# assert_routing '/store', { controller: 'store', action: 'index' }, {}, {}, 'Route for store index not generated properly'
|
152
242
|
#
|
153
|
-
#
|
154
|
-
#
|
243
|
+
# # Tests a route, providing a defaults hash
|
244
|
+
# assert_routing 'controller/action/9', {id: "9", item: "square"}, {controller: "controller", action: "action"}, {}, {item: "square"}
|
155
245
|
#
|
156
|
-
#
|
157
|
-
#
|
246
|
+
# # Tests a route with an HTTP method
|
247
|
+
# assert_routing({ method: 'put', path: '/product/321' }, { controller: "product", action: "update", id: "321" })
|
158
248
|
def assert_routing(path, options, defaults = {}, extras = {}, message = nil)
|
159
249
|
assert_recognizes(options, path, extras, message)
|
160
250
|
|
@@ -167,40 +257,19 @@ module ActionDispatch
|
|
167
257
|
assert_generates(path.is_a?(Hash) ? path[:path] : path, generate_options, defaults, extras, message)
|
168
258
|
end
|
169
259
|
|
170
|
-
# A helper to make it easier to test different route configurations.
|
171
|
-
# This method temporarily replaces @routes with a new RouteSet instance.
|
172
|
-
#
|
173
|
-
# The new instance is yielded to the passed block. Typically the block
|
174
|
-
# will create some routes using <tt>set.draw { match ... }</tt>:
|
175
|
-
#
|
176
|
-
# with_routing do |set|
|
177
|
-
# set.draw do
|
178
|
-
# resources :users
|
179
|
-
# end
|
180
|
-
# assert_equal "/users", users_path
|
181
|
-
# end
|
182
|
-
#
|
183
|
-
def with_routing(&block)
|
184
|
-
old_routes, old_controller = @routes, @controller
|
185
|
-
create_routes(&block)
|
186
|
-
ensure
|
187
|
-
reset_routes(old_routes, old_controller)
|
188
|
-
end
|
189
|
-
|
190
260
|
# ROUTES TODO: These assertions should really work in an integration context
|
191
|
-
def method_missing(selector,
|
192
|
-
if
|
193
|
-
@controller.public_send(selector,
|
261
|
+
def method_missing(selector, ...)
|
262
|
+
if @controller && @routes&.named_routes&.route_defined?(selector)
|
263
|
+
@controller.public_send(selector, ...)
|
194
264
|
else
|
195
265
|
super
|
196
266
|
end
|
197
267
|
end
|
198
|
-
ruby2_keywords(:method_missing)
|
199
268
|
|
200
269
|
private
|
201
270
|
def create_routes
|
202
271
|
@routes = ActionDispatch::Routing::RouteSet.new
|
203
|
-
if
|
272
|
+
if @controller
|
204
273
|
@controller = @controller.clone
|
205
274
|
_routes = @routes
|
206
275
|
|
@@ -224,7 +293,7 @@ module ActionDispatch
|
|
224
293
|
|
225
294
|
def reset_routes(old_routes, old_controller)
|
226
295
|
@routes = old_routes
|
227
|
-
if
|
296
|
+
if @controller
|
228
297
|
@controller = old_controller
|
229
298
|
end
|
230
299
|
end
|