iconfu iconfu iconfu is the world's largest collection of free, open-source icons and it comes with a handy image editor, so you can tweak icons to suit your needs exactly or even draw your own from scratch
invert blue resize move up verbose drawmode lighter previews remove swap animator library library draw shift up make a copy large editor explorer your icon contract agreement tag

24 February 2008

Readable Specifications : Hpricot and RSpec

I use FIT and HTMLUnit during the day for really, truly testing my web application. At night, when I transform myself into a Ruby monster, it's RSpec and Hpricot (the "enjoyable" HTML parser). I had tried before with assert_select, but I ended up with a zillion nested with_tag statements that didn't help my digestion.

At work, we have written a little bit of transformation so that the tables we see in our FIT tests look pretty similar to the tables we are testing in our application. I wanted to do the same with RSpec so it would look like this:

table = doc.search("//table[@id='invitations']").first

table.should_match([
  [ "email",            "sent",        "accepted",    "login"   ],
  [ "foo@bar",          "2008-02-10",  "2008-02-16",  "foobar"  ],
  [ "yoyo@toto",        "2008-02-15",  "2008-02-17",  "yoyo"    ],
  [ "will@not.accept",  "2008-02-15",  "",            ""        ],
])

The following little bit of code does the job (I dropped it into my spec_helper)

module Hpricot
  class Elem
    def should_match(array)
      array.each_with_index { |row_data, row_index|
        if (row_index == 0)
          cell_tag = "th"
          row = 1
        else
          cell_tag = "td"
          row = row_index
        end
        row_data.each_with_index { |cell_text, column_index|
          q = "//tr[#{row}]/#{cell_tag}[#{column_index + 1}]"
          self.search(q).inner_html.strip.should == cell_text
        }
      }
    end
  end
end

This is a really basic solution ... there's lots of work before I can use it to test attributes and nested markup in an equally readable way. And it assumes the first row is in a <thead> and contains <th> elements; and that the remainder is under a <tbody> element (this is how Markaby generates markup (it also happens to be correct, if you have a header row)).

I'm a total Hpricot n00b, so there's probably a better way to implement this, but I'm enjoying it for now ... please let me know if you have a better way :)

0 comments:

Post a Comment