diff --git a/lib/shoulda/matchers/action_controller/route_matcher.rb b/lib/shoulda/matchers/action_controller/route_matcher.rb index df1e4c086..a3f26d93b 100644 --- a/lib/shoulda/matchers/action_controller/route_matcher.rb +++ b/lib/shoulda/matchers/action_controller/route_matcher.rb @@ -79,6 +79,10 @@ module ActionController # # route(:get, '/posts/1').to('posts#show', id: 1) # + # You may also specify special parameters such as `:format`: + # + # route(:get, '/posts').to('posts#index', format: :json) + # # @return [RouteMatcher] # def route(method, path) diff --git a/lib/shoulda/matchers/action_controller/route_params.rb b/lib/shoulda/matchers/action_controller/route_params.rb index a1cd5e65e..0ede628b0 100644 --- a/lib/shoulda/matchers/action_controller/route_params.rb +++ b/lib/shoulda/matchers/action_controller/route_params.rb @@ -3,6 +3,8 @@ module Matchers module ActionController # @private class RouteParams + PARAMS_TO_SYMBOLIZE = %i{ format } + def initialize(args) @args = args end @@ -26,17 +28,24 @@ def controller_and_action_given_as_string? def extract_params_from_string controller, action = args[0].split('#') params = (args[1] || {}).merge(controller: controller, action: action) - stringify_values(params) + normalize_values(params) end def stringify_params - stringify_values(args[0]) + normalize_values(args[0]) end - def stringify_values(hash) - hash.inject({}) do |hash_copy, (key, value)| - hash_copy[key] = stringify(value) - hash_copy + def normalize_values(hash) + hash.each_with_object({}) do |(key, value), hash_copy| + hash_copy[key] = symbolize_or_stringify(key, value) + end + end + + def symbolize_or_stringify(key, value) + if key.in?(PARAMS_TO_SYMBOLIZE) + value.to_sym + else + stringify(value) end end diff --git a/spec/unit/shoulda/matchers/action_controller/route_matcher_spec.rb b/spec/unit/shoulda/matchers/action_controller/route_matcher_spec.rb index 980f770f9..bc413f37e 100644 --- a/spec/unit/shoulda/matchers/action_controller/route_matcher_spec.rb +++ b/spec/unit/shoulda/matchers/action_controller/route_matcher_spec.rb @@ -48,6 +48,26 @@ to(action: 'show', some: 'other', params: 'here') end end + + context 'when route has a default format' do + it 'accepts' do + expect(controller_with_defined_routes). + to route(:post, "/#{controller_path}"). + to(action: 'create', format: 'json') + end + + it 'accepts when format is specified as a symbol' do + expect(controller_with_defined_routes). + to route(:post, "/#{controller_path}"). + to(action: 'create', format: :json) + end + + it 'rejects when format is unspecified' do + expect(controller_with_defined_routes). + not_to route(:post, "/#{controller_path}"). + to(action: 'create') + end + end end context 'when controller and action are specified as a joined string' do @@ -64,6 +84,20 @@ to("#{controller_path}#show", id: 1) end end + + context 'when route has the format' do + it 'accepts' do + expect(controller_with_defined_routes). + to route(:post, "/#{controller_path}"). + to("#{controller_path}#create", format: 'json') + end + + it 'rejects when format is unspecified' do + expect(controller_with_defined_routes). + not_to route(:post, "/#{controller_path}"). + to(action: 'create') + end + end end def controller_with_defined_routes @@ -76,6 +110,9 @@ def controller_with_defined_routes define_routes do get "/#{_controller_path}", to: "#{_controller_path}#index" get "/#{_controller_path}/:id", to: "#{_controller_path}#show" + post "/#{_controller_path}", + to: "#{_controller_path}#create", + defaults: { format: :json } end controller