Feb 14

refresh_to plugin rspec matcher

etienne @ 10:00 pm

We have been using the refresh_to plugin in one of our projects. For those who do not know, the refresh_to plugin adds a refresh_to method to the ActionController::Base which allows us to avoid the IE security warnings when moving from a secure SSL page to an insecure page.

We are using rspec for our testing and when I went to write some tests to test some code that uses the refresh_to method I found out that the standard redirect_to rspec matcher does not work with refresh_to. The same problem exist for the standard test method assert_response :redirect and assert_redirected_to my_url, but the plugin does supply replacement tests for these methods. The problem is that it does not supply a replacement for the rspec matcher so I had to write my own. 

# The standard rspec redirect_to matcher does not work with the refresh_to
# plugin methods, i.e. refresh_to and refresh_back_or_default.
# This is also the case with the with the standard Rails functional
# tests - assert_response :redirect and assert_redirected_to my_url.
# The plugin has replacement test methods for these but they do not
# have an rspec replacement for redirect_to so I’ve had to write my own.
#
module Spec
  module Rails
    module Matchers
     
      class RefreshTo  #:nodoc:

        def initialize(controller, expected)
          @expected = expected
          @controller = controller
        end

        def matches?(response)
          match_data = response.body.match(/<meta http-equiv="refresh" content="0;url=([\S]+)">/)
          return false if (!match_data)
          parts = match_data[1].split("http://test.host")
          @actual = parts.last
          return match()
        end
         
        def match
          case @expected.class.to_s
            when ‘String’
              parts = @expected.split("http://test.host")                      
              @expected = parts.last
              return @actual == @expected
            when ‘Hash’
              @expected = @controller.url_for(@expected)
              return match()
          end         
        end

        def failure_message
          return %Q{expected redirect to #{@expected.inspect}, got redirect to #{@actual.inspect}}
        end

        def negative_failure_message
          return %Q{expected not to be redirected to #{@expected.inspect}, but was}
        end

        def description
          "redirect to #{@actual.inspect}"
        end
      end
     
      # :call-seq:
      #   response.should refresh_to(url)
      #   response.should refresh_to(:action => action_name)
      #   response.should refresh_to(:controller => controller_name, :action => action_name)
      #   response.should_not refresh_to(url)
      #   response.should_not refresh_to(:action => action_name)
      #   response.should_not refresh_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 refresh_to("path/to/action")
      #   response.should refresh_to("http://test.host/path/to/action")
      #   response.should refresh_to(:action => ‘list’)
      def refresh_to(opts)
        RefreshTo.new(controller, opts)
      end
    end

  end
end 

Leave a Reply