Froze rails gems
[depot.git] / vendor / rails / actionpack / lib / action_controller / assertions / tag_assertions.rb
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