An RJS Redirect Matcher for rspec

You know what's stupid? Clumsily checking for a javascript redirect in your RJS with this kind of shit:

it "should redirect to the collaborative quote screen" do
  xhr :post, 'attach', :attachment_id => '4023'
  response.body.should =~ /window\.location\.href = \"/collabquote\";"
end

Not only is this ugly, but it ties your test to a particular route, rather than allowing you to use your named route. So I whipped up a custom RJS redirect matcher in about 10 minutes following the guidelines in this post, and I was surprised how easy it was. It should be pretty self explanatory.

module RedirectViaRjsToMatcher  
  class RedirectViaRjsTo  
    def initialize(expected)  
      @expected = expected  
    end  

    def matches?(target)  
      @target = target
      @url = target.body.split('"')[1]
      @target.body == "window.location.href = \"#{@expected}\";"
    end  

    def failure_message  
      "expected redirect via rjs to #{@expected}, redirected instead to #{@url}"
    end  

    def negative_failure_message  
      "unexpected redirect via rjs to #{@expected}"  
    end
  end
  
  # Actual matcher that is exposed 
  def redirect_via_rjs_to(expected)  
    RedirectViaRjsTo.new(expected)  
  end
end

All you need to do is save this file in /spec/custom/redirect_via_rjs_to.rb and include it in /spec/spec_helper.rb like so:

require 'spec/be_the_same_as'

Spec::Runner.configure do |config|  
  config.include(RedirectViaRjsToMatcher)  
end

Voilla! It really is that easy, and turns that first spec into something a bit more readable and reusable:

it "should redirect to the collaborative quote screen" do
  xhr :post, 'attach', :attachment_id => '4023'
  response.should redirect_via_rjs_to quote_path(@quote)
end

UPDATE: Jim clued me into simple_matcher, which appears to be yet another very easy way to create custom matchers.

Read this article
Written on Thursday, January 29, 2009