[rspec-users] [ANN] rspec_hpricot_matchers 1.0: have_tag on hpricot

Phlip phlip2005 at gmail.com
Fri Apr 4 00:19:48 EDT 2008

Corey Haines wrote:

>     A few weeks ago, I put together a little project that provides a
>     have_tag() matcher look-alike that can be used outside of Rails
>     projects, backed by Hpricot, which I very creatively named
>     rspec_hpricot_matchers.

I bet it can easily do something like this (if you rspeckers will excuse the 
dreaded word "assert"!):

   def assert_all_embedded_images
     assert_any_xpath :img do |img|
       assert_public_image_file img[:src]
       false # :keep looping!

   def test_find_all_embedded_images
     get :some_action                # a Rails functional test

   def assert_public_image_file(src, line = nil)
     src.sub!(/^\//, '')
        #  RailsRoot = Pathname.new(RAILS_ROOT)
     image_file = RailsRoot + 'public' + src
     #  this file must be where the server and browser can see it
     assert_file(line){ image_file }

Those assertions scan every image in a page and ensure a file with the correct
name appears in ./public/images/. (Our artists have recently been sending us new 
assets, and I didn't feel like manually checking we copied in all the right 

The :img is a shortcut for the XPathic 'descendent-or-self::img', and the 
img[:src] is naturally a shortcut for the <img src=''> attribute.

Those assertions - assert_xpath, assert_any_xpath, etc - work interchangeably 
with REXML, Hpricot, or Libxml for their parser. You just pick the one you want 
by adding to your setup() a call like invoke_rexml, invoke_hpricot, or 
invoke_libxml. Each provides various trades-off, but at work we have fixated on 
Libxml, naturally, because we use hundreds of these assertions, so we need its 
speed. Also, Libxml strictly enforces the Transitional XHTML type that appears 
in all our DOCTYPEs. (gem install assert_xpath, but I haven't documented the 
libxml variant yet...)

My little trick with the image files is only the start of assert_xpath's 
abilities. You can also call it from inside an rspec; you just have to include 
its modules. And, like any of my assertions, it provides a detailed, 
comprehensive diagnostic if it fails.


More information about the rspec-users mailing list