rails-dom-testing 2.0.3 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +44 -26
- data/lib/rails/dom/testing/assertions/dom_assertions.rb +82 -18
- data/lib/rails/dom/testing/assertions/selector_assertions/html_selector.rb +129 -111
- data/lib/rails/dom/testing/assertions/selector_assertions/substitution_context.rb +36 -25
- data/lib/rails/dom/testing/assertions/selector_assertions.rb +287 -233
- data/lib/rails/dom/testing/assertions.rb +5 -8
- data/lib/rails/dom/testing/railtie.rb +14 -0
- data/lib/rails/dom/testing/version.rb +3 -1
- data/lib/rails/dom/testing.rb +52 -0
- data/lib/rails-dom-testing.rb +4 -1
- data/test/dom_assertions_test.rb +169 -6
- data/test/parser_selection_test.rb +75 -0
- data/test/selector_assertions_test.rb +152 -68
- data/test/test_helper.rb +21 -4
- metadata +20 -32
- data/lib/rails/dom/testing/assertions/selector_assertions/count_describable.rb +0 -32
@@ -1,14 +1,14 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require_relative
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "selector_assertions/html_selector"
|
4
4
|
|
5
5
|
module Rails
|
6
6
|
module Dom
|
7
7
|
module Testing
|
8
8
|
module Assertions
|
9
|
-
# Adds the +
|
9
|
+
# Adds the +assert_dom+ method for use in Rails functional
|
10
10
|
# test cases, which can be used to make assertions on the response HTML of a controller
|
11
|
-
# action. You can also call +
|
11
|
+
# action. You can also call +assert_dom+ within another +assert_dom+ to
|
12
12
|
# make assertions on elements selected by the enclosing assertion.
|
13
13
|
#
|
14
14
|
# Use +css_select+ to select elements without making an assertions, either
|
@@ -16,261 +16,298 @@ module Rails
|
|
16
16
|
#
|
17
17
|
# In addition to HTML responses, you can make the following assertions:
|
18
18
|
#
|
19
|
-
# * +
|
20
|
-
# * +
|
19
|
+
# * +assert_dom_encoded+ - Assertions on HTML encoded inside XML, for example for dealing with feed item descriptions.
|
20
|
+
# * +assert_dom_email+ - Assertions on the HTML body of an e-mail.
|
21
21
|
module SelectorAssertions
|
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?
|
22
60
|
|
23
|
-
|
24
|
-
#
|
25
|
-
# If called with a single argument, uses that argument as a selector.
|
26
|
-
# Called without an element +css_select+ selects from
|
27
|
-
# the element returned in +document_root_element+
|
28
|
-
#
|
29
|
-
# The default implementation of +document_root_element+ raises an exception explaining this.
|
30
|
-
#
|
31
|
-
# Returns an empty Nokogiri::XML::NodeSet if no match is found.
|
32
|
-
#
|
33
|
-
# If called with two arguments, uses the first argument as the root
|
34
|
-
# element and the second argument as the selector. Attempts to match the
|
35
|
-
# root element and any of its children.
|
36
|
-
# Returns an empty Nokogiri::XML::NodeSet if no match is found.
|
37
|
-
#
|
38
|
-
# The selector may be a CSS selector expression (String).
|
39
|
-
# css_select returns nil if called with an invalid css selector.
|
40
|
-
#
|
41
|
-
# # Selects all div tags
|
42
|
-
# divs = css_select("div")
|
43
|
-
#
|
44
|
-
# # Selects all paragraph tags and does something interesting
|
45
|
-
# pars = css_select("p")
|
46
|
-
# pars.each do |par|
|
47
|
-
# # Do something fun with paragraphs here...
|
48
|
-
# end
|
49
|
-
#
|
50
|
-
# # Selects all list items in unordered lists
|
51
|
-
# items = css_select("ul>li")
|
52
|
-
#
|
53
|
-
# # Selects all form tags and then all inputs inside the form
|
54
|
-
# forms = css_select("form")
|
55
|
-
# forms.each do |form|
|
56
|
-
# inputs = css_select(form, "input")
|
57
|
-
# ...
|
58
|
-
# end
|
59
|
-
def css_select(*args)
|
60
|
-
raise ArgumentError, "you at least need a selector argument" if args.empty?
|
61
|
+
root = args.size == 1 ? document_root_element : args.shift
|
61
62
|
|
62
|
-
|
63
|
+
nodeset(root).css(args.first)
|
64
|
+
end
|
63
65
|
|
64
|
-
|
65
|
-
|
66
|
+
# An assertion that selects elements and makes one or more equality tests.
|
67
|
+
#
|
68
|
+
# If the first argument is an element, selects all matching elements
|
69
|
+
# starting from (and including) that element and all its children in
|
70
|
+
# depth-first order.
|
71
|
+
#
|
72
|
+
# If no element is specified +assert_dom+ selects from
|
73
|
+
# the element returned in +document_root_element+
|
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.
|
76
|
+
# The default implementation raises an exception explaining this.
|
77
|
+
#
|
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,
|
80
|
+
# runs the assertion on the complete set of elements selected by the enclosing assertion.
|
81
|
+
# Alternatively the array may be iterated through so that +assert_dom+ can be called
|
82
|
+
# separately for each element.
|
83
|
+
#
|
84
|
+
#
|
85
|
+
# ==== Example
|
86
|
+
# If the response contains two ordered lists, each with four list elements then:
|
87
|
+
# assert_dom "ol" do |elements|
|
88
|
+
# elements.each do |element|
|
89
|
+
# assert_dom element, "li", 4
|
90
|
+
# end
|
91
|
+
# end
|
92
|
+
#
|
93
|
+
# will pass, as will:
|
94
|
+
# assert_dom "ol" do
|
95
|
+
# assert_dom "li", 8
|
96
|
+
# end
|
97
|
+
#
|
98
|
+
# The selector may be a CSS selector expression (String, Symbol, or Numeric) or an expression
|
99
|
+
# with substitution values (Array).
|
100
|
+
# Substitution uses a custom pseudo class match. Pass in whatever attribute you want to match (enclosed in quotes) and a ? for the substitution.
|
101
|
+
# assert_dom returns nil if called with an invalid css selector.
|
102
|
+
#
|
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+/
|
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_dom "form"
|
139
|
+
#
|
140
|
+
# # Form element includes four input fields
|
141
|
+
# assert_dom "form input", 4
|
142
|
+
#
|
143
|
+
# # Page title is "Welcome"
|
144
|
+
# assert_dom "title", "Welcome"
|
145
|
+
#
|
146
|
+
# # Page title is "Welcome" and there is only one title element
|
147
|
+
# assert_dom "title", {count: 1, text: "Welcome"},
|
148
|
+
# "Wrong title or more than one title element"
|
149
|
+
#
|
150
|
+
# # Page contains no forms
|
151
|
+
# assert_dom "form", false, "This page must contain no forms"
|
152
|
+
#
|
153
|
+
# # Test the content and style
|
154
|
+
# assert_dom "body div.header ul.menu"
|
155
|
+
#
|
156
|
+
# # Use substitution values
|
157
|
+
# assert_dom "ol>li:match('id', ?)", /item-\d+/
|
158
|
+
#
|
159
|
+
# # All input fields in the form have a name
|
160
|
+
# assert_dom "form input" do
|
161
|
+
# assert_dom ":match('name', ?)", /.+/ # Not empty
|
162
|
+
# end
|
163
|
+
def assert_dom(*args, &block)
|
164
|
+
@selected ||= nil
|
66
165
|
|
67
|
-
|
68
|
-
#
|
69
|
-
# If the first argument is an element, selects all matching elements
|
70
|
-
# starting from (and including) that element and all its children in
|
71
|
-
# depth-first order.
|
72
|
-
#
|
73
|
-
# If no element is specified +assert_select+ selects from
|
74
|
-
# the element returned in +document_root_element+
|
75
|
-
# unless +assert_select+ is called from within an +assert_select+ block.
|
76
|
-
# Override +document_root_element+ to tell +assert_select+ what to select from.
|
77
|
-
# The default implementation raises an exception explaining this.
|
78
|
-
#
|
79
|
-
# When called with a block +assert_select+ passes an array of selected elements
|
80
|
-
# to the block. Calling +assert_select+ from the block, with no element specified,
|
81
|
-
# runs the assertion on the complete set of elements selected by the enclosing assertion.
|
82
|
-
# Alternatively the array may be iterated through so that +assert_select+ can be called
|
83
|
-
# separately for each element.
|
84
|
-
#
|
85
|
-
#
|
86
|
-
# ==== Example
|
87
|
-
# If the response contains two ordered lists, each with four list elements then:
|
88
|
-
# assert_select "ol" do |elements|
|
89
|
-
# elements.each do |element|
|
90
|
-
# assert_select element, "li", 4
|
91
|
-
# end
|
92
|
-
# end
|
93
|
-
#
|
94
|
-
# will pass, as will:
|
95
|
-
# assert_select "ol" do
|
96
|
-
# assert_select "li", 8
|
97
|
-
# end
|
98
|
-
#
|
99
|
-
# The selector may be a CSS selector expression (String) or an expression
|
100
|
-
# with substitution values (Array).
|
101
|
-
# Substitution uses a custom pseudo class match. Pass in whatever attribute you want to match (enclosed in quotes) and a ? for the substitution.
|
102
|
-
# assert_select returns nil if called with an invalid css selector.
|
103
|
-
#
|
104
|
-
# assert_select "div:match('id', ?)", /\d+/
|
105
|
-
#
|
106
|
-
# === Equality Tests
|
107
|
-
#
|
108
|
-
# The equality test may be one of the following:
|
109
|
-
# * <tt>true</tt> - Assertion is true if at least one element selected.
|
110
|
-
# * <tt>false</tt> - Assertion is true if no element selected.
|
111
|
-
# * <tt>String/Regexp</tt> - Assertion is true if the text value of at least
|
112
|
-
# one element matches the string or regular expression.
|
113
|
-
# * <tt>Integer</tt> - Assertion is true if exactly that number of
|
114
|
-
# elements are selected.
|
115
|
-
# * <tt>Range</tt> - Assertion is true if the number of selected
|
116
|
-
# elements fit the range.
|
117
|
-
# If no equality test specified, the assertion is true if at least one
|
118
|
-
# element selected.
|
119
|
-
#
|
120
|
-
# To perform more than one equality tests, use a hash with the following keys:
|
121
|
-
# * <tt>:text</tt> - Narrow the selection to elements that have this text
|
122
|
-
# value (string or regexp).
|
123
|
-
# * <tt>:html</tt> - Narrow the selection to elements that have this HTML
|
124
|
-
# content (string or regexp).
|
125
|
-
# * <tt>:count</tt> - Assertion is true if the number of selected elements
|
126
|
-
# is equal to this value.
|
127
|
-
# * <tt>:minimum</tt> - Assertion is true if the number of selected
|
128
|
-
# elements is at least this value.
|
129
|
-
# * <tt>:maximum</tt> - Assertion is true if the number of selected
|
130
|
-
# elements is at most this value.
|
131
|
-
#
|
132
|
-
# If the method is called with a block, once all equality tests are
|
133
|
-
# evaluated the block is called with an array of all matched elements.
|
134
|
-
#
|
135
|
-
# # At least one form element
|
136
|
-
# assert_select "form"
|
137
|
-
#
|
138
|
-
# # Form element includes four input fields
|
139
|
-
# assert_select "form input", 4
|
140
|
-
#
|
141
|
-
# # Page title is "Welcome"
|
142
|
-
# assert_select "title", "Welcome"
|
143
|
-
#
|
144
|
-
# # Page title is "Welcome" and there is only one title element
|
145
|
-
# assert_select "title", {count: 1, text: "Welcome"},
|
146
|
-
# "Wrong title or more than one title element"
|
147
|
-
#
|
148
|
-
# # Page contains no forms
|
149
|
-
# assert_select "form", false, "This page must contain no forms"
|
150
|
-
#
|
151
|
-
# # Test the content and style
|
152
|
-
# assert_select "body div.header ul.menu"
|
153
|
-
#
|
154
|
-
# # Use substitution values
|
155
|
-
# assert_select "ol>li:match('id', ?)", /item-\d+/
|
156
|
-
#
|
157
|
-
# # All input fields in the form have a name
|
158
|
-
# assert_select "form input" do
|
159
|
-
# assert_select ":match('name', ?)", /.+/ # Not empty
|
160
|
-
# end
|
161
|
-
def assert_select(*args, &block)
|
162
|
-
@selected ||= nil
|
163
|
-
|
164
|
-
selector = HTMLSelector.new(args, @selected) { nodeset document_root_element }
|
166
|
+
selector = HTMLSelector.new(args, @selected) { nodeset document_root_element }
|
165
167
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
168
|
+
if selector.selecting_no_body?
|
169
|
+
assert true
|
170
|
+
return
|
171
|
+
end
|
170
172
|
|
171
|
-
|
172
|
-
|
173
|
-
|
173
|
+
selector.select.tap do |matches|
|
174
|
+
assert_size_match!(matches.size, selector.tests,
|
175
|
+
selector.css_selector, selector.message)
|
174
176
|
|
175
|
-
|
177
|
+
nest_selection(matches, &block) if block_given? && !matches.empty?
|
178
|
+
end
|
176
179
|
end
|
177
|
-
|
180
|
+
alias_method :assert_select, :assert_dom
|
178
181
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
182
|
+
# Extracts the content of an element, treats it as encoded HTML and runs
|
183
|
+
# nested assertion on it.
|
184
|
+
#
|
185
|
+
# You typically call this method within another assertion to operate on
|
186
|
+
# all currently selected elements. You can also pass an element or array
|
187
|
+
# of elements.
|
188
|
+
#
|
189
|
+
# The content of each element is un-encoded, and wrapped in the root
|
190
|
+
# element +encoded+. It then calls the block with all un-encoded elements.
|
191
|
+
#
|
192
|
+
# # Selects all bold tags from within the title of an Atom feed's entries (perhaps to nab a section name prefix)
|
193
|
+
# assert_dom "feed[xmlns='http://www.w3.org/2005/Atom']" do
|
194
|
+
# # Select each entry item and then the title item
|
195
|
+
# assert_dom "entry>title" do
|
196
|
+
# # Run assertions on the encoded title elements
|
197
|
+
# assert_dom_encoded do
|
198
|
+
# assert_dom "b"
|
199
|
+
# end
|
200
|
+
# end
|
201
|
+
# end
|
202
|
+
#
|
203
|
+
#
|
204
|
+
# # Selects all paragraph tags from within the description of an RSS feed
|
205
|
+
# assert_dom "rss[version=2.0]" do
|
206
|
+
# # Select description element of each feed item.
|
207
|
+
# assert_dom "channel>item>description" do
|
208
|
+
# # Run assertions on the encoded elements.
|
209
|
+
# assert_dom_encoded do
|
210
|
+
# assert_dom "p"
|
211
|
+
# end
|
212
|
+
# end
|
213
|
+
# end
|
214
|
+
#
|
215
|
+
# The DOM is created using an HTML parser specified by
|
216
|
+
# Rails::Dom::Testing.default_html_version (either :html4 or :html5).
|
217
|
+
#
|
218
|
+
# When testing in a Rails application, the parser default can also be set by setting
|
219
|
+
# +Rails.application.config.dom_testing_default_html_version+.
|
220
|
+
#
|
221
|
+
# If you want to specify the HTML parser just for a particular assertion, pass
|
222
|
+
# <tt>html_version: :html4</tt> or <tt>html_version: :html5</tt> keyword arguments:
|
223
|
+
#
|
224
|
+
# assert_dom "feed[xmlns='http://www.w3.org/2005/Atom']" do
|
225
|
+
# assert_dom "entry>title" do
|
226
|
+
# assert_dom_encoded(html_version: :html5) do
|
227
|
+
# assert_dom "b"
|
228
|
+
# end
|
229
|
+
# end
|
230
|
+
# end
|
231
|
+
#
|
232
|
+
def assert_dom_encoded(element = nil, html_version: nil, &block)
|
233
|
+
if !element && !@selected
|
234
|
+
raise ArgumentError, "Element is required when called from a nonnested assert_dom"
|
235
|
+
end
|
215
236
|
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
237
|
+
content = nodeset(element || @selected).map do |elem|
|
238
|
+
elem.children.select do |child|
|
239
|
+
child.cdata? || (child.text? && !child.blank?)
|
240
|
+
end.map(&:content)
|
241
|
+
end.join
|
221
242
|
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
243
|
+
selected = Rails::Dom::Testing.html_document_fragment(html_version: html_version).parse(content)
|
244
|
+
nest_selection(selected) do
|
245
|
+
if content.empty?
|
246
|
+
yield selected
|
247
|
+
else
|
248
|
+
assert_dom ":root", &block
|
249
|
+
end
|
228
250
|
end
|
229
251
|
end
|
230
|
-
|
252
|
+
alias_method :assert_select_encoded, :assert_dom_encoded
|
231
253
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
#
|
247
|
-
|
248
|
-
|
249
|
-
|
254
|
+
# Extracts the body of an email and runs nested assertions on it.
|
255
|
+
#
|
256
|
+
# You must enable deliveries for this assertion to work, use:
|
257
|
+
# ActionMailer::Base.perform_deliveries = true
|
258
|
+
#
|
259
|
+
# Example usage:
|
260
|
+
#
|
261
|
+
# assert_dom_email do
|
262
|
+
# assert_dom "h1", "Email alert"
|
263
|
+
# end
|
264
|
+
#
|
265
|
+
# assert_dom_email do
|
266
|
+
# items = assert_dom "ol>li"
|
267
|
+
# items.each do
|
268
|
+
# # Work with items here...
|
269
|
+
# end
|
270
|
+
# end
|
271
|
+
#
|
272
|
+
# The DOM is created using an HTML parser specified by
|
273
|
+
# Rails::Dom::Testing.default_html_version (either :html4 or :html5).
|
274
|
+
#
|
275
|
+
# When testing in a Rails application, the parser default can also be set by setting
|
276
|
+
# +Rails.application.config.dom_testing_default_html_version+.
|
277
|
+
#
|
278
|
+
# If you want to specify the HTML parser just for a particular assertion, pass
|
279
|
+
# <tt>html_version: :html4</tt> or <tt>html_version: :html5</tt> keyword arguments:
|
280
|
+
#
|
281
|
+
# assert_dom_email(html_version: :html5) do
|
282
|
+
# assert_dom "h1", "Email alert"
|
283
|
+
# end
|
284
|
+
#
|
285
|
+
def assert_dom_email(html_version: nil, &block)
|
286
|
+
deliveries = ActionMailer::Base.deliveries
|
287
|
+
assert !deliveries.empty?, "No e-mail in delivery list"
|
250
288
|
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
289
|
+
deliveries.each do |delivery|
|
290
|
+
(delivery.parts.empty? ? [delivery] : delivery.parts).each do |part|
|
291
|
+
if /^text\/html\W/.match?(part["Content-Type"].to_s)
|
292
|
+
root = Rails::Dom::Testing.html_document_fragment(html_version: html_version).parse(part.body.to_s)
|
293
|
+
assert_dom root, ":root", &block
|
294
|
+
end
|
256
295
|
end
|
257
296
|
end
|
258
297
|
end
|
259
|
-
|
298
|
+
alias_method :assert_select_email, :assert_dom_email
|
260
299
|
|
261
300
|
private
|
262
|
-
include CountDescribable
|
263
|
-
|
264
301
|
def document_root_element
|
265
|
-
raise NotImplementedError,
|
266
|
-
|
302
|
+
raise NotImplementedError, "Implementing document_root_element makes " \
|
303
|
+
"assert_dom work without needing to specify an element to select from."
|
267
304
|
end
|
268
305
|
|
269
306
|
# +equals+ must contain :minimum, :maximum and :count keys
|
270
307
|
def assert_size_match!(size, equals, css_selector, message = nil)
|
271
308
|
min, max, count = equals[:minimum], equals[:maximum], equals[:count]
|
272
309
|
|
273
|
-
message ||= %(Expected #{count_description(min, max, count)} matching
|
310
|
+
message ||= %(Expected #{count_description(min, max, count)} matching #{css_selector.inspect}, found #{size})
|
274
311
|
if count
|
275
312
|
assert_equal count, size, message
|
276
313
|
else
|
@@ -279,8 +316,24 @@ module Rails
|
|
279
316
|
end
|
280
317
|
end
|
281
318
|
|
319
|
+
def count_description(min, max, count)
|
320
|
+
if min && max && (max != min)
|
321
|
+
"between #{min} and #{max} elements"
|
322
|
+
elsif min && max && max == min && count
|
323
|
+
"exactly #{count} #{pluralize_element(min)}"
|
324
|
+
elsif min && !(min == 1 && max == 1)
|
325
|
+
"at least #{min} #{pluralize_element(min)}"
|
326
|
+
elsif max
|
327
|
+
"at most #{max} #{pluralize_element(max)}"
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
def pluralize_element(quantity)
|
332
|
+
quantity == 1 ? "element" : "elements"
|
333
|
+
end
|
334
|
+
|
282
335
|
def nest_selection(selection)
|
283
|
-
# Set @selected to allow nested
|
336
|
+
# Set @selected to allow nested assert_dom.
|
284
337
|
# Can be nested several levels deep.
|
285
338
|
old_selected, @selected = @selected, selection
|
286
339
|
yield @selected
|
@@ -292,6 +345,7 @@ module Rails
|
|
292
345
|
if node.is_a?(Nokogiri::XML::NodeSet)
|
293
346
|
node
|
294
347
|
else
|
348
|
+
node ||= Nokogiri::HTML::Document.new
|
295
349
|
Nokogiri::XML::NodeSet.new(node.document, [node])
|
296
350
|
end
|
297
351
|
end
|
@@ -1,18 +1,15 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "assertions/dom_assertions"
|
4
|
+
require_relative "assertions/selector_assertions"
|
3
5
|
|
4
6
|
module Rails
|
5
7
|
module Dom
|
6
8
|
module Testing
|
7
9
|
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
10
|
include DomAssertions
|
14
11
|
include SelectorAssertions
|
15
12
|
end
|
16
13
|
end
|
17
14
|
end
|
18
|
-
end
|
15
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rails
|
4
|
+
module Dom
|
5
|
+
module Testing
|
6
|
+
class Railtie < Rails::Railtie # :nodoc:
|
7
|
+
config.after_initialize do |app|
|
8
|
+
version = app.config.try(:dom_testing_default_html_version) # Rails 7.1+
|
9
|
+
Rails::Dom::Testing.default_html_version = version if version
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|