~ubuntu-branches/ubuntu/raring/ruby-actionpack-3.2/raring

« back to all changes in this revision

Viewing changes to lib/action_dispatch/testing/assertions/tag.rb

  • Committer: Package Import Robot
  • Author(s): Ondřej Surý
  • Date: 2012-04-25 09:14:01 UTC
  • Revision ID: package-import@ubuntu.com-20120425091401-3nkf83btcemhjquo
Tags: upstream-3.2.3
Import upstream version 3.2.3

Show diffs side-by-side

added added

removed removed

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