rails-dom-testing 2.1.0 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +38 -20
- data/lib/rails/dom/testing/assertions/dom_assertions.rb +57 -11
- data/lib/rails/dom/testing/assertions/selector_assertions/html_selector.rb +129 -117
- data/lib/rails/dom/testing/assertions/selector_assertions/substitution_context.rb +38 -24
- data/lib/rails/dom/testing/assertions/selector_assertions.rb +280 -232
- data/lib/rails/dom/testing/assertions.rb +4 -3
- 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 +93 -5
- data/test/parser_selection_test.rb +75 -0
- data/test/selector_assertions_test.rb +122 -71
- data/test/test_helper.rb +21 -4
- metadata +18 -29
- data/lib/rails/dom/testing/assertions/selector_assertions/count_describable.rb +0 -28
@@ -1,5 +1,6 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "selector_assertions/html_selector"
|
3
4
|
|
4
5
|
module Rails
|
5
6
|
module Dom
|
@@ -18,257 +19,288 @@ module Rails
|
|
18
19
|
# * +assert_dom_encoded+ - Assertions on HTML encoded inside XML, for example for dealing with feed item descriptions.
|
19
20
|
# * +assert_dom_email+ - Assertions on the HTML body of an e-mail.
|
20
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?
|
21
60
|
|
22
|
-
|
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?
|
61
|
+
root = args.size == 1 ? document_root_element : args.shift
|
60
62
|
|
61
|
-
|
63
|
+
nodeset(root).css(args.first)
|
64
|
+
end
|
62
65
|
|
63
|
-
|
64
|
-
|
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
|
65
165
|
|
66
|
-
|
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
|
165
|
-
|
166
|
-
selector = HTMLSelector.new(args, @selected) { nodeset document_root_element }
|
166
|
+
selector = HTMLSelector.new(args, @selected) { nodeset document_root_element }
|
167
167
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
168
|
+
if selector.selecting_no_body?
|
169
|
+
assert true
|
170
|
+
return
|
171
|
+
end
|
172
172
|
|
173
|
-
|
174
|
-
|
175
|
-
|
173
|
+
selector.select.tap do |matches|
|
174
|
+
assert_size_match!(matches.size, selector.tests,
|
175
|
+
selector.css_selector, selector.message)
|
176
176
|
|
177
|
-
|
177
|
+
nest_selection(matches, &block) if block_given? && !matches.empty?
|
178
|
+
end
|
178
179
|
end
|
179
|
-
|
180
|
-
alias_method :assert_select, :assert_dom
|
180
|
+
alias_method :assert_select, :assert_dom
|
181
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
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
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
|
218
236
|
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
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
|
224
242
|
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
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
|
231
250
|
end
|
232
251
|
end
|
233
|
-
|
234
|
-
alias_method :assert_select_encoded, :assert_dom_encoded
|
252
|
+
alias_method :assert_select_encoded, :assert_dom_encoded
|
235
253
|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
#
|
251
|
-
|
252
|
-
|
253
|
-
|
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"
|
254
288
|
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
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
|
260
295
|
end
|
261
296
|
end
|
262
297
|
end
|
263
|
-
|
264
|
-
alias_method :assert_select_email, :assert_dom_email
|
298
|
+
alias_method :assert_select_email, :assert_dom_email
|
265
299
|
|
266
300
|
private
|
267
|
-
include CountDescribable
|
268
|
-
|
269
301
|
def document_root_element
|
270
|
-
raise NotImplementedError,
|
271
|
-
|
302
|
+
raise NotImplementedError, "Implementing document_root_element makes " \
|
303
|
+
"assert_dom work without needing to specify an element to select from."
|
272
304
|
end
|
273
305
|
|
274
306
|
# +equals+ must contain :minimum, :maximum and :count keys
|
@@ -284,6 +316,22 @@ module Rails
|
|
284
316
|
end
|
285
317
|
end
|
286
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
|
+
|
287
335
|
def nest_selection(selection)
|
288
336
|
# Set @selected to allow nested assert_dom.
|
289
337
|
# Can be nested several levels deep.
|
@@ -1,6 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "assertions/dom_assertions"
|
4
|
+
require_relative "assertions/selector_assertions"
|
4
5
|
|
5
6
|
module Rails
|
6
7
|
module Dom
|
@@ -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
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "nokogiri"
|
4
|
+
require "active_support"
|
5
|
+
require "active_support/core_ext/module/attribute_accessors"
|
6
|
+
|
7
|
+
require "rails/dom/testing/assertions"
|
8
|
+
|
9
|
+
module Rails
|
10
|
+
module Dom
|
11
|
+
module Testing
|
12
|
+
mattr_accessor :default_html_version, default: :html4
|
13
|
+
|
14
|
+
class << self
|
15
|
+
def html5_support?
|
16
|
+
defined?(Nokogiri::HTML5)
|
17
|
+
end
|
18
|
+
|
19
|
+
def html_document(html_version: nil)
|
20
|
+
parser_classes = { html4: Nokogiri::HTML4::Document }
|
21
|
+
parser_classes[:html5] = Nokogiri::HTML5::Document if html5_support?
|
22
|
+
|
23
|
+
choose_html_parser(parser_classes, html_version: html_version)
|
24
|
+
end
|
25
|
+
|
26
|
+
def html_document_fragment(html_version: nil)
|
27
|
+
parser_classes = { html4: Nokogiri::HTML4::DocumentFragment }
|
28
|
+
parser_classes[:html5] = Nokogiri::HTML5::DocumentFragment if html5_support?
|
29
|
+
|
30
|
+
choose_html_parser(parser_classes, html_version: html_version)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
def choose_html_parser(parser_classes, html_version: nil)
|
35
|
+
html_version ||= Rails::Dom::Testing.default_html_version
|
36
|
+
|
37
|
+
case html_version
|
38
|
+
when :html4
|
39
|
+
parser_classes[:html4]
|
40
|
+
when :html5
|
41
|
+
unless Rails::Dom::Testing.html5_support?
|
42
|
+
raise NotImplementedError, "html5 parser is not supported on this platform"
|
43
|
+
end
|
44
|
+
parser_classes[:html5]
|
45
|
+
else
|
46
|
+
raise ArgumentError, "html_version must be :html4 or :html5, received #{html_version.inspect}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/rails-dom-testing.rb
CHANGED