rails-dom-testing 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +66 -0
- data/lib/rails-dom-testing.rb +1 -0
- data/lib/rails/dom/testing/assertions.rb +18 -0
- data/lib/rails/dom/testing/assertions/dom_assertions.rb +75 -0
- data/lib/rails/dom/testing/assertions/selector_assertions.rb +339 -0
- data/lib/rails/dom/testing/assertions/selector_assertions/html_selector.rb +96 -0
- data/lib/rails/dom/testing/assertions/selector_assertions/substitution_context.rb +28 -0
- data/lib/rails/dom/testing/version.rb +7 -0
- data/test/dom_assertions_test.rb +43 -0
- data/test/selector_assertions_test.rb +281 -0
- data/test/test_helper.rb +3 -0
- metadata +133 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e4c5e946843592cec1b0b7e17a9dc5fe9b2b0ceb
|
4
|
+
data.tar.gz: 4cae76910af7476691d495a0ab84863e363824e3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d4ead231de2ed2c888eba70d866eae3a58a7eb853c5863b67278a87e4b164beae052af93c3c6c36b51ef198964a7613b8c874ee9a3fc60ec0168484ce92b5e10
|
7
|
+
data.tar.gz: 7744ed519a6cff2f3e77395aced9a5d104e034ebddb7370897f53ad68d55f00917bfff1891fe8d4f494754f23630b7899c0afd1147c49dbbf7b2460dd8feb5a8
|
data/CHANGELOG.md
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Kasper Timm Hansen
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
# Rails::Dom::Testing
|
2
|
+
[![Build Status](https://travis-ci.org/rails/rails-dom-testing.svg)](https://travis-ci.org/rails/rails-dom-testing)
|
3
|
+
|
4
|
+
This gem is responsible for comparing HTML doms and asserting that DOM elements are present in Rails applications.
|
5
|
+
Doms are compared via `assert_dom_equal` and `assert_dom_not_equal`.
|
6
|
+
Elements are asserted via `assert_select`, `assert_select_encoded`, `assert_select_email` and a subset of the dom can be selected with `css_select`.
|
7
|
+
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
gem 'rails-dom-testing'
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install rails-dom-testing
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
### Dom Assertions
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
assert_dom_equal '<h1>Lingua França</h1>', '<h1>Lingua França</h1>'
|
29
|
+
|
30
|
+
assert_dom_not_equal '<h1>Portuguese</h1>', '<h1>Danish</h1>'
|
31
|
+
```
|
32
|
+
|
33
|
+
### Selector Assertions
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
# implicitly selects from the document_root_element
|
37
|
+
css_select '.hello' # => Nokogiri::XML::NodeSet of elements with hello class
|
38
|
+
|
39
|
+
# select from a supplied node. assert_select asserts elements exist.
|
40
|
+
assert_select document_root_element.at('.hello'), '.goodbye'
|
41
|
+
|
42
|
+
# elements in CDATA encoded sections can also be selected
|
43
|
+
assert_select_encoded '#out-of-your-element'
|
44
|
+
|
45
|
+
# assert elements within an html email exists
|
46
|
+
assert_select_email '#you-got-mail'
|
47
|
+
```
|
48
|
+
|
49
|
+
The documentation in [selector_assertions.rb](https://github.com/kaspth/rails-dom-testing/blob/master/lib/rails/dom/testing/assertions/selector_assertions.rb) goes into a lot more detail of how selector assertions can be used.
|
50
|
+
|
51
|
+
## Read more
|
52
|
+
|
53
|
+
Under the hood the doms are parsed with Nokogiri and you'll generally be working with these two classes:
|
54
|
+
- [`Nokogiri::XML::Node`](http://nokogiri.org/Nokogiri/XML/Node.html)
|
55
|
+
- [`Nokogiri::XML::NodeSet`](http://nokogiri.org/Nokogiri/XML/NodeSet.html)
|
56
|
+
|
57
|
+
Read more about Nokogiri:
|
58
|
+
- [Nokogiri](http://nokogiri.org)
|
59
|
+
|
60
|
+
## Contributing
|
61
|
+
|
62
|
+
1. Fork it
|
63
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
64
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
65
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
66
|
+
5. Create new Pull Request
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'rails/dom/testing/assertions'
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
module Rails
|
5
|
+
module Dom
|
6
|
+
module Testing
|
7
|
+
module Assertions
|
8
|
+
autoload :DomAssertions, 'rails/dom/testing/assertions/dom_assertions'
|
9
|
+
autoload :SelectorAssertions, 'rails/dom/testing/assertions/selector_assertions'
|
10
|
+
|
11
|
+
extend ActiveSupport::Concern
|
12
|
+
|
13
|
+
include DomAssertions
|
14
|
+
include SelectorAssertions
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module Rails
|
2
|
+
module Dom
|
3
|
+
module Testing
|
4
|
+
module Assertions
|
5
|
+
module DomAssertions
|
6
|
+
# \Test two HTML strings for equivalency (e.g., equal even when attributes are in another order)
|
7
|
+
#
|
8
|
+
# # assert that the referenced method generates the appropriate HTML string
|
9
|
+
# assert_dom_equal '<a href="http://www.example.com">Apples</a>', link_to("Apples", "http://www.example.com")
|
10
|
+
def assert_dom_equal(expected, actual, message = nil)
|
11
|
+
expected_dom, actual_dom = fragment(expected), fragment(actual)
|
12
|
+
message ||= "Expected: #{expected}\nActual: #{actual}"
|
13
|
+
assert compare_doms(expected_dom, actual_dom), message
|
14
|
+
end
|
15
|
+
|
16
|
+
# The negated form of +assert_dom_equal+.
|
17
|
+
#
|
18
|
+
# # assert that the referenced method does not generate the specified HTML string
|
19
|
+
# assert_dom_not_equal '<a href="http://www.example.com">Apples</a>', link_to("Oranges", "http://www.example.com")
|
20
|
+
def assert_dom_not_equal(expected, actual, message = nil)
|
21
|
+
expected_dom, actual_dom = fragment(expected), fragment(actual)
|
22
|
+
message ||= "Expected: #{expected}\nActual: #{actual}"
|
23
|
+
assert_not compare_doms(expected_dom, actual_dom), message
|
24
|
+
end
|
25
|
+
|
26
|
+
protected
|
27
|
+
|
28
|
+
def compare_doms(expected, actual)
|
29
|
+
return false unless expected.children.size == actual.children.size
|
30
|
+
|
31
|
+
expected.children.each_with_index do |child, i|
|
32
|
+
return false unless equal_children?(child, actual.children[i])
|
33
|
+
end
|
34
|
+
|
35
|
+
true
|
36
|
+
end
|
37
|
+
|
38
|
+
def equal_children?(child, other_child)
|
39
|
+
return false unless child.type == other_child.type
|
40
|
+
|
41
|
+
if child.element?
|
42
|
+
child.name == other_child.name &&
|
43
|
+
equal_attribute_nodes?(child.attribute_nodes, other_child.attribute_nodes)
|
44
|
+
else
|
45
|
+
child.to_s == other_child.to_s
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def equal_attribute_nodes?(nodes, other_nodes)
|
50
|
+
return false unless nodes.size == other_nodes.size
|
51
|
+
|
52
|
+
nodes = nodes.sort_by(&:name)
|
53
|
+
other_nodes = other_nodes.sort_by(&:name)
|
54
|
+
|
55
|
+
nodes.each_with_index do |attr, i|
|
56
|
+
return false unless equal_attribute?(attr, other_nodes[i])
|
57
|
+
end
|
58
|
+
|
59
|
+
true
|
60
|
+
end
|
61
|
+
|
62
|
+
def equal_attribute?(attr, other_attr)
|
63
|
+
attr.name == other_attr.name && attr.value == other_attr.value
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def fragment(text)
|
69
|
+
Nokogiri::HTML::DocumentFragment.parse(text)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,339 @@
|
|
1
|
+
require 'active_support/deprecation'
|
2
|
+
require_relative 'selector_assertions/html_selector'
|
3
|
+
|
4
|
+
module Rails
|
5
|
+
module Dom
|
6
|
+
module Testing
|
7
|
+
module Assertions
|
8
|
+
# Adds the +assert_select+ method for use in Rails functional
|
9
|
+
# test cases, which can be used to make assertions on the response HTML of a controller
|
10
|
+
# action. You can also call +assert_select+ within another +assert_select+ to
|
11
|
+
# make assertions on elements selected by the enclosing assertion.
|
12
|
+
#
|
13
|
+
# Use +css_select+ to select elements without making an assertions, either
|
14
|
+
# from the response HTML or elements selected by the enclosing assertion.
|
15
|
+
#
|
16
|
+
# In addition to HTML responses, you can make the following assertions:
|
17
|
+
#
|
18
|
+
# * +assert_select_encoded+ - Assertions on HTML encoded inside XML, for example for dealing with feed item descriptions.
|
19
|
+
# * +assert_select_email+ - Assertions on the HTML body of an e-mail.
|
20
|
+
module SelectorAssertions
|
21
|
+
|
22
|
+
# Select and return all matching elements.
|
23
|
+
#
|
24
|
+
# If called with a single argument, uses that argument as a selector.
|
25
|
+
# Called without an element +css_select+ selects from
|
26
|
+
# the element returned in +document_root_element+
|
27
|
+
#
|
28
|
+
# The default implementation of +document_root_element+ raises an exception explaining this.
|
29
|
+
#
|
30
|
+
# Returns an empty Nokogiri::XML::NodeSet if no match is found.
|
31
|
+
#
|
32
|
+
# If called with two arguments, uses the first argument as the root
|
33
|
+
# element and the second argument as the selector. Attempts to match the
|
34
|
+
# root element and any of its children.
|
35
|
+
# Returns an empty Nokogiri::XML::NodeSet if no match is found.
|
36
|
+
#
|
37
|
+
# The selector may be a CSS selector expression (String).
|
38
|
+
# css_select returns nil if called with an invalid css selector.
|
39
|
+
#
|
40
|
+
# # Selects all div tags
|
41
|
+
# divs = css_select("div")
|
42
|
+
#
|
43
|
+
# # Selects all paragraph tags and does something interesting
|
44
|
+
# pars = css_select("p")
|
45
|
+
# pars.each do |par|
|
46
|
+
# # Do something fun with paragraphs here...
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
# # Selects all list items in unordered lists
|
50
|
+
# items = css_select("ul>li")
|
51
|
+
#
|
52
|
+
# # Selects all form tags and then all inputs inside the form
|
53
|
+
# forms = css_select("form")
|
54
|
+
# forms.each do |form|
|
55
|
+
# inputs = css_select(form, "input")
|
56
|
+
# ...
|
57
|
+
# end
|
58
|
+
def css_select(*args)
|
59
|
+
raise ArgumentError, "you at least need a selector argument" if args.empty?
|
60
|
+
|
61
|
+
root = args.size == 1 ? document_root_element : args.shift
|
62
|
+
selector = args.first
|
63
|
+
|
64
|
+
catch_invalid_selector do
|
65
|
+
nodeset(root).css(selector)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# An assertion that selects elements and makes one or more equality tests.
|
70
|
+
#
|
71
|
+
# If the first argument is an element, selects all matching elements
|
72
|
+
# starting from (and including) that element and all its children in
|
73
|
+
# depth-first order.
|
74
|
+
#
|
75
|
+
# If no element is specified +assert_select+ selects from
|
76
|
+
# the element returned in +document_root_element+
|
77
|
+
# unless +assert_select+ is called from within an +assert_select+ block.
|
78
|
+
# Override +document_root_element+ to tell +assert_select+ what to select from.
|
79
|
+
# The default implementation raises an exception explaining this.
|
80
|
+
#
|
81
|
+
# When called with a block +assert_select+ passes an array of selected elements
|
82
|
+
# to the block. Calling +assert_select+ from the block, with no element specified,
|
83
|
+
# runs the assertion on the complete set of elements selected by the enclosing assertion.
|
84
|
+
# Alternatively the array may be iterated through so that +assert_select+ can be called
|
85
|
+
# separately for each element.
|
86
|
+
#
|
87
|
+
#
|
88
|
+
# ==== Example
|
89
|
+
# If the response contains two ordered lists, each with four list elements then:
|
90
|
+
# assert_select "ol" do |elements|
|
91
|
+
# elements.each do |element|
|
92
|
+
# assert_select element, "li", 4
|
93
|
+
# end
|
94
|
+
# end
|
95
|
+
#
|
96
|
+
# will pass, as will:
|
97
|
+
# assert_select "ol" do
|
98
|
+
# assert_select "li", 8
|
99
|
+
# end
|
100
|
+
#
|
101
|
+
# The selector may be a CSS selector expression (String) or an expression
|
102
|
+
# with substitution values (Array).
|
103
|
+
# Substitution uses a custom pseudo class match. Pass in whatever attribute you want to match (enclosed in quotes) and a ? for the substitution.
|
104
|
+
# assert_select returns nil if called with an invalid css selector.
|
105
|
+
#
|
106
|
+
# assert_select "div:match('id', ?)", /\d+/
|
107
|
+
#
|
108
|
+
# === Equality Tests
|
109
|
+
#
|
110
|
+
# The equality test may be one of the following:
|
111
|
+
# * <tt>true</tt> - Assertion is true if at least one element selected.
|
112
|
+
# * <tt>false</tt> - Assertion is true if no element selected.
|
113
|
+
# * <tt>String/Regexp</tt> - Assertion is true if the text value of at least
|
114
|
+
# one element matches the string or regular expression.
|
115
|
+
# * <tt>Integer</tt> - Assertion is true if exactly that number of
|
116
|
+
# elements are selected.
|
117
|
+
# * <tt>Range</tt> - Assertion is true if the number of selected
|
118
|
+
# elements fit the range.
|
119
|
+
# If no equality test specified, the assertion is true if at least one
|
120
|
+
# element selected.
|
121
|
+
#
|
122
|
+
# To perform more than one equality tests, use a hash with the following keys:
|
123
|
+
# * <tt>:text</tt> - Narrow the selection to elements that have this text
|
124
|
+
# value (string or regexp).
|
125
|
+
# * <tt>:html</tt> - Narrow the selection to elements that have this HTML
|
126
|
+
# content (string or regexp).
|
127
|
+
# * <tt>:count</tt> - Assertion is true if the number of selected elements
|
128
|
+
# is equal to this value.
|
129
|
+
# * <tt>:minimum</tt> - Assertion is true if the number of selected
|
130
|
+
# elements is at least this value.
|
131
|
+
# * <tt>:maximum</tt> - Assertion is true if the number of selected
|
132
|
+
# elements is at most this value.
|
133
|
+
#
|
134
|
+
# If the method is called with a block, once all equality tests are
|
135
|
+
# evaluated the block is called with an array of all matched elements.
|
136
|
+
#
|
137
|
+
# # At least one form element
|
138
|
+
# assert_select "form"
|
139
|
+
#
|
140
|
+
# # Form element includes four input fields
|
141
|
+
# assert_select "form input", 4
|
142
|
+
#
|
143
|
+
# # Page title is "Welcome"
|
144
|
+
# assert_select "title", "Welcome"
|
145
|
+
#
|
146
|
+
# # Page title is "Welcome" and there is only one title element
|
147
|
+
# assert_select "title", {count: 1, text: "Welcome"},
|
148
|
+
# "Wrong title or more than one title element"
|
149
|
+
#
|
150
|
+
# # Page contains no forms
|
151
|
+
# assert_select "form", false, "This page must contain no forms"
|
152
|
+
#
|
153
|
+
# # Test the content and style
|
154
|
+
# assert_select "body div.header ul.menu"
|
155
|
+
#
|
156
|
+
# # Use substitution values
|
157
|
+
# assert_select "ol>li:match('id', ?)", /item-\d+/
|
158
|
+
#
|
159
|
+
# # All input fields in the form have a name
|
160
|
+
# assert_select "form input" do
|
161
|
+
# assert_select ":match('name', ?)", /.+/ # Not empty
|
162
|
+
# end
|
163
|
+
def assert_select(*args, &block)
|
164
|
+
@selected ||= nil
|
165
|
+
|
166
|
+
root = determine_root_from(args, @selected)
|
167
|
+
selector = HTMLSelector.new(root, args)
|
168
|
+
|
169
|
+
matches = nil
|
170
|
+
catch_invalid_selector do
|
171
|
+
matches = selector.select
|
172
|
+
|
173
|
+
assert_size_match!(matches.size, selector.equality_tests, selector.source, selector.message)
|
174
|
+
end
|
175
|
+
|
176
|
+
nest_selection(matches, &block) if block_given? && !matches.empty?
|
177
|
+
|
178
|
+
matches
|
179
|
+
end
|
180
|
+
|
181
|
+
def count_description(min, max, count) #:nodoc:
|
182
|
+
pluralize = lambda {|word, quantity| word << (quantity == 1 ? '' : 's')}
|
183
|
+
|
184
|
+
if min && max && (max != min)
|
185
|
+
"between #{min} and #{max} elements"
|
186
|
+
elsif min && max && max == min && count
|
187
|
+
"exactly #{count} #{pluralize['element', min]}"
|
188
|
+
elsif min && !(min == 1 && max == 1)
|
189
|
+
"at least #{min} #{pluralize['element', min]}"
|
190
|
+
elsif max
|
191
|
+
"at most #{max} #{pluralize['element', max]}"
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
# Extracts the content of an element, treats it as encoded HTML and runs
|
196
|
+
# nested assertion on it.
|
197
|
+
#
|
198
|
+
# You typically call this method within another assertion to operate on
|
199
|
+
# all currently selected elements. You can also pass an element or array
|
200
|
+
# of elements.
|
201
|
+
#
|
202
|
+
# The content of each element is un-encoded, and wrapped in the root
|
203
|
+
# element +encoded+. It then calls the block with all un-encoded elements.
|
204
|
+
#
|
205
|
+
# # Selects all bold tags from within the title of an Atom feed's entries (perhaps to nab a section name prefix)
|
206
|
+
# assert_select "feed[xmlns='http://www.w3.org/2005/Atom']" do
|
207
|
+
# # Select each entry item and then the title item
|
208
|
+
# assert_select "entry>title" do
|
209
|
+
# # Run assertions on the encoded title elements
|
210
|
+
# assert_select_encoded do
|
211
|
+
# assert_select "b"
|
212
|
+
# end
|
213
|
+
# end
|
214
|
+
# end
|
215
|
+
#
|
216
|
+
#
|
217
|
+
# # Selects all paragraph tags from within the description of an RSS feed
|
218
|
+
# assert_select "rss[version=2.0]" do
|
219
|
+
# # Select description element of each feed item.
|
220
|
+
# assert_select "channel>item>description" do
|
221
|
+
# # Run assertions on the encoded elements.
|
222
|
+
# assert_select_encoded do
|
223
|
+
# assert_select "p"
|
224
|
+
# end
|
225
|
+
# end
|
226
|
+
# end
|
227
|
+
def assert_select_encoded(element = nil, &block)
|
228
|
+
if !element && !@selected
|
229
|
+
raise ArgumentError, "Element is required when called from a nonnested assert_select"
|
230
|
+
end
|
231
|
+
|
232
|
+
content = nodeset(element || @selected).map do |elem|
|
233
|
+
elem.children.select(&:cdata?).map(&:content)
|
234
|
+
end.join
|
235
|
+
|
236
|
+
selected = Nokogiri::HTML::DocumentFragment.parse(content)
|
237
|
+
nest_selection(selected) do
|
238
|
+
if content.empty?
|
239
|
+
yield selected
|
240
|
+
else
|
241
|
+
assert_select ":root", &block
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
# Extracts the body of an email and runs nested assertions on it.
|
247
|
+
#
|
248
|
+
# You must enable deliveries for this assertion to work, use:
|
249
|
+
# ActionMailer::Base.perform_deliveries = true
|
250
|
+
#
|
251
|
+
# assert_select_email do
|
252
|
+
# assert_select "h1", "Email alert"
|
253
|
+
# end
|
254
|
+
#
|
255
|
+
# assert_select_email do
|
256
|
+
# items = assert_select "ol>li"
|
257
|
+
# items.each do
|
258
|
+
# # Work with items here...
|
259
|
+
# end
|
260
|
+
# end
|
261
|
+
def assert_select_email(&block)
|
262
|
+
deliveries = ActionMailer::Base.deliveries
|
263
|
+
assert !deliveries.empty?, "No e-mail in delivery list"
|
264
|
+
|
265
|
+
deliveries.each do |delivery|
|
266
|
+
(delivery.parts.empty? ? [delivery] : delivery.parts).each do |part|
|
267
|
+
if part["Content-Type"].to_s =~ /^text\/html\W/
|
268
|
+
root = Nokogiri::HTML::DocumentFragment.parse(part.body.to_s)
|
269
|
+
assert_select root, ":root", &block
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
protected
|
276
|
+
|
277
|
+
def document_root_element
|
278
|
+
raise NotImplementedError, "Implementing document_root_element makes assert_select work without needing to specify an element to select from."
|
279
|
+
end
|
280
|
+
|
281
|
+
def catch_invalid_selector
|
282
|
+
begin
|
283
|
+
yield
|
284
|
+
rescue Nokogiri::CSS::SyntaxError => e
|
285
|
+
ActiveSupport::Deprecation.warn("The assertion was not run because of an invalid css selector.\n#{e}")
|
286
|
+
return
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
# +equals+ must contain :minimum, :maximum and :count keys
|
291
|
+
def assert_size_match!(size, equals, css_selector, message = nil)
|
292
|
+
min, max, count = equals[:minimum], equals[:maximum], equals[:count]
|
293
|
+
|
294
|
+
message ||= %(Expected #{count_description(min, max, count)} matching "#{css_selector}", found #{size}.)
|
295
|
+
if count
|
296
|
+
assert_equal count, size, message
|
297
|
+
else
|
298
|
+
assert_operator size, :>=, min, message if min
|
299
|
+
assert_operator size, :<=, max, message if max
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
def determine_root_from(args, previous_selection = nil)
|
304
|
+
possible_root = args.first
|
305
|
+
if possible_root == nil
|
306
|
+
raise ArgumentError, "First argument is either selector or element to select, but nil found. Perhaps you called assert_select with an element that does not exist?"
|
307
|
+
elsif HTMLSelector.can_select_from?(possible_root)
|
308
|
+
args.shift # remove the root, so selector is the first argument
|
309
|
+
possible_root
|
310
|
+
elsif previous_selection
|
311
|
+
previous_selection
|
312
|
+
else
|
313
|
+
document_root_element
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
def nest_selection(selection)
|
318
|
+
# Set @selected to allow nested assert_select.
|
319
|
+
# Can be nested several levels deep.
|
320
|
+
begin
|
321
|
+
old_selected, @selected = @selected, selection
|
322
|
+
yield @selected
|
323
|
+
ensure
|
324
|
+
@selected = old_selected
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
def nodeset(node)
|
329
|
+
if node.is_a?(Nokogiri::XML::NodeSet)
|
330
|
+
node
|
331
|
+
else
|
332
|
+
Nokogiri::XML::NodeSet.new(node.document, [node])
|
333
|
+
end
|
334
|
+
end
|
335
|
+
end
|
336
|
+
end
|
337
|
+
end
|
338
|
+
end
|
339
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require_relative 'substitution_context'
|
2
|
+
|
3
|
+
class HTMLSelector #:nodoc:
|
4
|
+
NO_STRIP = %w{pre script style textarea}
|
5
|
+
attr_accessor :root, :selector, :equality_tests, :message
|
6
|
+
|
7
|
+
alias :source :selector
|
8
|
+
|
9
|
+
def initialize(root, args)
|
10
|
+
@root = root
|
11
|
+
@selector = extract_selector(args)
|
12
|
+
|
13
|
+
@equality_tests = equality_tests_from(args.shift)
|
14
|
+
@message = args.shift
|
15
|
+
|
16
|
+
if args.shift
|
17
|
+
raise ArgumentError, "Not expecting that last argument, you either have too many arguments, or they're the wrong type"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class << self
|
22
|
+
def can_select_from?(selector)
|
23
|
+
selector.respond_to?(:css)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def select
|
28
|
+
filter root.css(selector, context)
|
29
|
+
end
|
30
|
+
|
31
|
+
def filter(matches)
|
32
|
+
match_with = equality_tests[:text] || equality_tests[:html]
|
33
|
+
return matches if matches.empty? || !match_with
|
34
|
+
|
35
|
+
content_mismatch = nil
|
36
|
+
text_matches = equality_tests.has_key?(:text)
|
37
|
+
regex_matching = match_with.is_a?(Regexp)
|
38
|
+
|
39
|
+
remaining = matches.reject do |match|
|
40
|
+
# Preserve markup with to_s for html elements
|
41
|
+
content = text_matches ? match.text : match.children.to_s
|
42
|
+
|
43
|
+
content.strip! unless NO_STRIP.include?(match.name)
|
44
|
+
content.sub!(/\A\n/, '') if text_matches && match.name == "textarea"
|
45
|
+
|
46
|
+
next if regex_matching ? (content =~ match_with) : (content == match_with)
|
47
|
+
content_mismatch ||= sprintf("<%s> expected but was\n<%s>.", match_with, content)
|
48
|
+
true
|
49
|
+
end
|
50
|
+
|
51
|
+
self.message ||= content_mismatch if remaining.empty?
|
52
|
+
Nokogiri::XML::NodeSet.new(matches.document, remaining)
|
53
|
+
end
|
54
|
+
|
55
|
+
def extract_selector(values)
|
56
|
+
selector = values.shift
|
57
|
+
|
58
|
+
unless selector.is_a? String
|
59
|
+
raise ArgumentError, "Expecting a selector as the first argument"
|
60
|
+
end
|
61
|
+
|
62
|
+
context.substitute!(selector, values)
|
63
|
+
end
|
64
|
+
|
65
|
+
def equality_tests_from(comparator)
|
66
|
+
comparisons = {}
|
67
|
+
case comparator
|
68
|
+
when Hash
|
69
|
+
comparisons = comparator
|
70
|
+
when String, Regexp
|
71
|
+
comparisons[:text] = comparator
|
72
|
+
when Integer
|
73
|
+
comparisons[:count] = comparator
|
74
|
+
when Range
|
75
|
+
comparisons[:minimum] = comparator.begin
|
76
|
+
comparisons[:maximum] = comparator.end
|
77
|
+
when FalseClass
|
78
|
+
comparisons[:count] = 0
|
79
|
+
when NilClass, TrueClass
|
80
|
+
comparisons[:minimum] = 1
|
81
|
+
else raise ArgumentError, "I don't understand what you're trying to match"
|
82
|
+
end
|
83
|
+
|
84
|
+
# By default we're looking for at least one match.
|
85
|
+
if comparisons[:count]
|
86
|
+
comparisons[:minimum] = comparisons[:maximum] = comparisons[:count]
|
87
|
+
else
|
88
|
+
comparisons[:minimum] ||= 1
|
89
|
+
end
|
90
|
+
comparisons
|
91
|
+
end
|
92
|
+
|
93
|
+
def context
|
94
|
+
@context ||= SubstitutionContext.new
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class SubstitutionContext
|
2
|
+
def initialize(substitute = '?')
|
3
|
+
@substitute = substitute
|
4
|
+
@regexes = []
|
5
|
+
end
|
6
|
+
|
7
|
+
def add_regex(regex)
|
8
|
+
# Nokogiri doesn't like arbitrary values without quotes, hence inspect.
|
9
|
+
return regex.inspect unless regex.is_a?(Regexp)
|
10
|
+
@regexes.push(regex)
|
11
|
+
last_id.to_s # avoid implicit conversions of Fixnum to String
|
12
|
+
end
|
13
|
+
|
14
|
+
def last_id
|
15
|
+
@regexes.count - 1
|
16
|
+
end
|
17
|
+
|
18
|
+
def match(matches, attribute, id)
|
19
|
+
matches.find_all { |node| node[attribute] =~ @regexes[id] }
|
20
|
+
end
|
21
|
+
|
22
|
+
def substitute!(selector, values)
|
23
|
+
while !values.empty? && selector.index(@substitute)
|
24
|
+
selector.sub!(@substitute, add_regex(values.shift))
|
25
|
+
end
|
26
|
+
selector
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'rails/dom/testing/assertions/dom_assertions'
|
3
|
+
|
4
|
+
class DomAssertionsTest < ActiveSupport::TestCase
|
5
|
+
Assertion = Minitest::Assertion
|
6
|
+
|
7
|
+
include Rails::Dom::Testing::Assertions::DomAssertions
|
8
|
+
|
9
|
+
def test_responds_to_assert_dom_equal
|
10
|
+
assert respond_to?(:assert_dom_equal)
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_dom_equal
|
14
|
+
html = '<a></a>'
|
15
|
+
assert_dom_equal(html, html.dup)
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_equal_doms_with_different_order_attributes
|
19
|
+
attributes = %{<a b="hello" c="hello"></a>}
|
20
|
+
reverse_attributes = %{<a c="hello" b="hello"></a>}
|
21
|
+
assert_dom_equal(attributes, reverse_attributes)
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_dom_not_equal
|
25
|
+
assert_dom_not_equal('<a></a>', '<b></b>')
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_unequal_doms_attributes_with_different_order_and_values
|
29
|
+
attributes = %{<a b="hello" c="hello"></a>}
|
30
|
+
reverse_attributes = %{<a c="hello" b="goodbye"></a>}
|
31
|
+
assert_dom_not_equal(attributes, reverse_attributes)
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_custom_message_is_used_in_failures
|
35
|
+
message = "This is my message."
|
36
|
+
|
37
|
+
e = assert_raises(Assertion) do
|
38
|
+
assert_dom_equal('<a></a>', '<b></b>', message)
|
39
|
+
end
|
40
|
+
|
41
|
+
assert_equal e.message, message
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,281 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
require 'rails/dom/testing/assertions/selector_assertions'
|
5
|
+
|
6
|
+
class AssertSelectTest < ActiveSupport::TestCase
|
7
|
+
Assertion = Minitest::Assertion
|
8
|
+
|
9
|
+
include Rails::Dom::Testing::Assertions::SelectorAssertions
|
10
|
+
|
11
|
+
def assert_failure(message, &block)
|
12
|
+
e = assert_raises(Assertion, &block)
|
13
|
+
assert_match(message, e.message) if Regexp === message
|
14
|
+
assert_equal(message, e.message) if String === message
|
15
|
+
end
|
16
|
+
|
17
|
+
#
|
18
|
+
# Test assert select.
|
19
|
+
#
|
20
|
+
|
21
|
+
def test_assert_select
|
22
|
+
render_html %Q{<div id="1"></div><div id="2"></div>}
|
23
|
+
assert_select "div", 2
|
24
|
+
assert_failure(/Expected at least 1 element matching \"p\", found 0/) { assert_select "p" }
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_equality_integer
|
28
|
+
render_html %Q{<div id="1"></div><div id="2"></div>}
|
29
|
+
assert_failure(/Expected exactly 3 elements matching \"div\", found 2/) { assert_select "div", 3 }
|
30
|
+
assert_failure(/Expected exactly 0 elements matching \"div\", found 2/) { assert_select "div", 0 }
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_equality_true_false
|
34
|
+
render_html %Q{<div id="1"></div><div id="2"></div>}
|
35
|
+
assert_nothing_raised { assert_select "div" }
|
36
|
+
assert_raise(Assertion) { assert_select "p" }
|
37
|
+
assert_nothing_raised { assert_select "div", true }
|
38
|
+
assert_raise(Assertion) { assert_select "p", true }
|
39
|
+
assert_raise(Assertion) { assert_select "div", false }
|
40
|
+
assert_nothing_raised { assert_select "p", false }
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_equality_false_message
|
44
|
+
render_html %Q{<div id="1"></div><div id="2"></div>}
|
45
|
+
assert_failure(/Expected exactly 0 elements matching \"div\", found 2/) { assert_select "div", false }
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_equality_string_and_regexp
|
49
|
+
render_html %Q{<div id="1">foo</div><div id="2">foo</div>}
|
50
|
+
assert_nothing_raised { assert_select "div", "foo" }
|
51
|
+
assert_raise(Assertion) { assert_select "div", "bar" }
|
52
|
+
assert_nothing_raised { assert_select "div", :text=>"foo" }
|
53
|
+
assert_raise(Assertion) { assert_select "div", :text=>"bar" }
|
54
|
+
assert_nothing_raised { assert_select "div", /(foo|bar)/ }
|
55
|
+
assert_raise(Assertion) { assert_select "div", /foobar/ }
|
56
|
+
assert_nothing_raised { assert_select "div", :text=>/(foo|bar)/ }
|
57
|
+
assert_raise(Assertion) { assert_select "div", :text=>/foobar/ }
|
58
|
+
assert_raise(Assertion) { assert_select "p", :text=>/foobar/ }
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_equality_of_html
|
62
|
+
render_html %Q{<p>\n<em>"This is <strong>not</strong> a big problem,"</em> he said.\n</p>}
|
63
|
+
text = "\"This is not a big problem,\" he said."
|
64
|
+
html = "<em>\"This is <strong>not</strong> a big problem,\"</em> he said."
|
65
|
+
assert_nothing_raised { assert_select "p", text }
|
66
|
+
assert_raise(Assertion) { assert_select "p", html }
|
67
|
+
assert_nothing_raised { assert_select "p", :html=>html }
|
68
|
+
assert_raise(Assertion) { assert_select "p", :html=>text }
|
69
|
+
# No stripping for pre.
|
70
|
+
render_html %Q{<pre>\n<em>"This is <strong>not</strong> a big problem,"</em> he said.\n</pre>}
|
71
|
+
text = "\n\"This is not a big problem,\" he said.\n"
|
72
|
+
html = "\n<em>\"This is <strong>not</strong> a big problem,\"</em> he said.\n"
|
73
|
+
assert_nothing_raised { assert_select "pre", text }
|
74
|
+
assert_raise(Assertion) { assert_select "pre", html }
|
75
|
+
assert_nothing_raised { assert_select "pre", :html=>html }
|
76
|
+
assert_raise(Assertion) { assert_select "pre", :html=>text }
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_strip_textarea
|
80
|
+
render_html %Q{<textarea>\n\nfoo\n</textarea>}
|
81
|
+
assert_select "textarea", "\nfoo\n"
|
82
|
+
render_html %Q{<textarea>\nfoo</textarea>}
|
83
|
+
assert_select "textarea", "foo"
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_counts
|
87
|
+
render_html %Q{<div id="1">foo</div><div id="2">foo</div>}
|
88
|
+
assert_nothing_raised { assert_select "div", 2 }
|
89
|
+
assert_failure(/Expected exactly 3 elements matching \"div\", found 2/) do
|
90
|
+
assert_select "div", 3
|
91
|
+
end
|
92
|
+
assert_nothing_raised { assert_select "div", 1..2 }
|
93
|
+
assert_failure(/Expected between 3 and 4 elements matching \"div\", found 2/) do
|
94
|
+
assert_select "div", 3..4
|
95
|
+
end
|
96
|
+
assert_nothing_raised { assert_select "div", :count=>2 }
|
97
|
+
assert_failure(/Expected exactly 3 elements matching \"div\", found 2/) do
|
98
|
+
assert_select "div", :count=>3
|
99
|
+
end
|
100
|
+
assert_nothing_raised { assert_select "div", :minimum=>1 }
|
101
|
+
assert_nothing_raised { assert_select "div", :minimum=>2 }
|
102
|
+
assert_failure(/Expected at least 3 elements matching \"div\", found 2/) do
|
103
|
+
assert_select "div", :minimum=>3
|
104
|
+
end
|
105
|
+
assert_nothing_raised { assert_select "div", :maximum=>2 }
|
106
|
+
assert_nothing_raised { assert_select "div", :maximum=>3 }
|
107
|
+
assert_failure(/Expected at most 1 element matching \"div\", found 2/) do
|
108
|
+
assert_select "div", :maximum=>1
|
109
|
+
end
|
110
|
+
assert_nothing_raised { assert_select "div", :minimum=>1, :maximum=>2 }
|
111
|
+
assert_failure(/Expected between 3 and 4 elements matching \"div\", found 2/) do
|
112
|
+
assert_select "div", :minimum=>3, :maximum=>4
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_substitution_values
|
117
|
+
render_html %Q{<div id="1">foo</div><div id="2">foo</div>}
|
118
|
+
assert_select "div:match('id', ?)", /\d+/ do |elements|
|
119
|
+
assert_equal 2, elements.size
|
120
|
+
end
|
121
|
+
assert_select "div" do
|
122
|
+
assert_select ":match('id', ?)", /\d+/ do |elements|
|
123
|
+
assert_equal 2, elements.size
|
124
|
+
assert_select "#1"
|
125
|
+
assert_select "#2"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_nested_assert_select
|
131
|
+
render_html %Q{<div id="1">foo</div><div id="2">foo</div>}
|
132
|
+
assert_select "div" do |elements|
|
133
|
+
assert_equal 2, elements.size
|
134
|
+
assert_select elements, "#1"
|
135
|
+
assert_select elements, "#2"
|
136
|
+
end
|
137
|
+
assert_select "div" do
|
138
|
+
assert_select "div" do |elements|
|
139
|
+
assert_equal 2, elements.size
|
140
|
+
# Testing in a group is one thing
|
141
|
+
assert_select "#1,#2"
|
142
|
+
# Testing individually is another.
|
143
|
+
assert_select "#1"
|
144
|
+
assert_select "#2"
|
145
|
+
assert_select "#3", false
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
assert_failure(/Expected at least 1 element matching \"#4\", found 0\./) do
|
150
|
+
assert_select "div" do
|
151
|
+
assert_select "#4"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def test_assert_select_text_match
|
157
|
+
render_html %Q{<div id="1"><span>foo</span></div><div id="2"><span>bar</span></div>}
|
158
|
+
assert_select "div" do
|
159
|
+
assert_nothing_raised { assert_select "div", "foo" }
|
160
|
+
assert_nothing_raised { assert_select "div", "bar" }
|
161
|
+
assert_nothing_raised { assert_select "div", /\w*/ }
|
162
|
+
assert_nothing_raised { assert_select "div", :text => /\w*/, :count=>2 }
|
163
|
+
assert_raise(Assertion) { assert_select "div", :text=>"foo", :count=>2 }
|
164
|
+
assert_nothing_raised { assert_select "div", :html=>"<span>bar</span>" }
|
165
|
+
assert_nothing_raised { assert_select "div", :html=>"<span>bar</span>" }
|
166
|
+
assert_nothing_raised { assert_select "div", :html=>/\w*/ }
|
167
|
+
assert_nothing_raised { assert_select "div", :html=>/\w*/, :count=>2 }
|
168
|
+
assert_raise(Assertion) { assert_select "div", :html=>"<span>foo</span>", :count=>2 }
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
#
|
173
|
+
# Test css_select.
|
174
|
+
#
|
175
|
+
|
176
|
+
def test_css_select
|
177
|
+
render_html %Q{<div id="1"></div><div id="2"></div>}
|
178
|
+
assert_equal 2, css_select("div").size
|
179
|
+
assert_equal 0, css_select("p").size
|
180
|
+
end
|
181
|
+
|
182
|
+
def test_nested_css_select
|
183
|
+
render_html %Q{<div id="1">foo</div><div id="2">foo</div>}
|
184
|
+
assert_select "div:match('id', ?)", /\d+/ do |elements|
|
185
|
+
assert_equal 1, css_select(elements[0], "div").size
|
186
|
+
assert_equal 1, css_select(elements[1], "div").size
|
187
|
+
end
|
188
|
+
assert_select "div" do
|
189
|
+
assert_equal 2, css_select("div").size
|
190
|
+
css_select("div").each do |element|
|
191
|
+
# Testing as a group is one thing
|
192
|
+
assert !css_select("#1,#2").empty?
|
193
|
+
# Testing individually is another
|
194
|
+
assert !css_select("#1").empty?
|
195
|
+
assert !css_select("#2").empty?
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# testing invalid selectors
|
201
|
+
def test_assert_select_with_invalid_selector
|
202
|
+
render_html '<a href="http://example.com">hello</a>'
|
203
|
+
assert_deprecated do
|
204
|
+
assert_nil assert_select("[href=http://example.com]")
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def test_css_select_with_invalid_selector
|
209
|
+
render_html '<a href="http://example.com">hello</a>'
|
210
|
+
assert_deprecated do
|
211
|
+
assert_nil css_select("[href=http://example.com]")
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def test_feed_item_encoded
|
216
|
+
render_xml <<-EOF
|
217
|
+
<rss version="2.0">
|
218
|
+
<channel>
|
219
|
+
<item>
|
220
|
+
<description>
|
221
|
+
<![CDATA[
|
222
|
+
<p>Test 1</p>
|
223
|
+
]]>
|
224
|
+
</description>
|
225
|
+
</item>
|
226
|
+
<item>
|
227
|
+
<description>
|
228
|
+
<![CDATA[
|
229
|
+
<p>Test 2</p>
|
230
|
+
]]>
|
231
|
+
</description>
|
232
|
+
</item>
|
233
|
+
</channel>
|
234
|
+
</rss>
|
235
|
+
EOF
|
236
|
+
assert_select "channel item description" do
|
237
|
+
|
238
|
+
assert_select_encoded do
|
239
|
+
assert_select "p", :count=>2, :text=>/Test/
|
240
|
+
end
|
241
|
+
|
242
|
+
# Test individually.
|
243
|
+
assert_select "description" do |elements|
|
244
|
+
assert_select_encoded elements[0] do
|
245
|
+
assert_select "p", "Test 1"
|
246
|
+
end
|
247
|
+
assert_select_encoded elements[1] do
|
248
|
+
assert_select "p", "Test 2"
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
# Test that we only un-encode element itself.
|
254
|
+
assert_select "channel item" do
|
255
|
+
assert_select_encoded do
|
256
|
+
assert_select "p", 0
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
protected
|
262
|
+
def render_html(html)
|
263
|
+
fake_render(:html, html)
|
264
|
+
end
|
265
|
+
|
266
|
+
def render_xml(xml)
|
267
|
+
fake_render(:xml, xml)
|
268
|
+
end
|
269
|
+
|
270
|
+
def fake_render(content_type, content)
|
271
|
+
@html_document = if content_type == :xml
|
272
|
+
Nokogiri::XML::Document.parse(content)
|
273
|
+
else
|
274
|
+
Nokogiri::HTML::Document.parse(content)
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
def document_root_element
|
279
|
+
@html_document.root
|
280
|
+
end
|
281
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rails-dom-testing
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Rafael Mendonça França
|
8
|
+
- Kasper Timm Hansen
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-08-18 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: nokogiri
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: 1.6.0
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 1.6.0
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: activesupport
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
type: :runtime
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: bundler
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - "~>"
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '1.3'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - "~>"
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '1.3'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: rake
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: minitest
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
description: " Dom and Selector assertions for Rails applications "
|
85
|
+
email:
|
86
|
+
- rafaelmfranca@gmail.com
|
87
|
+
- kaspth@gmail.com
|
88
|
+
executables: []
|
89
|
+
extensions: []
|
90
|
+
extra_rdoc_files: []
|
91
|
+
files:
|
92
|
+
- CHANGELOG.md
|
93
|
+
- LICENSE.txt
|
94
|
+
- README.md
|
95
|
+
- lib/rails-dom-testing.rb
|
96
|
+
- lib/rails/dom/testing/assertions.rb
|
97
|
+
- lib/rails/dom/testing/assertions/dom_assertions.rb
|
98
|
+
- lib/rails/dom/testing/assertions/selector_assertions.rb
|
99
|
+
- lib/rails/dom/testing/assertions/selector_assertions/html_selector.rb
|
100
|
+
- lib/rails/dom/testing/assertions/selector_assertions/substitution_context.rb
|
101
|
+
- lib/rails/dom/testing/version.rb
|
102
|
+
- test/dom_assertions_test.rb
|
103
|
+
- test/selector_assertions_test.rb
|
104
|
+
- test/test_helper.rb
|
105
|
+
homepage: https://github.com/kaspth/rails-dom-testing
|
106
|
+
licenses:
|
107
|
+
- MIT
|
108
|
+
metadata: {}
|
109
|
+
post_install_message:
|
110
|
+
rdoc_options: []
|
111
|
+
require_paths:
|
112
|
+
- lib
|
113
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '0'
|
123
|
+
requirements: []
|
124
|
+
rubyforge_project:
|
125
|
+
rubygems_version: 2.2.2
|
126
|
+
signing_key:
|
127
|
+
specification_version: 4
|
128
|
+
summary: This gem can compare doms and assert certain elements exists in doms using
|
129
|
+
Nokogiri.
|
130
|
+
test_files:
|
131
|
+
- test/dom_assertions_test.rb
|
132
|
+
- test/selector_assertions_test.rb
|
133
|
+
- test/test_helper.rb
|