module Spec module Rails module Matchers class RedirectTo #:nodoc: def initialize(request, expected) @expected = expected @request = request end def matches?(response) @redirected = response.redirect? @actual = response.redirect_url return false unless @redirected if @expected.instance_of? Hash return false unless @actual =~ %r{^\w+://#{@request.host}} return false unless actual_redirect_to_valid_route return actual_hash == expected_hash else return @actual == expected_url end end def actual_hash hash_from_url @actual end def expected_hash hash_from_url expected_url end def actual_redirect_to_valid_route actual_hash end def hash_from_url(url) query_hash(url).merge(path_hash(url)).with_indifferent_access end def path_hash(url) path = url.sub(%r{^\w+://#{@request.host}(?::\d+)?}, "").split("?", 2)[0] ActionController::Routing::Routes.recognize_path path end def query_hash(url) query = url.split("?", 2)[1] || "" QueryParameterParser.parse_query_parameters(query, @request) end def expected_url case @expected when Hash return ActionController::UrlRewriter.new(@request, {}).rewrite(@expected) when :back return @request.env['HTTP_REFERER'] when %r{^\w+://.*} return @expected else return "http://#{@request.host}" + (@expected.split('')[0] == '/' ? '' : '/') + @expected end end def failure_message if @redirected return %Q{expected redirect to #{@expected.inspect}, got redirect to #{@actual.inspect}} else return %Q{expected redirect to #{@expected.inspect}, got no redirect} end end def negative_failure_message return %Q{expected not to be redirected to #{@expected.inspect}, but was} if @redirected end def description "redirect to #{@actual.inspect}" end class QueryParameterParser def self.parse_query_parameters(query, request) if defined?(CGIMethods) CGIMethods.parse_query_parameters(query) else request.class.parse_query_parameters(query) end end end end # :call-seq: # response.should redirect_to(url) # response.should redirect_to(:action => action_name) # response.should redirect_to(:controller => controller_name, :action => action_name) # response.should_not redirect_to(url) # response.should_not redirect_to(:action => action_name) # response.should_not redirect_to(:controller => controller_name, :action => action_name) # # Passes if the response is a redirect to the url, action or controller/action. # Useful in controller specs (integration or isolation mode). # # == Examples # # response.should redirect_to("path/to/action") # response.should redirect_to("http://test.host/path/to/action") # response.should redirect_to(:action => 'list') def redirect_to(opts) RedirectTo.new(request, opts) end end end end