The assert{ 2.0 } project asks a simple question: How the leanest possible assertions can yield the maximum diagnostics? Its latest assertion, assert_xhtml, answers this question for HTML. To begin, grab it with: gem install nokogiri assert2 ==require 'assert2/xhtml'== All assert{ 2.0 } dependencies are optional. If you have Nokogiri (>=1.2.2), you can test Rails views like this: user = users(:Moses) get :edit_user, :id => user.id assert_xhtml do form :action => '/users' do fieldset do legend 'Personal Information' label 'First name' input :type => 'text', :name => 'user[first_name]' :value => user.first_name end end end That's a Rails functional test on a form. The assertion expects the form to target the given action, and contain a fieldset, a legend, a label, and a populated text input field. The assertion forgives any other details, such as intervening structural tags, excess spaces, or extra attributes; and complains if any required detail is missing, out of order, or ill-formed. The DSL inside that block is Nokogiri::HTML::Builder notation. Generally speaking, anything Nokogiri can build, you can specify. ===arguments=== Call assert_xhtml(my_xml){} to interrogate your XML. When called without an argument, the method reads @response.body. ===without!=== Every assert* has a matching deny* method. assert_xhtml recognizes the special element without! as a request to fail if the given elements do indeed appear in your output: get :info, :record_id => record.id assert_xhtml do div :class => :content do without!{ div :class => :download } end end That assertion will fail if the outer
tag does not exist, or if any inner
does exist. The without! element respects your document layout. This assertion passes... assert_xhtml SAMPLE_LIST do ul{ li{ ul{ li 'Sales report' without!{ li 'All Sales report criteria' } } } } end ...even though the target document contains an
  • All Sales report criteria
  • : The two
  • elements appear in different
      lists, so the assertion does not associate them. The committee does not yet know what without!{ without!{} } does, so please do not rely on its current behavior, whatever that is! ===escapes=== Certain elements, such as