1 module ActionController
3 # Suite of assertions to test routes generated by Rails and the handling of requests made to them.
4 module RoutingAssertions
5 # Asserts that the routing of the given +path+ was handled correctly and that the parsed options (given in the +expected_options+ hash)
6 # match +path+. Basically, it asserts that Rails recognizes the route given by +expected_options+.
8 # Pass a hash in the second argument (+path+) to specify the request method. This is useful for routes
9 # requiring a specific HTTP method. The hash should contain a :path with the incoming request path
10 # and a :method containing the required HTTP verb.
12 # # assert that POSTing to /items will call the create action on ItemsController
13 # assert_recognizes {:controller => 'items', :action => 'create'}, {:path => 'items', :method => :post}
15 # You can also pass in +extras+ with a hash containing URL parameters that would normally be in the query string. This can be used
16 # to assert that values in the query string string will end up in the params hash correctly. To test query strings you must use the
17 # extras argument, appending the query string on the path directly will not work. For example:
19 # # assert that a path of '/items/list/1?view=print' returns the correct options
20 # assert_recognizes {:controller => 'items', :action => 'list', :id => '1', :view => 'print'}, 'items/list/1', { :view => "print" }
22 # The +message+ parameter allows you to pass in an error message that is displayed upon failure.
25 # # Check the default route (i.e., the index action)
26 # assert_recognizes {:controller => 'items', :action => 'index'}, 'items'
28 # # Test a specific action
29 # assert_recognizes {:controller => 'items', :action => 'list'}, 'items/list'
31 # # Test an action with a parameter
32 # assert_recognizes {:controller => 'items', :action => 'destroy', :id => '1'}, 'items/destroy/1'
34 # # Test a custom route
35 # assert_recognizes {:controller => 'items', :action => 'show', :id => '1'}, 'view/item1'
37 # # Check a Simply RESTful generated route
38 # assert_recognizes list_items_url, 'items/list'
39 def assert_recognizes(expected_options
, path
, extras
={}, message
=nil)
41 request_method
= path
[:method]
48 ActionController
::Routing::Routes.reload
if ActionController
::Routing::Routes.empty
?
49 request
= recognized_request_for(path
, request_method
)
51 expected_options
= expected_options
.clone
52 extras
.each_key
{ |key
| expected_options
.delete key
} unless extras
.nil?
54 expected_options
.stringify_keys
!
55 routing_diff
= expected_options
.diff(request
.path_parameters
)
56 msg
= build_message(message
, "The recognized options <?> did not match <?>, difference: <?>",
57 request
.path_parameters
, expected_options
, expected_options
.diff(request
.path_parameters
))
58 assert_block(msg
) { request
.path_parameters
== expected_options
}
62 # Asserts that the provided options can be used to generate the provided path. This is the inverse of +assert_recognizes+.
63 # The +extras+ parameter is used to tell the request the names and values of additional request parameters that would be in
64 # a query string. The +message+ parameter allows you to specify a custom error message for assertion failures.
66 # The +defaults+ parameter is unused.
69 # # Asserts that the default action is generated for a route with no action
70 # assert_generates "/items", :controller => "items", :action => "index"
72 # # Tests that the list action is properly routed
73 # assert_generates "/items/list", :controller => "items", :action => "list"
75 # # Tests the generation of a route with a parameter
76 # assert_generates "/items/list/1", { :controller => "items", :action => "list", :id => "1" }
78 # # Asserts that the generated route gives us our custom route
79 # assert_generates "changesets/12", { :controller => 'scm', :action => 'show_diff', :revision => "12" }
80 def assert_generates(expected_path
, options
, defaults
={}, extras
= {}, message
=nil)
82 expected_path
= "/#{expected_path}" unless expected_path
[0] == ?/
83 # Load routes.rb if it hasn't been loaded.
84 ActionController
::Routing::Routes.reload
if ActionController
::Routing::Routes.empty
?
86 generated_path
, extra_keys
= ActionController
::Routing::Routes.generate_extras(options
, defaults
)
87 found_extras
= options
.reject
{|k
, v
| ! extra_keys
.include? k
}
89 msg
= build_message(message
, "found extras <?>, not <?>", found_extras
, extras
)
90 assert_block(msg
) { found_extras
== extras
}
92 msg
= build_message(message
, "The generated path <?> did not match <?>", generated_path
,
94 assert_block(msg
) { expected_path
== generated_path
}
98 # Asserts that path and options match both ways; in other words, it verifies that <tt>path</tt> generates
99 # <tt>options</tt> and then that <tt>options</tt> generates <tt>path</tt>. This essentially combines +assert_recognizes+
100 # and +assert_generates+ into one step.
102 # The +extras+ hash allows you to specify options that would normally be provided as a query string to the action. The
103 # +message+ parameter allows you to specify a custom error message to display upon failure.
106 # # Assert a basic route: a controller with the default action (index)
107 # assert_routing '/home', :controller => 'home', :action => 'index'
109 # # Test a route generated with a specific controller, action, and parameter (id)
110 # assert_routing '/entries/show/23', :controller => 'entries', :action => 'show', id => 23
112 # # Assert a basic route (controller + default action), with an error message if it fails
113 # assert_routing '/store', { :controller => 'store', :action => 'index' }, {}, {}, 'Route for store index not generated properly'
115 # # Tests a route, providing a defaults hash
116 # assert_routing 'controller/action/9', {:id => "9", :item => "square"}, {:controller => "controller", :action => "action"}, {}, {:item => "square"}
118 # # Tests a route with a HTTP method
119 # assert_routing { :method => 'put', :path => '/product/321' }, { :controller => "product", :action => "update", :id => "321" }
120 def assert_routing(path
, options
, defaults
={}, extras
={}, message
=nil)
121 assert_recognizes(options
, path
, extras
, message
)
123 controller
, default_controller
= options
[:controller], defaults
[:controller]
124 if controller
&& controller
.include?(?/) && default_controller && default_controller.include?(?/)
125 options
[:controller] = "/#{controller}"
128 assert_generates(path
.is_a
?(Hash
) ? path
[:path] : path
, options
, defaults
, extras
, message
)
132 # Recognizes the route for a given path.
133 def recognized_request_for(path
, request_method
= nil)
134 path
= "/#{path}" unless path
.first
== '/'
136 # Assume given controller
137 request
= ActionController
::TestRequest.new({}, {}, nil)
138 request
.env["REQUEST_METHOD"] = request_method
.to_s
.upcase
if request_method
141 ActionController
::Routing::Routes.recognize(request
)