rails-dom-testing 2.0.2 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/README.md +6 -6
- data/lib/rails/dom/testing/assertions/dom_assertions.rb +28 -10
- data/lib/rails/dom/testing/assertions/selector_assertions/count_describable.rb +0 -4
- data/lib/rails/dom/testing/assertions/selector_assertions/html_selector.rb +22 -16
- data/lib/rails/dom/testing/assertions/selector_assertions/substitution_context.rb +5 -8
- data/lib/rails/dom/testing/assertions/selector_assertions.rb +54 -48
- data/lib/rails/dom/testing/assertions.rb +3 -7
- data/lib/rails/dom/testing/version.rb +1 -1
- data/test/dom_assertions_test.rb +76 -1
- data/test/selector_assertions_test.rb +33 -0
- metadata +9 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d3af7ffd9f30304ed5cc33f9d2483fc9ba0827f6aade8d3e3bcef4410cb41956
|
4
|
+
data.tar.gz: f1ba5e86a04619e0c9943ce4543dca021b1f2f8593ce2fa18b2e2e66318ed2aa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 89242830f894040fa4bfca0777099dbd41f45b48745fa155ce0084e9abd60d66d61ab3f8be307bdbe8fd543b0cac1970b0fd7b2e7205430e425866719d832774
|
7
|
+
data.tar.gz: f3398b23f429cc591c053750557135b7e5fc68cb9ba6b107b4f605c3ff2ca3e389261e060fa9a51755bc3d8b428cf7954588bf496b205fa84e10faf434dfe915
|
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
This gem is responsible for comparing HTML doms and asserting that DOM elements are present in Rails applications.
|
4
4
|
Doms are compared via `assert_dom_equal` and `assert_dom_not_equal`.
|
5
|
-
Elements are asserted via `
|
5
|
+
Elements are asserted via `assert_dom`, `assert_dom_encoded`, `assert_dom_email` and a subset of the dom can be selected with `css_select`.
|
6
6
|
The gem is developed for Rails 4.2 and above, and will not work on previous versions.
|
7
7
|
|
8
8
|
## Nokogiri::CSS::SyntaxError exceptions when upgrading to Rails 4.2:
|
@@ -41,21 +41,21 @@ assert_dom_not_equal '<h1>Portuguese</h1>', '<h1>Danish</h1>'
|
|
41
41
|
# implicitly selects from the document_root_element
|
42
42
|
css_select '.hello' # => Nokogiri::XML::NodeSet of elements with hello class
|
43
43
|
|
44
|
-
# select from a supplied node.
|
45
|
-
|
44
|
+
# select from a supplied node. assert_dom asserts elements exist.
|
45
|
+
assert_dom document_root_element.at('.hello'), '.goodbye'
|
46
46
|
|
47
47
|
# elements in CDATA encoded sections can also be selected
|
48
|
-
|
48
|
+
assert_dom_encoded '#out-of-your-element'
|
49
49
|
|
50
50
|
# assert elements within an html email exists
|
51
|
-
|
51
|
+
assert_dom_email '#you-got-mail'
|
52
52
|
```
|
53
53
|
|
54
54
|
The documentation in [selector_assertions.rb](https://github.com/rails/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.
|
55
55
|
|
56
56
|
## Read more
|
57
57
|
|
58
|
-
Under the hood the doms are parsed with Nokogiri and you'll generally be working with these two classes:
|
58
|
+
Under the hood the doms are parsed with Nokogiri, and you'll generally be working with these two classes:
|
59
59
|
- [`Nokogiri::XML::Node`](http://www.rubydoc.info/github/sparklemotion/nokogiri/Nokogiri/XML/Node)
|
60
60
|
- [`Nokogiri::XML::NodeSet`](http://www.rubydoc.info/github/sparklemotion/nokogiri/Nokogiri/XML/NodeSet)
|
61
61
|
|
@@ -7,43 +7,61 @@ module Rails
|
|
7
7
|
#
|
8
8
|
# # assert that the referenced method generates the appropriate HTML string
|
9
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)
|
10
|
+
def assert_dom_equal(expected, actual, message = nil, strict: false)
|
11
11
|
expected_dom, actual_dom = fragment(expected), fragment(actual)
|
12
12
|
message ||= "Expected: #{expected}\nActual: #{actual}"
|
13
|
-
assert compare_doms(expected_dom, actual_dom), message
|
13
|
+
assert compare_doms(expected_dom, actual_dom, strict), message
|
14
14
|
end
|
15
15
|
|
16
16
|
# The negated form of +assert_dom_equal+.
|
17
17
|
#
|
18
18
|
# # assert that the referenced method does not generate the specified HTML string
|
19
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)
|
20
|
+
def assert_dom_not_equal(expected, actual, message = nil, strict: false)
|
21
21
|
expected_dom, actual_dom = fragment(expected), fragment(actual)
|
22
22
|
message ||= "Expected: #{expected}\nActual: #{actual}"
|
23
|
-
assert_not compare_doms(expected_dom, actual_dom), message
|
23
|
+
assert_not compare_doms(expected_dom, actual_dom, strict), message
|
24
24
|
end
|
25
25
|
|
26
26
|
protected
|
27
27
|
|
28
|
-
def compare_doms(expected, actual)
|
29
|
-
|
28
|
+
def compare_doms(expected, actual, strict)
|
29
|
+
expected_children = extract_children(expected, strict)
|
30
|
+
actual_children = extract_children(actual, strict)
|
31
|
+
return false unless expected_children.size == actual_children.size
|
30
32
|
|
31
|
-
|
32
|
-
return false unless equal_children?(child,
|
33
|
+
expected_children.each_with_index do |child, i|
|
34
|
+
return false unless equal_children?(child, actual_children[i], strict)
|
33
35
|
end
|
34
36
|
|
35
37
|
true
|
36
38
|
end
|
37
39
|
|
38
|
-
def
|
40
|
+
def extract_children(node, strict)
|
41
|
+
if strict
|
42
|
+
node.children
|
43
|
+
else
|
44
|
+
node.children.reject{|n| n.text? && n.text.blank?}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def equal_children?(child, other_child, strict)
|
39
49
|
return false unless child.type == other_child.type
|
40
50
|
|
41
51
|
if child.element?
|
42
52
|
child.name == other_child.name &&
|
43
53
|
equal_attribute_nodes?(child.attribute_nodes, other_child.attribute_nodes) &&
|
44
|
-
compare_doms(child, other_child)
|
54
|
+
compare_doms(child, other_child, strict)
|
45
55
|
else
|
56
|
+
equal_child?(child, other_child, strict)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def equal_child?(child, other_child, strict)
|
61
|
+
if strict
|
46
62
|
child.to_s == other_child.to_s
|
63
|
+
else
|
64
|
+
child.to_s.split == other_child.to_s.split
|
47
65
|
end
|
48
66
|
end
|
49
67
|
|
@@ -1,13 +1,9 @@
|
|
1
|
-
require 'active_support/concern'
|
2
|
-
|
3
1
|
module Rails
|
4
2
|
module Dom
|
5
3
|
module Testing
|
6
4
|
module Assertions
|
7
5
|
module SelectorAssertions
|
8
6
|
module CountDescribable
|
9
|
-
extend ActiveSupport::Concern
|
10
|
-
|
11
7
|
private
|
12
8
|
def count_description(min, max, count) #:nodoc:
|
13
9
|
if min && max && (max != min)
|
@@ -4,6 +4,8 @@ require_relative 'substitution_context'
|
|
4
4
|
class HTMLSelector #:nodoc:
|
5
5
|
attr_reader :css_selector, :tests, :message
|
6
6
|
|
7
|
+
include Minitest::Assertions
|
8
|
+
|
7
9
|
def initialize(values, previous_selection = nil, &root_fallback)
|
8
10
|
@values = values
|
9
11
|
@root = extract_root(previous_selection, root_fallback)
|
@@ -11,6 +13,10 @@ class HTMLSelector #:nodoc:
|
|
11
13
|
@tests = extract_equality_tests
|
12
14
|
@message = @values.shift
|
13
15
|
|
16
|
+
if @message.is_a?(Hash)
|
17
|
+
raise ArgumentError, "Last argument was a Hash, which would be used for the assertion message. You probably want this to be a String, or you have the wrong type of arguments."
|
18
|
+
end
|
19
|
+
|
14
20
|
if @values.shift
|
15
21
|
raise ArgumentError, "Not expecting that last argument, you either have too many arguments, or they're the wrong type"
|
16
22
|
end
|
@@ -48,7 +54,7 @@ class HTMLSelector #:nodoc:
|
|
48
54
|
content.sub!(/\A\n/, '') if text_matches && match.name == "textarea"
|
49
55
|
|
50
56
|
next if regex_matching ? (content =~ match_with) : (content == match_with)
|
51
|
-
content_mismatch ||=
|
57
|
+
content_mismatch ||= diff(match_with, content)
|
52
58
|
true
|
53
59
|
end
|
54
60
|
|
@@ -61,7 +67,7 @@ class HTMLSelector #:nodoc:
|
|
61
67
|
|
62
68
|
if possible_root == nil
|
63
69
|
raise ArgumentError, 'First argument is either selector or element ' \
|
64
|
-
'to select, but nil found. Perhaps you called
|
70
|
+
'to select, but nil found. Perhaps you called assert_dom with ' \
|
65
71
|
'an element that does not exist?'
|
66
72
|
elsif possible_root.respond_to?(:css)
|
67
73
|
@values.shift # remove the root, so selector is the first argument
|
@@ -87,20 +93,20 @@ class HTMLSelector #:nodoc:
|
|
87
93
|
def extract_equality_tests
|
88
94
|
comparisons = {}
|
89
95
|
case comparator = @values.shift
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
96
|
+
when Hash
|
97
|
+
comparisons = comparator
|
98
|
+
when String, Regexp
|
99
|
+
comparisons[:text] = comparator
|
100
|
+
when Integer
|
101
|
+
comparisons[:count] = comparator
|
102
|
+
when Range
|
103
|
+
comparisons[:minimum] = comparator.begin
|
104
|
+
comparisons[:maximum] = comparator.end
|
105
|
+
when FalseClass
|
106
|
+
comparisons[:count] = 0
|
107
|
+
when NilClass, TrueClass
|
108
|
+
comparisons[:minimum] = 1
|
109
|
+
else raise ArgumentError, "I don't understand what you're trying to match"
|
104
110
|
end
|
105
111
|
|
106
112
|
# By default we're looking for at least one match.
|
@@ -4,13 +4,10 @@ class SubstitutionContext
|
|
4
4
|
end
|
5
5
|
|
6
6
|
def substitute!(selector, values, format_for_presentation = false)
|
7
|
-
selector
|
8
|
-
|
9
|
-
|
10
|
-
selector.sub! @substitute, matcher_for(values.shift, format_for_presentation)
|
7
|
+
selector.gsub @substitute do |match|
|
8
|
+
next match[0] if values.empty? || !substitutable?(values.first)
|
9
|
+
matcher_for(values.shift, format_for_presentation)
|
11
10
|
end
|
12
|
-
|
13
|
-
selector
|
14
11
|
end
|
15
12
|
|
16
13
|
def match(matches, attribute, matcher)
|
@@ -23,11 +20,11 @@ class SubstitutionContext
|
|
23
20
|
if format_for_presentation
|
24
21
|
value.inspect # Avoid to_s so Regexps aren't put in quotes.
|
25
22
|
else
|
26
|
-
value
|
23
|
+
"\"#{value}\""
|
27
24
|
end
|
28
25
|
end
|
29
26
|
|
30
27
|
def substitutable?(value)
|
31
|
-
|
28
|
+
[ Symbol, Numeric, String, Regexp ].any? { |type| value.is_a? type }
|
32
29
|
end
|
33
30
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'active_support/deprecation'
|
2
1
|
require_relative 'selector_assertions/count_describable'
|
3
2
|
require_relative 'selector_assertions/html_selector'
|
4
3
|
|
@@ -6,9 +5,9 @@ module Rails
|
|
6
5
|
module Dom
|
7
6
|
module Testing
|
8
7
|
module Assertions
|
9
|
-
# Adds the +
|
8
|
+
# Adds the +assert_dom+ method for use in Rails functional
|
10
9
|
# test cases, which can be used to make assertions on the response HTML of a controller
|
11
|
-
# action. You can also call +
|
10
|
+
# action. You can also call +assert_dom+ within another +assert_dom+ to
|
12
11
|
# make assertions on elements selected by the enclosing assertion.
|
13
12
|
#
|
14
13
|
# Use +css_select+ to select elements without making an assertions, either
|
@@ -16,8 +15,8 @@ module Rails
|
|
16
15
|
#
|
17
16
|
# In addition to HTML responses, you can make the following assertions:
|
18
17
|
#
|
19
|
-
# * +
|
20
|
-
# * +
|
18
|
+
# * +assert_dom_encoded+ - Assertions on HTML encoded inside XML, for example for dealing with feed item descriptions.
|
19
|
+
# * +assert_dom_email+ - Assertions on the HTML body of an e-mail.
|
21
20
|
module SelectorAssertions
|
22
21
|
|
23
22
|
# Select and return all matching elements.
|
@@ -70,38 +69,41 @@ module Rails
|
|
70
69
|
# starting from (and including) that element and all its children in
|
71
70
|
# depth-first order.
|
72
71
|
#
|
73
|
-
# If no element is specified +
|
72
|
+
# If no element is specified +assert_dom+ selects from
|
74
73
|
# the element returned in +document_root_element+
|
75
|
-
# unless +
|
76
|
-
# Override +document_root_element+ to tell +
|
74
|
+
# unless +assert_dom+ is called from within an +assert_dom+ block.
|
75
|
+
# Override +document_root_element+ to tell +assert_dom+ what to select from.
|
77
76
|
# The default implementation raises an exception explaining this.
|
78
77
|
#
|
79
|
-
# When called with a block +
|
80
|
-
# to the block. Calling +
|
78
|
+
# When called with a block +assert_dom+ passes an array of selected elements
|
79
|
+
# to the block. Calling +assert_dom+ from the block, with no element specified,
|
81
80
|
# runs the assertion on the complete set of elements selected by the enclosing assertion.
|
82
|
-
# Alternatively the array may be iterated through so that +
|
81
|
+
# Alternatively the array may be iterated through so that +assert_dom+ can be called
|
83
82
|
# separately for each element.
|
84
83
|
#
|
85
84
|
#
|
86
85
|
# ==== Example
|
87
86
|
# If the response contains two ordered lists, each with four list elements then:
|
88
|
-
#
|
87
|
+
# assert_dom "ol" do |elements|
|
89
88
|
# elements.each do |element|
|
90
|
-
#
|
89
|
+
# assert_dom element, "li", 4
|
91
90
|
# end
|
92
91
|
# end
|
93
92
|
#
|
94
93
|
# will pass, as will:
|
95
|
-
#
|
96
|
-
#
|
94
|
+
# assert_dom "ol" do
|
95
|
+
# assert_dom "li", 8
|
97
96
|
# end
|
98
97
|
#
|
99
|
-
# The selector may be a CSS selector expression (String) or an expression
|
98
|
+
# The selector may be a CSS selector expression (String, Symbol, or Numeric) or an expression
|
100
99
|
# with substitution values (Array).
|
101
100
|
# Substitution uses a custom pseudo class match. Pass in whatever attribute you want to match (enclosed in quotes) and a ? for the substitution.
|
102
|
-
#
|
101
|
+
# assert_dom returns nil if called with an invalid css selector.
|
103
102
|
#
|
104
|
-
#
|
103
|
+
# assert_dom "div:match('id', ?)", "id_string"
|
104
|
+
# assert_dom "div:match('id', ?)", :id_string
|
105
|
+
# assert_dom "div:match('id', ?)", 1
|
106
|
+
# assert_dom "div:match('id', ?)", /\d+/
|
105
107
|
#
|
106
108
|
# === Equality Tests
|
107
109
|
#
|
@@ -133,32 +135,32 @@ module Rails
|
|
133
135
|
# evaluated the block is called with an array of all matched elements.
|
134
136
|
#
|
135
137
|
# # At least one form element
|
136
|
-
#
|
138
|
+
# assert_dom "form"
|
137
139
|
#
|
138
140
|
# # Form element includes four input fields
|
139
|
-
#
|
141
|
+
# assert_dom "form input", 4
|
140
142
|
#
|
141
143
|
# # Page title is "Welcome"
|
142
|
-
#
|
144
|
+
# assert_dom "title", "Welcome"
|
143
145
|
#
|
144
146
|
# # Page title is "Welcome" and there is only one title element
|
145
|
-
#
|
147
|
+
# assert_dom "title", {count: 1, text: "Welcome"},
|
146
148
|
# "Wrong title or more than one title element"
|
147
149
|
#
|
148
150
|
# # Page contains no forms
|
149
|
-
#
|
151
|
+
# assert_dom "form", false, "This page must contain no forms"
|
150
152
|
#
|
151
153
|
# # Test the content and style
|
152
|
-
#
|
154
|
+
# assert_dom "body div.header ul.menu"
|
153
155
|
#
|
154
156
|
# # Use substitution values
|
155
|
-
#
|
157
|
+
# assert_dom "ol>li:match('id', ?)", /item-\d+/
|
156
158
|
#
|
157
159
|
# # All input fields in the form have a name
|
158
|
-
#
|
159
|
-
#
|
160
|
+
# assert_dom "form input" do
|
161
|
+
# assert_dom ":match('name', ?)", /.+/ # Not empty
|
160
162
|
# end
|
161
|
-
def
|
163
|
+
def assert_dom(*args, &block)
|
162
164
|
@selected ||= nil
|
163
165
|
|
164
166
|
selector = HTMLSelector.new(args, @selected) { nodeset document_root_element }
|
@@ -175,6 +177,7 @@ module Rails
|
|
175
177
|
nest_selection(matches, &block) if block_given? && !matches.empty?
|
176
178
|
end
|
177
179
|
end
|
180
|
+
alias_method :assert_select, :assert_dom
|
178
181
|
|
179
182
|
# Extracts the content of an element, treats it as encoded HTML and runs
|
180
183
|
# nested assertion on it.
|
@@ -187,30 +190,30 @@ module Rails
|
|
187
190
|
# element +encoded+. It then calls the block with all un-encoded elements.
|
188
191
|
#
|
189
192
|
# # Selects all bold tags from within the title of an Atom feed's entries (perhaps to nab a section name prefix)
|
190
|
-
#
|
193
|
+
# assert_dom "feed[xmlns='http://www.w3.org/2005/Atom']" do
|
191
194
|
# # Select each entry item and then the title item
|
192
|
-
#
|
195
|
+
# assert_dom "entry>title" do
|
193
196
|
# # Run assertions on the encoded title elements
|
194
|
-
#
|
195
|
-
#
|
197
|
+
# assert_dom_encoded do
|
198
|
+
# assert_dom "b"
|
196
199
|
# end
|
197
200
|
# end
|
198
201
|
# end
|
199
202
|
#
|
200
203
|
#
|
201
204
|
# # Selects all paragraph tags from within the description of an RSS feed
|
202
|
-
#
|
205
|
+
# assert_dom "rss[version=2.0]" do
|
203
206
|
# # Select description element of each feed item.
|
204
|
-
#
|
207
|
+
# assert_dom "channel>item>description" do
|
205
208
|
# # Run assertions on the encoded elements.
|
206
|
-
#
|
207
|
-
#
|
209
|
+
# assert_dom_encoded do
|
210
|
+
# assert_dom "p"
|
208
211
|
# end
|
209
212
|
# end
|
210
213
|
# end
|
211
|
-
def
|
214
|
+
def assert_dom_encoded(element = nil, &block)
|
212
215
|
if !element && !@selected
|
213
|
-
raise ArgumentError, "Element is required when called from a nonnested
|
216
|
+
raise ArgumentError, "Element is required when called from a nonnested assert_dom"
|
214
217
|
end
|
215
218
|
|
216
219
|
content = nodeset(element || @selected).map do |elem|
|
@@ -224,27 +227,28 @@ module Rails
|
|
224
227
|
if content.empty?
|
225
228
|
yield selected
|
226
229
|
else
|
227
|
-
|
230
|
+
assert_dom ":root", &block
|
228
231
|
end
|
229
232
|
end
|
230
233
|
end
|
234
|
+
alias_method :assert_select_encoded, :assert_dom_encoded
|
231
235
|
|
232
236
|
# Extracts the body of an email and runs nested assertions on it.
|
233
237
|
#
|
234
238
|
# You must enable deliveries for this assertion to work, use:
|
235
239
|
# ActionMailer::Base.perform_deliveries = true
|
236
240
|
#
|
237
|
-
#
|
238
|
-
#
|
241
|
+
# assert_dom_email do
|
242
|
+
# assert_dom "h1", "Email alert"
|
239
243
|
# end
|
240
244
|
#
|
241
|
-
#
|
242
|
-
# items =
|
245
|
+
# assert_dom_email do
|
246
|
+
# items = assert_dom "ol>li"
|
243
247
|
# items.each do
|
244
248
|
# # Work with items here...
|
245
249
|
# end
|
246
250
|
# end
|
247
|
-
def
|
251
|
+
def assert_dom_email(&block)
|
248
252
|
deliveries = ActionMailer::Base.deliveries
|
249
253
|
assert !deliveries.empty?, "No e-mail in delivery list"
|
250
254
|
|
@@ -252,25 +256,26 @@ module Rails
|
|
252
256
|
(delivery.parts.empty? ? [delivery] : delivery.parts).each do |part|
|
253
257
|
if part["Content-Type"].to_s =~ /^text\/html\W/
|
254
258
|
root = Nokogiri::HTML::DocumentFragment.parse(part.body.to_s)
|
255
|
-
|
259
|
+
assert_dom root, ":root", &block
|
256
260
|
end
|
257
261
|
end
|
258
262
|
end
|
259
263
|
end
|
264
|
+
alias_method :assert_select_email, :assert_dom_email
|
260
265
|
|
261
266
|
private
|
262
267
|
include CountDescribable
|
263
268
|
|
264
269
|
def document_root_element
|
265
270
|
raise NotImplementedError, 'Implementing document_root_element makes ' \
|
266
|
-
'
|
271
|
+
'assert_dom work without needing to specify an element to select from.'
|
267
272
|
end
|
268
273
|
|
269
274
|
# +equals+ must contain :minimum, :maximum and :count keys
|
270
275
|
def assert_size_match!(size, equals, css_selector, message = nil)
|
271
276
|
min, max, count = equals[:minimum], equals[:maximum], equals[:count]
|
272
277
|
|
273
|
-
message ||= %(Expected #{count_description(min, max, count)} matching
|
278
|
+
message ||= %(Expected #{count_description(min, max, count)} matching #{css_selector.inspect}, found #{size})
|
274
279
|
if count
|
275
280
|
assert_equal count, size, message
|
276
281
|
else
|
@@ -280,7 +285,7 @@ module Rails
|
|
280
285
|
end
|
281
286
|
|
282
287
|
def nest_selection(selection)
|
283
|
-
# Set @selected to allow nested
|
288
|
+
# Set @selected to allow nested assert_dom.
|
284
289
|
# Can be nested several levels deep.
|
285
290
|
old_selected, @selected = @selected, selection
|
286
291
|
yield @selected
|
@@ -292,6 +297,7 @@ module Rails
|
|
292
297
|
if node.is_a?(Nokogiri::XML::NodeSet)
|
293
298
|
node
|
294
299
|
else
|
300
|
+
node ||= Nokogiri::HTML::Document.new
|
295
301
|
Nokogiri::XML::NodeSet.new(node.document, [node])
|
296
302
|
end
|
297
303
|
end
|
@@ -1,18 +1,14 @@
|
|
1
|
-
require 'active_support/concern'
|
2
1
|
require 'nokogiri'
|
2
|
+
require 'rails/dom/testing/assertions/dom_assertions'
|
3
|
+
require 'rails/dom/testing/assertions/selector_assertions'
|
3
4
|
|
4
5
|
module Rails
|
5
6
|
module Dom
|
6
7
|
module Testing
|
7
8
|
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
9
|
include DomAssertions
|
14
10
|
include SelectorAssertions
|
15
11
|
end
|
16
12
|
end
|
17
13
|
end
|
18
|
-
end
|
14
|
+
end
|
data/test/dom_assertions_test.rb
CHANGED
@@ -47,4 +47,79 @@ class DomAssertionsTest < ActiveSupport::TestCase
|
|
47
47
|
%{<a><b c="2" /></a>}
|
48
48
|
)
|
49
49
|
end
|
50
|
-
|
50
|
+
|
51
|
+
def test_dom_equal_with_whitespace_strict
|
52
|
+
canonical = %{<a><b>hello</b> world</a>}
|
53
|
+
assert_dom_not_equal(canonical, %{<a>\n<b>hello\n </b> world</a>}, strict: true)
|
54
|
+
assert_dom_not_equal(canonical, %{<a> \n <b>\n hello</b> world</a>}, strict: true)
|
55
|
+
assert_dom_not_equal(canonical, %{<a>\n\t<b>hello</b> world</a>}, strict: true)
|
56
|
+
assert_dom_equal(canonical, %{<a><b>hello</b> world</a>}, strict: true)
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_dom_equal_with_whitespace
|
60
|
+
canonical = %{<a><b>hello</b> world</a>}
|
61
|
+
assert_dom_equal(canonical, %{<a>\n<b>hello\n </b> world</a>})
|
62
|
+
assert_dom_equal(canonical, %{<a>\n<b>hello </b>\nworld</a>})
|
63
|
+
assert_dom_equal(canonical, %{<a> \n <b>\n hello</b> world</a>})
|
64
|
+
assert_dom_equal(canonical, %{<a> \n <b> hello </b>world</a>})
|
65
|
+
assert_dom_equal(canonical, %{<a> \n <b>hello </b>world\n</a>\n})
|
66
|
+
assert_dom_equal(canonical, %{<a>\n\t<b>hello</b> world</a>})
|
67
|
+
assert_dom_equal(canonical, %{<a>\n\t<b>hello </b>\n\tworld</a>})
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_dom_equal_with_attribute_whitespace
|
71
|
+
canonical = %(<div data-wow="Don't strip this">)
|
72
|
+
assert_dom_equal(canonical, %(<div data-wow="Don't strip this">))
|
73
|
+
assert_dom_not_equal(canonical, %(<div data-wow="Don't strip this">))
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_dom_equal_with_indentation
|
77
|
+
canonical = %{<a>hello <b>cruel</b> world</a>}
|
78
|
+
assert_dom_equal(canonical, <<-HTML)
|
79
|
+
<a>
|
80
|
+
hello
|
81
|
+
<b>cruel</b>
|
82
|
+
world
|
83
|
+
</a>
|
84
|
+
HTML
|
85
|
+
|
86
|
+
assert_dom_equal(canonical, <<-HTML)
|
87
|
+
<a>
|
88
|
+
hello
|
89
|
+
<b>cruel</b>
|
90
|
+
world
|
91
|
+
</a>
|
92
|
+
HTML
|
93
|
+
|
94
|
+
assert_dom_equal(canonical, <<-HTML)
|
95
|
+
<a>hello
|
96
|
+
<b>
|
97
|
+
cruel
|
98
|
+
</b>
|
99
|
+
world</a>
|
100
|
+
HTML
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_dom_equal_with_surrounding_whitespace
|
104
|
+
canonical = %{<p>Lorem ipsum dolor</p><p>sit amet, consectetur adipiscing elit</p>}
|
105
|
+
assert_dom_equal(canonical, <<-HTML)
|
106
|
+
<p>
|
107
|
+
Lorem
|
108
|
+
ipsum
|
109
|
+
dolor
|
110
|
+
</p>
|
111
|
+
|
112
|
+
<p>
|
113
|
+
sit amet,
|
114
|
+
consectetur
|
115
|
+
adipiscing elit
|
116
|
+
</p>
|
117
|
+
HTML
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_dom_not_equal_with_interior_whitespace
|
121
|
+
with_space = %{<a><b>hello world</b></a>}
|
122
|
+
without_space = %{<a><b>helloworld</b></a>}
|
123
|
+
assert_dom_not_equal(with_space, without_space)
|
124
|
+
end
|
125
|
+
end
|
@@ -135,6 +135,21 @@ class AssertSelectTest < ActiveSupport::TestCase
|
|
135
135
|
end
|
136
136
|
end
|
137
137
|
|
138
|
+
def test_multiple_substitution_values
|
139
|
+
render_html '<input name="foo[12]" value="34">'
|
140
|
+
assert_select ":match('name', ?):match('value', ?)", /\w+\[\d+\]/, /\d+/
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_substitution_values_with_values_other_than_string_or_regexp
|
144
|
+
render_html %Q{<div id="id_string">symbol</div><div id="1">numeric</div>}
|
145
|
+
assert_select "div:match('id', ?)", :id_string do |elements|
|
146
|
+
assert_equal 1, elements.size
|
147
|
+
end
|
148
|
+
assert_select "div:match('id', ?)", 1 do |elements|
|
149
|
+
assert_equal 1, elements.size
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
138
153
|
def test_assert_select_root_html
|
139
154
|
render_html '<a></a>'
|
140
155
|
|
@@ -302,6 +317,24 @@ EOF
|
|
302
317
|
assert_select '.foo'
|
303
318
|
end
|
304
319
|
|
320
|
+
def test_assert_select_with_extra_argument
|
321
|
+
render_html '<html><head><title>Welcome</title></head><body><div></div></body></html>'
|
322
|
+
|
323
|
+
assert_raises ArgumentError do
|
324
|
+
assert_select "title", "Welcome", count: 1
|
325
|
+
end
|
326
|
+
|
327
|
+
assert_select "title", text: "Welcome", count: 1
|
328
|
+
end
|
329
|
+
|
330
|
+
def test_assert_select_on_blank_response
|
331
|
+
render_html ""
|
332
|
+
assert_select "div", 0
|
333
|
+
assert_failure(/Expected exactly 1 element matching \"div\", found 0./) do
|
334
|
+
assert_select "div", 1
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
305
338
|
protected
|
306
339
|
def render_html(html)
|
307
340
|
fake_render(:html, html)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails-dom-testing
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rafael Mendonça França
|
@@ -9,20 +9,20 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2023-06-30 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: nokogiri
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
|
-
- - "
|
18
|
+
- - ">="
|
19
19
|
- !ruby/object:Gem::Version
|
20
20
|
version: '1.6'
|
21
21
|
type: :runtime
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
|
-
- - "
|
25
|
+
- - ">="
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: '1.6'
|
28
28
|
- !ruby/object:Gem::Dependency
|
@@ -31,32 +31,26 @@ dependencies:
|
|
31
31
|
requirements:
|
32
32
|
- - ">="
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version:
|
35
|
-
- - "<"
|
36
|
-
- !ruby/object:Gem::Version
|
37
|
-
version: '6.0'
|
34
|
+
version: 5.0.0
|
38
35
|
type: :runtime
|
39
36
|
prerelease: false
|
40
37
|
version_requirements: !ruby/object:Gem::Requirement
|
41
38
|
requirements:
|
42
39
|
- - ">="
|
43
40
|
- !ruby/object:Gem::Version
|
44
|
-
version:
|
45
|
-
- - "<"
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '6.0'
|
41
|
+
version: 5.0.0
|
48
42
|
- !ruby/object:Gem::Dependency
|
49
43
|
name: bundler
|
50
44
|
requirement: !ruby/object:Gem::Requirement
|
51
45
|
requirements:
|
52
|
-
- - "
|
46
|
+
- - ">="
|
53
47
|
- !ruby/object:Gem::Version
|
54
48
|
version: '1.3'
|
55
49
|
type: :development
|
56
50
|
prerelease: false
|
57
51
|
version_requirements: !ruby/object:Gem::Requirement
|
58
52
|
requirements:
|
59
|
-
- - "
|
53
|
+
- - ">="
|
60
54
|
- !ruby/object:Gem::Version
|
61
55
|
version: '1.3'
|
62
56
|
- !ruby/object:Gem::Dependency
|
@@ -128,8 +122,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
128
122
|
- !ruby/object:Gem::Version
|
129
123
|
version: '0'
|
130
124
|
requirements: []
|
131
|
-
|
132
|
-
rubygems_version: 2.6.8
|
125
|
+
rubygems_version: 3.4.10
|
133
126
|
signing_key:
|
134
127
|
specification_version: 4
|
135
128
|
summary: Dom and Selector assertions for Rails applications
|