Skip to content

Commit cb05bb7

Browse files
committed
feat: some assertions allow setting the HTML parser version
via an `html_version` kwarg: - assert_dom_equal and assert_dom_not_equal - assert_dom_encoded - assert_dom_email The remaining assertions all rely on `document_root_element` to return the DOM (meaning we'll have to make changes to Rails).
1 parent 1c306c5 commit cb05bb7

File tree

5 files changed

+152
-11
lines changed

5 files changed

+152
-11
lines changed

lib/rails/dom/testing/assertions/dom_assertions.rb

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# frozen_string_literal: true
22

3+
require_relative "../parser_selection"
4+
35
module Rails
46
module Dom
57
module Testing
@@ -9,8 +11,8 @@ module DomAssertions
911
#
1012
# # assert that the referenced method generates the appropriate HTML string
1113
# assert_dom_equal '<a href="http://www.example.com">Apples</a>', link_to("Apples", "http://www.example.com")
12-
def assert_dom_equal(expected, actual, message = nil, strict: false)
13-
expected_dom, actual_dom = fragment(expected), fragment(actual)
14+
def assert_dom_equal(expected, actual, message = nil, strict: false, html_version: nil)
15+
expected_dom, actual_dom = fragment(expected, html_version: html_version), fragment(actual, html_version: html_version)
1416
message ||= "Expected: #{expected}\nActual: #{actual}"
1517
assert compare_doms(expected_dom, actual_dom, strict), message
1618
end
@@ -19,8 +21,8 @@ def assert_dom_equal(expected, actual, message = nil, strict: false)
1921
#
2022
# # assert that the referenced method does not generate the specified HTML string
2123
# assert_dom_not_equal '<a href="http://www.example.com">Apples</a>', link_to("Oranges", "http://www.example.com")
22-
def assert_dom_not_equal(expected, actual, message = nil, strict: false)
23-
expected_dom, actual_dom = fragment(expected), fragment(actual)
24+
def assert_dom_not_equal(expected, actual, message = nil, strict: false, html_version: nil)
25+
expected_dom, actual_dom = fragment(expected, html_version: html_version), fragment(actual, html_version: html_version)
2426
message ||= "Expected: #{expected}\nActual: #{actual}"
2527
assert_not compare_doms(expected_dom, actual_dom, strict), message
2628
end
@@ -84,8 +86,8 @@ def equal_attribute?(attr, other_attr)
8486
end
8587

8688
private
87-
def fragment(text)
88-
Nokogiri::HTML::DocumentFragment.parse(text)
89+
def fragment(text, html_version: nil)
90+
Rails::Dom::Testing.html_document_fragment(html_version: html_version).parse(text)
8991
end
9092
end
9193
end

lib/rails/dom/testing/assertions/selector_assertions.rb

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# frozen_string_literal: true
22

3+
require_relative "../parser_selection"
34
require_relative "selector_assertions/count_describable"
45
require_relative "selector_assertions/html_selector"
56

@@ -212,7 +213,7 @@ def assert_dom(*args, &block)
212213
# end
213214
# end
214215
# end
215-
def assert_dom_encoded(element = nil, &block)
216+
def assert_dom_encoded(element = nil, html_version: nil, &block)
216217
if !element && !@selected
217218
raise ArgumentError, "Element is required when called from a nonnested assert_dom"
218219
end
@@ -223,7 +224,7 @@ def assert_dom_encoded(element = nil, &block)
223224
end.map(&:content)
224225
end.join
225226

226-
selected = Nokogiri::HTML::DocumentFragment.parse(content)
227+
selected = Rails::Dom::Testing.html_document_fragment(html_version: html_version).parse(content)
227228
nest_selection(selected) do
228229
if content.empty?
229230
yield selected
@@ -249,14 +250,14 @@ def assert_dom_encoded(element = nil, &block)
249250
# # Work with items here...
250251
# end
251252
# end
252-
def assert_dom_email(&block)
253+
def assert_dom_email(html_version: nil, &block)
253254
deliveries = ActionMailer::Base.deliveries
254255
assert !deliveries.empty?, "No e-mail in delivery list"
255256

256257
deliveries.each do |delivery|
257258
(delivery.parts.empty? ? [delivery] : delivery.parts).each do |part|
258259
if /^text\/html\W/.match?(part["Content-Type"].to_s)
259-
root = Nokogiri::HTML::DocumentFragment.parse(part.body.to_s)
260+
root = Rails::Dom::Testing.html_document_fragment(html_version: html_version).parse(part.body.to_s)
260261
assert_dom root, ":root", &block
261262
end
262263
end

test/dom_assertions_test.rb

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,90 @@ def test_dom_not_equal_with_interior_whitespace
125125
assert_dom_not_equal(with_space, without_space)
126126
end
127127
end
128+
129+
class DomAssertionsHtmlParserSelectionTest < ActiveSupport::TestCase
130+
include DomTestingHelpers
131+
include Rails::Dom::Testing::Assertions::DomAssertions
132+
133+
def setup
134+
super
135+
136+
# https://html.spec.whatwg.org/multipage/parsing.html#an-introduction-to-error-handling-and-strange-cases-in-the-parser
137+
# we use these results to assert that we're invoking the expected parser.
138+
@input = "<p>1<b>2<i>3</b>4</i>5</p>"
139+
@html4_result = jruby? ? "<p>1<b>2<i>3</i></b><i>4</i>5</p>" : "<p>1<b>2<i>3</i></b>45</p>"
140+
@html5_result = jruby? ? nil : "<p>1<b>2<i>3</i></b><i>4</i>5</p>"
141+
end
142+
143+
test "default value is html4" do
144+
assert_equal(:html4, Rails::Dom::Testing.default_html_version)
145+
end
146+
147+
test "default html4, no version specified" do
148+
with_default_html_version(:html4) do
149+
assert_dom_equal(@html4_result, @input)
150+
assert_dom_not_equal(@html5_result, @input)
151+
end
152+
end
153+
154+
test "default html4, html4 specified" do
155+
with_default_html_version(:html4) do
156+
assert_dom_equal(@html4_result, @input, html_version: :html4)
157+
assert_dom_not_equal(@html5_result, @input, html_version: :html4)
158+
end
159+
end
160+
161+
test "default html4, html5 specified" do
162+
skip("html5 is not supported") unless Rails::Dom::Testing.html5_support?
163+
164+
with_default_html_version(:html4) do
165+
assert_dom_equal(@html5_result, @input, html_version: :html5)
166+
assert_dom_not_equal(@html4_result, @input, html_version: :html5)
167+
end
168+
end
169+
170+
test "default html5, no version specified" do
171+
skip("html5 is not supported") unless Rails::Dom::Testing.html5_support?
172+
173+
with_default_html_version(:html5) do
174+
assert_dom_equal(@html5_result, @input)
175+
assert_dom_not_equal(@html4_result, @input)
176+
end
177+
end
178+
179+
test "default html5, html4 specified" do
180+
with_default_html_version(:html5) do
181+
assert_dom_equal(@html4_result, @input, html_version: :html4)
182+
assert_dom_not_equal(@html5_result, @input, html_version: :html4)
183+
end
184+
end
185+
186+
test "default html5, html5 specified" do
187+
skip("html5 is not supported") unless Rails::Dom::Testing.html5_support?
188+
189+
with_default_html_version(:html5) do
190+
assert_dom_equal(@html5_result, @input, html_version: :html5)
191+
assert_dom_not_equal(@html4_result, @input, html_version: :html5)
192+
end
193+
end
194+
195+
test "raise NotImplementedError html5 when not supported" do
196+
Rails::Dom::Testing.stub(:html5_support?, false) do
197+
with_default_html_version(:html5) do
198+
assert_raises(NotImplementedError) { assert_dom_equal("a", "b") }
199+
assert_raises(NotImplementedError) { assert_dom_equal("a", "b", html_version: :html5) }
200+
assert_nothing_raised { assert_dom_equal(@html4_result, @input, html_version: :html4) }
201+
end
202+
end
203+
end
204+
205+
test "default set to invalid" do
206+
with_default_html_version(:html9) do
207+
assert_raises(ArgumentError) { assert_dom_equal("a", "b") }
208+
end
209+
end
210+
211+
test "invalid version specified" do
212+
assert_raises(ArgumentError) { assert_dom_equal("a", "b", html_version: :html9) }
213+
end
214+
end

test/selector_assertions_test.rb

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
class AssertSelectTest < ActiveSupport::TestCase
88
Assertion = Minitest::Assertion
99

10+
include DomTestingHelpers
1011
include Rails::Dom::Testing::Assertions::SelectorAssertions
1112

1213
def assert_failure(message, &block)
@@ -302,6 +303,52 @@ def test_feed_item_encoded
302303
end
303304
end
304305

306+
def test_feed_item_encoded_with_html_version
307+
# https://html.spec.whatwg.org/multipage/parsing.html#an-introduction-to-error-handling-and-strange-cases-in-the-parser
308+
# we use these results to assert that we're invoking the expected parser.
309+
input = CGI.escapeHTML("<p>1<b>2<i>3</b>4</i>5</p>")
310+
html4_result = jruby? ? "<p>1<b>2<i>3</i></b><i>4</i>5</p>" : "<p>1<b>2<i>3</i></b>45</p>"
311+
html5_result = jruby? ? nil : "<p>1<b>2<i>3</i></b><i>4</i>5</p>"
312+
313+
render_xml(<<~XML)
314+
<root>
315+
<contents>#{input}</contents>
316+
</root>
317+
XML
318+
319+
with_default_html_version(:html4) do
320+
assert_select "root contents" do
321+
assert_select_encoded do |contents|
322+
assert_equal(html4_result, contents.to_html)
323+
end
324+
325+
assert_select_encoded(html_version: :html4) do |contents|
326+
assert_equal(html4_result, contents.to_html)
327+
end
328+
329+
assert_select_encoded(html_version: :html5) do |contents|
330+
assert_equal(html5_result, contents.to_html)
331+
end if Rails::Dom::Testing.html5_support?
332+
end
333+
end
334+
335+
with_default_html_version(:html5) do
336+
assert_select "root contents" do
337+
assert_select_encoded do |contents|
338+
assert_equal(html5_result, contents.to_html)
339+
end if Rails::Dom::Testing.html5_support?
340+
341+
assert_select_encoded(html_version: :html4) do |contents|
342+
assert_equal(html4_result, contents.to_html)
343+
end
344+
345+
assert_select_encoded(html_version: :html5) do |contents|
346+
assert_equal(html5_result, contents.to_html)
347+
end if Rails::Dom::Testing.html5_support?
348+
end
349+
end
350+
end
351+
305352
def test_body_not_present_in_empty_document
306353
render_html "<div></div>"
307354
assert_select "body", 0
@@ -348,7 +395,7 @@ def fake_render(content_type, content)
348395
@html_document = if content_type == :xml
349396
Nokogiri::XML::Document.parse(content)
350397
else
351-
Nokogiri::HTML::Document.parse(content)
398+
Rails::Dom::Testing.html_document.parse(content)
352399
end
353400
end
354401

test/test_helper.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
ActiveSupport::TestCase.test_order = :random
99

1010
module DomTestingHelpers
11+
def jruby?
12+
!! Nokogiri.jruby?
13+
end
14+
1115
def with_default_html_version(version)
1216
old_version = Rails::Dom::Testing.default_html_version
1317
begin

0 commit comments

Comments
 (0)