Skip to content

Commit

Permalink
Add assert_equivalent_html
Browse files Browse the repository at this point in the history
  • Loading branch information
joeldrapper committed Feb 12, 2025
1 parent 850ed1c commit 7a7c7cb
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ gemspec

gem "rspec-expectations"
gem "minitest"
gem "nokogiri"

if RUBY_ENGINE == "ruby"
group :development do
gem "rubocop"
gem "minitest"
gem "sus"
gem "covered"
end
Expand Down
1 change: 1 addition & 0 deletions lib/quickdraw.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ module Quickdraw
autoload :Timer, "quickdraw/timer"
autoload :Worker, "quickdraw/worker"
autoload :MinitestAdapter, "quickdraw/minitest_adapter"
autoload :HTMLPrettifier, "quickdraw/html_prettifier"

Null = Object.new.freeze
Error = Module.new
Expand Down
23 changes: 23 additions & 0 deletions lib/quickdraw/assertions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,33 @@ def assert_equal_html(actual, expected)
assert(actual == expected) do
diff = DIFFER.diff_html(actual, expected)

if diff.end_with?("No syntactic changes.")
diff = DIFFER.diff_strings(actual, expected)
end

"Expected HTML strings to be equal (compared with `actual == expected`):\n\n#{diff}"
end
end

def assert_equivalent_html(actual, expected)
if actual == expected
success!
else
pretty_actual = Quickdraw::HTMLPrettifier.prettify(actual)
pretty_expected = Quickdraw::HTMLPrettifier.prettify(expected)

assert(pretty_actual == pretty_expected) do
diff = DIFFER.diff_html(pretty_actual, pretty_expected)

if diff.end_with?("No syntactic changes.")
diff = DIFFER.diff_strings(pretty_actual, pretty_expected)
end

"Expected HTML to be equivalent (ignoring whitespace):\n\n#{diff}"
end
end
end

def assert_equal_ruby(actual, expected)
unless String === actual && String === expected
raise ArgumentError.new("expected both actual and expected to be strings")
Expand Down
74 changes: 74 additions & 0 deletions lib/quickdraw/html_prettifier.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# frozen_string_literal: true

require "nokogiri"

module Quickdraw::HTMLPrettifier
extend self

VOID_ELEMENTS = Set[
"area",
"base",
"br",
"col",
"embed",
"hr",
"img",
"input",
"link",
"meta",
"source",
"track",
].freeze

def prettify(html)
node = case html
when Nokogiri::HTML5::DocumentFragment
html
when String
Nokogiri::HTML5.fragment(html)
else
raise ArgumentError.new("Expected a Nokogiri::HTML5::DocumentFragment or a String, but got a #{html.class}")
end

prettify_node(node)
end

def prettify_node(node, depth = 0)
indent = " " * depth

case node
when Nokogiri::HTML5::DocumentFragment
map_children(node, depth)
when Nokogiri::XML::Element
attributes = node.attribute_nodes.map { |attr| prettify_node(attr) }.join
opening_tag = "#{indent}<#{node.name}#{attributes}>"

if VOID_ELEMENTS.include?(node.name)
opening_tag
else
[
opening_tag,
map_children(node, depth + 1),
"#{indent}</#{node.name}>",
].freeze.compact.join("\n")
end
when Nokogiri::XML::Text
text = node.text.strip
"#{indent}#{text}" if text.length > 0
when Nokogiri::XML::Attr
if node.value == ""
" #{node.name}"
else
%( #{node.name}="#{node.value}")
end
else
raise ArgumentError.new("Unexpected node type: #{node.class}")
end
end

def map_children(node, depth)
if node.children.any?
node.children.map { |child| prettify_node(child, depth) }.compact.join("\n")
end
end
end

0 comments on commit 7a7c7cb

Please sign in to comment.