Module: Dommy::Internal::DomMatching
- Defined in:
- lib/dommy/internal/dom_matching.rb
Overview
Shared matching primitives used by both RSpec matchers and Minitest assertions. Centralizes selector / text / count interpretation so the two frameworks behave identically.
Class Method Summary collapse
- .count_matches?(actual, expected) ⇒ Boolean
-
.filter(scope, selector, text: nil) ⇒ Array<Dommy::Element>
Find elements in scope matching selector, optionally filtered by text content.
-
.filter_by_visibility(elements, visible) ⇒ Object
Filter elements by Capybara-style :visible option.
-
.html_of(scope) ⇒ Object
Get the inner_html of a scope, falling back to body for Document.
-
.normalize_html(html) ⇒ Object
Normalize an HTML string for structural comparison.
- .text_matches?(actual, expected, exact: false) ⇒ Boolean
-
.text_of(scope) ⇒ Object
Get the text_content of a scope, handling Document (which has no text_content directly — its body does).
-
.visible?(element) ⇒ Boolean
Best-effort visibility check using HTML-level signals only.
Class Method Details
.count_matches?(actual, expected) ⇒ Boolean
41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/dommy/internal/dom_matching.rb', line 41 def count_matches?(actual, expected) case expected when nil actual.positive? when Integer actual == expected when Range expected.cover?(actual) else false end end |
.filter(scope, selector, text: nil) ⇒ Array<Dommy::Element>
Find elements in scope matching selector, optionally filtered by text content.
18 19 20 21 22 23 |
# File 'lib/dommy/internal/dom_matching.rb', line 18 def filter(scope, selector, text: nil) elements = scope.query_selector_all(selector).to_a return elements if text.nil? elements.select { |el| text_matches?(el.text_content, text) } end |
.filter_by_visibility(elements, visible) ⇒ Object
Filter elements by Capybara-style :visible option.
110 111 112 113 114 115 116 117 118 119 |
# File 'lib/dommy/internal/dom_matching.rb', line 110 def filter_by_visibility(elements, visible) case visible when nil, :all, false elements when :hidden elements.reject { |el| visible?(el) } else elements.select { |el| visible?(el) } end end |
.html_of(scope) ⇒ Object
Get the inner_html of a scope, falling back to body for Document.
76 77 78 79 80 81 82 83 84 |
# File 'lib/dommy/internal/dom_matching.rb', line 76 def html_of(scope) if scope.respond_to?(:inner_html) scope.inner_html.to_s elsif scope.respond_to?(:body) && scope.body scope.body.inner_html.to_s else scope.to_s end end |
.normalize_html(html) ⇒ Object
Normalize an HTML string for structural comparison. Re-parses through Nokogiri and re-serializes, which collapses whitespace differences and attribute ordering quirks.
59 60 61 |
# File 'lib/dommy/internal/dom_matching.rb', line 59 def normalize_html(html) Nokogiri::HTML5.fragment(html.to_s).to_html.gsub(/\s+/, " ").strip end |
.text_matches?(actual, expected, exact: false) ⇒ Boolean
29 30 31 32 33 34 35 36 37 |
# File 'lib/dommy/internal/dom_matching.rb', line 29 def text_matches?(actual, expected, exact: false) actual = actual.to_s case expected when Regexp exact ? actual.match?(expected) && actual == actual[expected] : actual.match?(expected) else exact ? actual.strip == expected.to_s : actual.include?(expected.to_s) end end |
.text_of(scope) ⇒ Object
Get the text_content of a scope, handling Document (which has no text_content directly — its body does).
65 66 67 68 69 70 71 72 73 |
# File 'lib/dommy/internal/dom_matching.rb', line 65 def text_of(scope) if scope.respond_to?(:text_content) scope.text_content.to_s elsif scope.respond_to?(:body) && scope.body scope.body.text_content.to_s else scope.to_s end end |
.visible?(element) ⇒ Boolean
Best-effort visibility check using HTML-level signals only. Does NOT evaluate CSS stylesheets — ‘display: none` via class is NOT detected. See README for details and workarounds.
Detects: ‘hidden` attribute, `<input type=hidden>`, non-rendering ancestors (head/script/style/template), inline `display:none` / `visibility:hidden` on element or any ancestor.
93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/dommy/internal/dom_matching.rb', line 93 def visible?(element) return true unless element.respond_to?(:__node__) node = element.__node__ return false if node_invisible_self?(node) NodeTraversal.each_ancestor(node) do |ancestor| return false if non_rendering_tag?(ancestor) return false if node_invisible_self?(ancestor) end true end |