Verifying DOM Structure with Tag-Related Assertions

Problem

Your application may make alterations to a web page's Document Object Model (DOM). Testing whether these changes happen correctly can be a great way to verify that the code behind the scenes (in your controller or view helpers) is working correctly. You want to know how to make assertions about the DOM of a page.

Solution

Use the assert_tag Test::Unit assertion to verify that specific DOM elements exist or that an element has specific properties. Assume your application has a template that produces the following output:

app/views/book/display.rhtml:

<html>
 <head><title>RoRCB</title></head>
 <body>
 <h1>Book Page</h1>
 <img class="promo" src="http://railscookbook.org/rorcb.jpg" />
 <ol>
 <li>Chapter One</li>
 <li>Chapter Two</li>
 <li>Chapter Three</li>
 </ol>
 </body>
</html>

To test that the image tag was created correctly and that the list contains three list items and no other child tags, add the following assertions to the test_book_page_display method of the BookControllerTest class:

test/functional/book_controller_test.rb:

require File.dirname(__FILE__) + '/../test_helper'
require 'book_controller'
class BookController; def rescue_action(e) raise e end; end class BookControllerTest < Test::Unit::TestCase
 def setup
 @controller = BookController.new
 @request = ActionController::TestRequest.new
 @response = ActionController::TestResponse.new
 end
 def test_book_page_display
 get :display
 assert_tag :tag => "h1", :content => "Book Page"
 assert_tag :tag => "img",
 :attributes => {
 :class => "promo",
 :src => "http://railscookbook.org/rorcb.jpg"
 }
 assert_tag :tag => "ol", 
 :children => { 
 :count => 3,
 :only => { :tag => "li" }
 }
 end end

Then run the test with rake:

$ rake test:functionals
(in /private/var/www/demo)
/usr/local/bin/ruby -Ilib:test "/usr/local/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/
 rake/rake_test_\
loader.rb" "test/functional/book_controller_test.rb" 
Loaded suite /usr/local/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake/rake_test_loader Started
.
Finished in 0.242395 seconds.
1 tests, 3 assertions, 0 failures, 0 errors

Discussion

assert_tag can be a useful assertion, but it assumes you're working with well-formed XHTML. The assertion's :tag option specifies an XHTML element to search for within the page. Other optional conditions, passed in as a hash, put further constraints on the search.

The solution calls assert_tag three times. The first asserts that an H1 tag exists and that it contains the text Book Page. The second one makes an assertion about the attributes of any existing image tags. Finally, we assert that an ordered list is present in the response XHTML and that it contains three child "li" elements.

The assert_tag assertion comes with a number of options to match both element properties as well as element position and relationship among other elements.


:tag

The node type must match the corresponding value.


:attributes

A hash; the nodes attributes must match the corresponding values in the hash.


:parent

A hash; the node's parent must match the corresponding hash.


:child

A hash; at least one of the node's immediate children must meet the criteria described by the hash.


:ancestor

A hash; at least one of the node's ancestors must meet the criteria described by the hash.


:descendant

A hash; at least one of the node's descendants must meet the criteria described by the hash.


:sibling

A hash; at least one of the node's siblings must meet the criteria described by the hash.


:after

A hash; the node must be after any sibling meeting the criteria described by the hash, and at least one sibling must match.


:before

A hash; the node must be before any sibling meeting the criteria described by the hash, and at least one sibling must match.


:children

A hash, for counting children of a node. Accepts the following keys:


:count

Either a number or a range which must equal (or include) the number of children that match.


:less_than

The number of matching children must be less than this number.


:greater_than

The number of matching children must be greater than this number.


:only

Another hash consisting of the keys to use to match on the children, and only matching children will be counted.


:content

The text content of the node must match the given value.

See Also