Page Searching in Merb Specs with Hpricot

I’m not entirely sure what the status of this code is, but it seems to be working for me. I tried throwing it a little further upstream and got hit with 42 failed specs, so I’m content to use it as a spec helper for now.

In any event, yeah. There’s Hpricot goodness available for your Merb specs, it just has to be enabled. Where normally we’d get a controller response with a string containing the HTML of the body, we’ll get an Hpricot document that’s easily searchable for tags and such.

Here’s the helper:

spec/spec_helper.rb

  def dispatch controller, action = :index, opts = {}
    @controller = dispatch_to(controller, action, opts)
    @controller.body = Merb::Test::ViewHelper::DocumentOutput.new @controller.body
  end

Now in any of your specs, do this:

  describe Main, "index action" do
 
    it "should have a title of 'Happy Days Are Here'" do
      dispatch Main, :index
      @controller.body['title'].inner_text.should == "Happy Days Are Here"
    end
  end

Tada! No parsing through the document looking for the title tag. Very nice.

The methods you get are these:

  • []: The index method will return a single element if there’s one of them in the document, or an Array of them if there’s multiple ones. Then you can pick out the data you want.
  • content_for: This method takes an HTML element or HTML element and class specification (like ‘div’ ‘div.content’) and returns the text contents of the first found tag that matches that element or element and class. This means if you have code like this:
  <div class='awesome'>
    This is some content.
    <b>This is some more content.</b>
    <a href='http://google.com'>This is a link.</a>
    <ul>
      <li>Item</li>
      <li>Item</li>
    </ul>
  </div>

Then calling @controller.body.content_for('div.awesome') will return the literal interpretation of all of the text, indentations and all, like so:

    This is some content.
            This is some more content.
            This is a link.
            Item
              Item
So be very careful doing matches with this method!

  • content_for_all: This method is the same as content_for, except it will parse through the entire document and find all of the elements that match that tag or tag and class, and return them in an Array. If you’re only looking for one instance of a tag, use content_for, as this will be needlessly time-consuming.

Edit: I should also mention that the [] method takes XPath expressions, so you could do something like div[@class='awesome']/ul/li to get an Array of the list items in the last example. Sweet!

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*