Custom RSpec routing matcher for all four HTTP verbs?

360 Views Asked by At

I'm writing a RSpec test suite of our routes for a rather large Rails 3 application. Many of the routes use "MATCH", but none of them should, especially since we'll have to rewrite them as we transition to Rails 4.

Most of my it blocks look something like this:

  it "with /comments/account/100" do
    expect(get("comments/account/100")).to    route_to("comments#list", :account_id => "100")
    expect(post("comments/account/100")).to   route_to("comments#list", :account_id => "100")
    expect(put("comments/account/100")).to    route_to("comments#list", :account_id => "100")
    expect(delete("comments/account/100")).to route_to("comments#list", :account_id => "100")
  end

It seems a bit, non-DRY, to have to write an endless number of blocks like that. I'd like to have a matcher that looks something like this:

expect(match_all_verbs("/comments/accounts/100")).to route_to("comments#list", :account_id => "100")

EDIT: Final working version, thanks to Steven:

def match_all_verbs(path, method, options = {})
  [:get, :post, :put, :delete].each do |verb|
    expect(send(verb, path)).to route_to(method, options)
  end
end

I added an options hash so I could pass params to the routes. Everything seems to be working fine.

And for fun, I made a match_no_verbs to test the .to_not be_routable matcher combo:

def match_no_verbs(path, method, options = {})
  [:get, :post, :put, :delete].each do |verb|
    expect(send(verb, path)).to_not route_to(method, options)
  end
end

Thanks so much!

1

There are 1 best solutions below

1
On BEST ANSWER

RSpec custom matchers take a single value per the documentation, so your formal parameter values is not getting defined and your reference to it in the body of your matcher fails.

Rather than a custom matcher, whose intent is to specify what equality means and how to display errors for a given type of object, I think you'd want to use some kind of helper which iterates over the verbs and generates the appropriate expect calls.

For example, you could use (not tested):

def match_all_verbs(path, method)
  [:get, :post, :put:, :delete].each do |verb|
    expect(send(verb, path)).to route_to(method)
  end
end