# Assert2-0.4.6 provides assert\_xhtml, an alternative to assert\_select

**URL:** <https://www.ruby-forum.com/t/assert2-0-4-6-provides-assert-xhtml-an-alternative-to-assert-select/163954>\
**Category:** Ruby\
**Created:** [March 26, 2009, 1:55pm UTC](https://www.ruby-forum.com/t/assert2-0-4-6-provides-assert-xhtml-an-alternative-to-assert-select/163954 "2009-03-26T13:55:47Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![Phlip](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/ed8c4c/32.png) [@Phlip](https://www.ruby-forum.com/u/Phlip)\
**Post date:** [March 26, 2009, 1:55pm UTC](https://www.ruby-forum.com/t/assert2-0-4-6-provides-assert-xhtml-an-alternative-to-assert-select/163954/1 "2009-03-26T13:55:47Z")

</div>

Rubyists:

Consider the following monstrosity, coded using assert\_select:

assert\_select “div#logo\_box img[src=/0000/0001/logo.gif][alt=My  
Company]”

Now, behold it rewritten to use assert\_xhtml:

assert\_xhtml do  
div.logo\_box! do  
img :src =\> /logo.gif$/,  
:alt =\> ‘My Company’  
end  
end

That sample contains more Ruby; it’s not just one big string.

Still not convinced? Oh, I forgot the around the ![]()! Try this:

assert\_xhtml do  
div.logo\_box! do  
a :href =\> ‘/’ do  
img :src =\> /logo.gif$/, :alt =\> ‘My Company’  
end  
end  
end

And we had an issue with the small logo sneaking into the logo\_box once.  
Let’s exclude it:

assert\_xhtml do  
div.logo\_box do  
a :href =\> ‘/’ do  
img :src =\> /logo.gif$/, :alt =\> ‘My Company’  
end  
without!{ img :src =\> /mini\_logo.gif/ }  
end  
end

Imagine adding all that to assert\_select - it would get much harder to  
read, and  
more complex. assert\_xhtml uses Nokogiri::HTML::Builder notation, so  
anything it  
can build, you can query.

Version 0.4.6 adds all the following features. To begin, enter:

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
:

```
 <ul style='font-size: 18'>
   <li>model
     <ul>
       <li>Billings report</li>
       <li>Sales report</li>
       <li>Billings criteria</li>
       <li>Common system</li>
     </ul>
   </li>
   <li>controller
     <ul>
       <li>All Sales report criteria</li>
       <li>All Billings reports</li>
     </ul>
   </li>
 </ul>

```

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 and , have the same names as  
internal  
methods. If you experience a bizarre error message, such as “wrong  
argument  
type Hash (expected Array)”, add a ! to the end of the element, like  
this:

```
 assert_xhtml do
   h2 'Sites'

   select! :id => 'sites',
           :name => 'sites[]',
           :multiple => :multiple,
           :size => SaleController::LIST_SIZE
 end

```

=== text ===

An element such as h3{ ‘text’ } will match

### text
, with leading  
or  
trailing blanks, but it won’t match 
### text
. This  
rule  
prevents runaway matches between high- and low-level elements.

The example for the next section illustrates how to mix text and  
attribute  
specifications on the same element.

A text specification may be a /regexp/.

=== :xpath!=\> ===

assert\_xhtml works by throwing away structural information. If you need  
more control over your structure, use an :xpath! attribute to apply raw  
XPath specifications to your target elements.

This assertion detect the rather pedestrian fact that your   
element remains inside your block - and it did not  
escape and rampage off to somewhere else:

```
 assert_xhtml do
   title :xpath! => 'parent::head/parent::html' do
     text 'Chamber of Commerce - Info - Hope Orphanage'
   end
 end

```

Note the XPath evaluates as a predicate of the target , so its  
parent  
axis lists the familiar elements in reverse.

That code also shows the ‘text’ directive, inserting text contents  
directly  
into the enclosing element. A future version of Nokogiri will allow the  
element’s first argument to specify its text.

An :xpath! of a number evaluates to the 1-based index of an item in its  
parent. This assertion forces list items to appear in the correct order:

```
 assert_xhtml do
   ul :style => 'font-size: 18' do
     li 'model' do
       li(:xpath! => 1){ text 'Sales report' }
       li(:xpath! => 2){ text 'Billings report' }
       li(:xpath! => 3){ text 'Billings criteria' }
     end
   end
 end

```

=== :verbose! =\> true ===

Sometimes when an assertion fails, you can’t tell why. To see each  
context the assertion considers, add :verbose! =\> true to the lowest  
element you know works, and run the tests:

```
 assert_xhtml SAMPLE_FORM do
   fieldset do
     li :verbose! => true do
       label 'First name', :for => :user_first_name
     end
   end
 end

```

The verbose option works as “spew”, not as a diagnostic, and it reports  
each considered element’s contents.

Because XPath evaluates the , in our example, before the

- ,  
you  
might need to comment the out to see a successful spew on the
- === scope ===
