RSpec link matcher with Hpricot

I wrote my first custom RSpec matcher today. I’ve been trying my hand at writing integration tests for a Sinatra app using Rack Test, and trying to confirm a link was in the body and in the correct place (just by seeing it’s inside the right div) was getting a bit verbose, so I wrote this.

# encoding: UTF-8

require "hpricot"

# designed to match links by the href and text
RSpec::Matchers.define :include_link do |href, text, div=nil|
  match do |actual|
    doc = Hpricot(actual)
    doc = doc.at("div##{div}") if div
    doc.search("a[@href*=#{href}]").select{|h| h.inner_html == text }.empty? ? false : true

and I use it like so:

subject { last_response }
it { subject.body.should include_link uri("/"), 'Name of Site', "header" }

that should confirm that something like this was in the body:

<div id='header'>
    <a href='http://localhost:9292/'>Name of Site</a>

It doesn’t mean it looks right, but it’s a step along the way. Btw, the uri method was nicked from Sinatra (with a few modifications so it’d run without explicitly requiring Sinatra) since I use it in the Sinatra app. Here it is in case anyone needs it or is interested. I add it to the rspec_helper.rb.

def uri(addr = nil, absolute = true, add_script_name = true)
  return addr if addr =~ /\A[A-z][A-z0-9\+\.\-]*:/
  uri = [host = ""]
  if absolute
    host << "http#{'s' if last_request.ssl?}://"
    if last_request.env.include?("HTTP_X_FORWARDED_HOST") or last_request.port != (last_request.ssl? ? 443 : 80)
      host << last_request.host_with_port
      host << last_request.host
  uri << last_request.script_name.to_s if add_script_name
  uri << (addr ? addr : last_request.path_info).to_s
  File.join uri
Added on:
Last updated:
  • rack (1.3.1)
  • rack-test (0.6.1)
  • ruby 1.9.2p290
  • rspec (2.6.0)
  • hpricot (0.8.4)
  • OSX 10.6.6
  • Tags