actionpack 7.1.3 → 7.2.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +82 -501
- 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 +15 -7
- 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 +198 -126
- 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 +123 -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 +210 -205
- 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 +86 -60
- 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 +18 -9
- data/lib/action_dispatch/http/filter_redirect.rb +22 -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 +31 -24
- 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 -44
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +94 -75
- data/lib/action_dispatch/http/response.rb +73 -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 +671 -636
- 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 +39 -16
@@ -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
|