Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

root/trunk/actionpack/lib/action_controller/assertions/tag_assertions.rb

Revision 8300, 6.2 kB (checked in by marcel, 1 year ago)

Add many examples to assertion documentation. Closes #7803 [jeremymcanally]

Line 
1 require 'rexml/document'
2 require 'html/document'
3
4 module ActionController
5   module Assertions
6     # Pair of assertions to testing elements in the HTML output of the response.
7     module TagAssertions
8       # Asserts that there is a tag/node/element in the body of the response
9       # that meets all of the given conditions. The +conditions+ parameter must
10       # be a hash of any of the following keys (all are optional):
11       #
12       # * <tt>:tag</tt>: the node type must match the corresponding value
13       # * <tt>:attributes</tt>: a hash. The node's attributes must match the
14       #   corresponding values in the hash.
15       # * <tt>:parent</tt>: a hash. The node's parent must match the
16       #   corresponding hash.
17       # * <tt>:child</tt>: a hash. At least one of the node's immediate children
18       #   must meet the criteria described by the hash.
19       # * <tt>:ancestor</tt>: a hash. At least one of the node's ancestors must
20       #   meet the criteria described by the hash.
21       # * <tt>:descendant</tt>: a hash. At least one of the node's descendants
22       #   must meet the criteria described by the hash.
23       # * <tt>:sibling</tt>: a hash. At least one of the node's siblings must
24       #   meet the criteria described by the hash.
25       # * <tt>:after</tt>: a hash. The node must be after any sibling meeting
26       #   the criteria described by the hash, and at least one sibling must match.
27       # * <tt>:before</tt>: a hash. The node must be before any sibling meeting
28       #   the criteria described by the hash, and at least one sibling must match.
29       # * <tt>:children</tt>: a hash, for counting children of a node. Accepts
30       #   the keys:
31       #   * <tt>:count</tt>: either a number or a range which must equal (or
32       #     include) the number of children that match.
33       #   * <tt>:less_than</tt>: the number of matching children must be less
34       #     than this number.
35       #   * <tt>:greater_than</tt>: the number of matching children must be
36       #     greater than this number.
37       #   * <tt>:only</tt>: another hash consisting of the keys to use
38       #     to match on the children, and only matching children will be
39       #     counted.
40       # * <tt>:content</tt>: the textual content of the node must match the
41       #   given value. This will not match HTML tags in the body of a
42       #   tag--only text.
43       #
44       # Conditions are matched using the following algorithm:
45       #
46       # * if the condition is a string, it must be a substring of the value.
47       # * if the condition is a regexp, it must match the value.
48       # * if the condition is a number, the value must match number.to_s.
49       # * if the condition is +true+, the value must not be +nil+.
50       # * if the condition is +false+ or +nil+, the value must be +nil+.
51       #
52       # === Examples
53       #
54       #   # Assert that there is a "span" tag
55       #   assert_tag :tag => "span"
56       #
57       #   # Assert that there is a "span" tag with id="x"
58       #   assert_tag :tag => "span", :attributes => { :id => "x" }
59       #
60       #   # Assert that there is a "span" tag using the short-hand
61       #   assert_tag :span
62       #
63       #   # Assert that there is a "span" tag with id="x" using the short-hand
64       #   assert_tag :span, :attributes => { :id => "x" }
65       #
66       #   # Assert that there is a "span" inside of a "div"
67       #   assert_tag :tag => "span", :parent => { :tag => "div" }
68       #
69       #   # Assert that there is a "span" somewhere inside a table
70       #   assert_tag :tag => "span", :ancestor => { :tag => "table" }
71       #
72       #   # Assert that there is a "span" with at least one "em" child
73       #   assert_tag :tag => "span", :child => { :tag => "em" }
74       #
75       #   # Assert that there is a "span" containing a (possibly nested)
76       #   # "strong" tag.
77       #   assert_tag :tag => "span", :descendant => { :tag => "strong" }
78       #
79       #   # Assert that there is a "span" containing between 2 and 4 "em" tags
80       #   # as immediate children
81       #   assert_tag :tag => "span",
82       #              :children => { :count => 2..4, :only => { :tag => "em" } }
83       #
84       #   # Get funky: assert that there is a "div", with an "ul" ancestor
85       #   # and an "li" parent (with "class" = "enum"), and containing a
86       #   # "span" descendant that contains text matching /hello world/
87       #   assert_tag :tag => "div",
88       #              :ancestor => { :tag => "ul" },
89       #              :parent => { :tag => "li",
90       #                           :attributes => { :class => "enum" } },
91       #              :descendant => { :tag => "span",
92       #                               :child => /hello world/ }
93       #
94       # <b>Please note</b>: #assert_tag and #assert_no_tag only work
95       # with well-formed XHTML. They recognize a few tags as implicitly self-closing
96       # (like br and hr and such) but will not work correctly with tags
97       # that allow optional closing tags (p, li, td). <em>You must explicitly
98       # close all of your tags to use these assertions.</em>
99       def assert_tag(*opts)
100         clean_backtrace do
101           opts = opts.size > 1 ? opts.last.merge({ :tag => opts.first.to_s }) : opts.first
102           tag = find_tag(opts)
103           assert tag, "expected tag, but no tag found matching #{opts.inspect} in:\n#{@response.body.inspect}"
104         end
105       end
106      
107       # Identical to #assert_tag, but asserts that a matching tag does _not_
108       # exist. (See #assert_tag for a full discussion of the syntax.)
109       #
110       # === Examples
111       #   # Assert that there is not a "div" containing a "p"
112       #   assert_no_tag :tag => "div", :descendant => { :tag => "p" }
113       #
114       #   # Assert that an unordered list is empty
115       #   assert_no_tag :tag => "ul", :descendant => { :tag => "li" }
116       #
117       #   # Assert that there is not a "p" tag with between 1 to 3 "img" tags
118       #   # as immediate children
119       #   assert_no_tag :tag => "p",
120       #              :children => { :count => 1..3, :only => { :tag => "img" } }
121       def assert_no_tag(*opts)
122         clean_backtrace do
123           opts = opts.size > 1 ? opts.last.merge({ :tag => opts.first.to_s }) : opts.first
124           tag = find_tag(opts)
125           assert !tag, "expected no tag, but found tag matching #{opts.inspect} in:\n#{@response.body.inspect}"
126         end
127       end
128     end
129   end
130 end
Note: See TracBrowser for help on using the browser.