Steve Ross
Steve Ross

Reputation: 4144

Testing Rack Routing Using rSpec

I have a rule in my routes.rb:

constraints AssetRestrictor do
  match '*seopath' => SeoDispatcher
end

Then in lib/seo_dispatcher.rb, I have this:

class SeoDispatcher
  AD_KEY = "action_dispatch.request.path_parameters"

  def self.call(env)
    seopath = env[AD_KEY][:seopath]

    if seopath
      params = seopath.split('/')           # get array of path components
      env[AD_KEY][:id] = params.last        # the real page name is the last element
      env[AD_KEY][:category] = params.first if params.length > 1
    end

    Rails.logger.debug "routing to show #{env[AD_KEY]}"
    PagesController.action(:show).call(env)
    # TODO error handling for invalid paths
  end
end

class AssetRestrictor
  EXCEPTION_FILES = ['javascripts', 'stylesheets', 'autodiscover']
  def self.matches?(request)
    return false if request.method == 'POST'  # no post requests are SEO-ed
    EXCEPTION_FILES.each do |ex|
      return false if request.url.include?(ex)
    end
    true
  end
end

And basically, the whole thing works. The idea is to peel off the last path component and match it to the slug for a page. SEO people tell me this is the cool way to trick search engines into ranking you higher.

My snarky comments aside, I'm having trouble writing a test in rSpec that exercises this code. My first shot at it was:

describe SeoDispatcher do
  it "routes /insurance/charters-and-guides/how-to-buy-charter-boat-insurance to pages#show :id => how-to-buy-charter-boat-insurance" do
    { :get => "/insurance/charters-and-guides/how-to-buy-charter-boat-insurance"}.should route_to(
      :controller => 'pages',
      :action     => 'show',
      :id         => 'how-to-buy-charter-boat-insurance'
    )
  end
end

But this simply doesn't exercise the Rack dispatch code. Does anyone know how one would (than cuking it) exercise the code? I really want to bring the parameters in from Rack instead of just doing SeoDispatcher.call({"action_dispatch.request.path_parameters" => {:seopath => "/foo/bar"}}).

Thanks!

Upvotes: 2

Views: 1619

Answers (1)

Steve Ross
Steve Ross

Reputation: 4144

Ok, answered my own question. Request spec:

describe SeoDispatcher do
  describe "seo parsing" do
    it "GET /insurance/charters-and-guides/how-to-buy-charter-boat-insurance displays how-to-buy-charter-boat-insurance (3-part path)" do
      p = Page.make(:title => "how-to-buy-charter-boat-insurance")
      p.save
      get "/insurance/charters-and-guides/how-to-buy-charter-boat-insurance"
      request.path.should == "/insurance/charters-and-guides/how-to-buy-charter-boat-insurance"
      assigns[:page].slug.should == "how-to-buy-charter-boat-insurance"
    end

    it "GET /insurance/charters-and-guides displays guides (2-part path)" do
      p = Page.make(:title => "charters and guides")
      p.save
      get "/insurance/charters-and-guides"
      request.path.should == "/insurance/charters-and-guides"
      assigns[:page].slug.should == "charters-and-guides"
    end

    it "GET /insurance displays insurance (1-part path)" do
      p = Page.make(:title => "insurance")
      p.save
      get "/insurance"
      request.path.should == "/insurance"
      assigns[:page].slug.should == "insurance"
    end
  end
end

If anyone knows a better way, feel free to let me know!

Upvotes: 2

Related Questions