root/trunk/actionpack/lib/action_controller/assertions/routing_assertions.rb
| Revision 8748, 7.8 kB (checked in by nzkoz, 10 months ago) |
|---|
| Line | |
|---|---|
| 1 | module ActionController |
| 2 | module Assertions |
| 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+. |
| 7 | # |
| 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. |
| 11 | # |
| 12 | # # assert that POSTing to /items will call the create action on ItemsController |
| 13 | # assert_recognizes({:controller => 'items', :action => 'create'}, {:path => 'items', :method => :post}) |
| 14 | # |
| 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: |
| 18 | # |
| 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" }) |
| 21 | # |
| 22 | # The +message+ parameter allows you to pass in an error message that is displayed upon failure. |
| 23 | # |
| 24 | # ==== Examples |
| 25 | # # Check the default route (i.e., the index action) |
| 26 | # assert_recognizes({:controller => 'items', :action => 'index'}, 'items') |
| 27 | # |
| 28 | # # Test a specific action |
| 29 | # assert_recognizes({:controller => 'items', :action => 'list'}, 'items/list') |
| 30 | # |
| 31 | # # Test an action with a parameter |
| 32 | # assert_recognizes({:controller => 'items', :action => 'destroy', :id => '1'}, 'items/destroy/1') |
| 33 | # |
| 34 | # # Test a custom route |
| 35 | # assert_recognizes({:controller => 'items', :action => 'show', :id => '1'}, 'view/item1') |
| 36 | # |
| 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) |
| 40 | if path.is_a? Hash |
| 41 | request_method = path[:method] |
| 42 | path = path[:path] |
| 43 | else |
| 44 | request_method = nil |
| 45 | end |
| 46 | |
| 47 | clean_backtrace do |
| 48 | ActionController::Routing::Routes.reload if ActionController::Routing::Routes.empty? |
| 49 | request = recognized_request_for(path, request_method) |
| 50 | |
| 51 | expected_options = expected_options.clone |
| 52 | extras.each_key { |key| expected_options.delete key } unless extras.nil? |
| 53 | |
| 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 } |
| 59 | end |
| 60 | end |
| 61 | |
| 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. |
| 65 | # |
| 66 | # The +defaults+ parameter is unused. |
| 67 | # |
| 68 | # ==== Examples |
| 69 | # # Asserts that the default action is generated for a route with no action |
| 70 | # assert_generates("/items", :controller => "items", :action => "index") |
| 71 | # |
| 72 | # # Tests that the list action is properly routed |
| 73 | # assert_generates("/items/list", :controller => "items", :action => "list") |
| 74 | # |
| 75 | # # Tests the generation of a route with a parameter |
| 76 | # assert_generates("/items/list/1", { :controller => "items", :action => "list", :id => "1" }) |
| 77 | # |
| 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) |
| 81 | clean_backtrace do |
| 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? |
| 85 | |
| 86 | generated_path, extra_keys = ActionController::Routing::Routes.generate_extras(options, defaults) |
| 87 | found_extras = options.reject {|k, v| ! extra_keys.include? k} |
| 88 | |
| 89 | msg = build_message(message, "found extras <?>, not <?>", found_extras, extras) |
| 90 | assert_block(msg) { found_extras == extras } |
| 91 | |
| 92 | msg = build_message(message, "The generated path <?> did not match <?>", generated_path, |
| 93 | expected_path) |
| 94 | assert_block(msg) { expected_path == generated_path } |
| 95 | end |
| 96 | end |
| 97 | |
| 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. |
| 101 | # |
| 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. |
| 104 | # |
| 105 | # ==== Examples |
| 106 | # # Assert a basic route: a controller with the default action (index) |
| 107 | # assert_routing('/home', :controller => 'home', :action => 'index') |
| 108 | # |
| 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) |
| 111 | # |
| 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') |
| 114 | # |
| 115 | # # Tests a route, providing a defaults hash |
| 116 | # assert_routing 'controller/action/9', {:id => "9", :item => "square"}, {:controller => "controller", :action => "action"}, {}, {:item => "square"} |
| 117 | # |
| 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) |
| 122 | |
| 123 | controller, default_controller = options[:controller], defaults[:controller] |
| 124 | if controller && controller.include?(?/) && default_controller && default_controller.include?(?/) |
| 125 | options[:controller] = "/#{controller}" |
| 126 | end |
| 127 | |
| 128 | assert_generates(path.is_a?(Hash) ? path[:path] : path, options, defaults, extras, message) |
| 129 | end |
| 130 | |
| 131 | private |
| 132 | # Recognizes the route for a given path. |
| 133 | def recognized_request_for(path, request_method = nil) |
| 134 | path = "/#{path}" unless path.first == '/' |
| 135 | |
| 136 | # Assume given controller |
| 137 | request = ActionController::TestRequest.new({}, {}, nil) |
| 138 | request.env["REQUEST_METHOD"] = request_method.to_s.upcase if request_method |
| 139 | request.path = path |
| 140 | |
| 141 | ActionController::Routing::Routes.recognize(request) |
| 142 | request |
| 143 | end |
| 144 | end |
| 145 | end |
| 146 | end |
Note: See TracBrowser for help on using the browser.