Skip to content

Commit

Permalink
Add initial support for shadow_root
Browse files Browse the repository at this point in the history
Following capybara's support
teamcapybara/capybara#2546
  • Loading branch information
til committed Dec 8, 2023
1 parent ddc9cee commit ceb4f86
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 12 deletions.
34 changes: 23 additions & 11 deletions lib/capybara/cuprite/javascripts/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,17 @@ class Cuprite {
if (this.isVisible(node)) {
if (node.nodeName == "TEXTAREA") {
return node.textContent;
} else {
if (node instanceof SVGElement) {
return node.textContent;
} else {
return node.innerText;
}
}
if (node instanceof SVGElement) {
return node.textContent;
}
if (node instanceof ShadowRoot) {
return Array.from(node.children)
.map(child => this.visibleText(child))
.filter(text => text)
.join(" ");
}
return node.innerText;
}
}

Expand All @@ -74,11 +78,15 @@ class Cuprite {
}

while (node) {
style = window.getComputedStyle(node);
if (style.display === "none" || style.visibility === "hidden" || parseFloat(style.opacity) === 0) {
return false;
if (node instanceof ShadowRoot) {
node = node.host;
} else {
style = window.getComputedStyle(node);
if (style.display === "none" || style.visibility === "hidden" || parseFloat(style.opacity) === 0) {
return false;
}
node = node.parentElement ?? (node.getRootNode() instanceof ShadowRoot && node.getRootNode());
}
node = node.parentElement;
}

return true;
Expand All @@ -94,6 +102,10 @@ class Cuprite {
}

path(node) {
if (node.getRootNode && node.getRootNode() instanceof ShadowRoot) {
return "(: Shadow DOM element - no XPath :)";
};

let nodes = [node];
let parent = node.parentNode;
while (parent !== document && parent !== null) {
Expand Down Expand Up @@ -280,7 +292,7 @@ class Cuprite {
x -= frameOffset.left;
y -= frameOffset.top;

let element = document.elementFromPoint(x, y);
let element = node.getRootNode().elementFromPoint(x, y);

let el = element;
while (el) {
Expand Down
7 changes: 7 additions & 0 deletions lib/capybara/cuprite/node.rb
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,13 @@ def path
command(:path)
end

def shadow_root
root = driver.evaluate_script <<~JS, self
arguments[0].shadowRoot
JS
root && self.class.new(driver, root.node)
end

def inspect
%(#<#{self.class} @node=#{@node.inspect}>)
end
Expand Down
18 changes: 18 additions & 0 deletions spec/features/session_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,24 @@
end
end

describe "Node#shadow_root" do
it "produces error messages when failing" do
@session.visit("/with_shadow")
shadow_root = @session.find(:css, "#shadow_host").shadow_root
expect do
expect(shadow_root).to have_css("#shadow_content", text: "Not in the document")
end.to raise_error(/tag="#document-fragment"/)
end

it "extends visibility check across shadow host boundary" do
@session.visit("/with_shadow")
shadow_root = @session.find(:css, "#shadow_host").shadow_root
expect(shadow_root).to have_css("a")
@session.execute_script %(document.getElementById("shadow_host").style.display = "none")
expect(shadow_root).to_not have_css("a")
end
end

it "has no trouble clicking elements when the size of a document changes" do
@session.visit("/cuprite/long_page")
@session.find(:css, "#penultimate").click
Expand Down
2 changes: 1 addition & 1 deletion spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ module TestSessions
node #visible? details non-summary descendants should be non-visible
node #visible? works when details is toggled open and closed
node #path reports when element in shadow dom
node #shadow_root
node #set should submit single text input forms if ended with
node #shadow_root should produce error messages when failing
#all with obscured filter should only find nodes on top in the viewport when false
#all with obscured filter should not find nodes on top outside the viewport when false
#all with obscured filter should find top nodes outside the viewport when true
Expand Down

0 comments on commit ceb4f86

Please sign in to comment.