Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit c3735e1

Browse files
committedNov 10, 2024·
Basic implementation for piercing Shadow DOM
- Added test case for looking into the nested shadow dom - Added basic method for piercing the showdom dom. Here using the cascading locators and checking if a parent element is a shadow dom host. If so it replaces the parent element with the resulting shadow dom object. Thus the continued find then searches the shadow dom root instead of the regular dom. This is a highly simplified method for piercing and misses many important scenarios (might be a descendant but on the regular dom for example).
1 parent 5859883 commit c3735e1

File tree

2 files changed

+12
-0
lines changed

2 files changed

+12
-0
lines changed
 

‎atest/acceptance/3-shadow_dom/piercing_shadowdom.robot

+3
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,6 @@ Test Setup Go To Page "shadow_dom.html"
1111
Multiple Locators with double arrows as separator should work
1212
[Setup] Go To Page "links.html"
1313
Page Should Contain Element css:div#div_id >> xpath:a[6] >> id:image1_id
14+
15+
Nested Shadow DOM
16+
Page Should Contain Element id:shadow_host >> id:nested_shadow_host >> id:nested_div

‎src/SeleniumLibrary/locators/elementfinder.py

+9
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from selenium.webdriver.remote.webelement import WebElement
2222
from selenium.webdriver.support.event_firing_webdriver import EventFiringWebElement
2323
from selenium.webdriver.common.by import By
24+
from selenium.common.exceptions import NoSuchShadowRootException
2425

2526
from SeleniumLibrary.base import ContextAware
2627
from SeleniumLibrary.errors import ElementNotFound
@@ -110,13 +111,21 @@ def _split_locator(self, locator: Union[str, list]) -> list:
110111
return parts
111112

112113
def _find(self, locator, tag=None, first_only=True, required=True, parent=None):
114+
parent_is_shadowdom_host = False
113115
element_type = "Element" if not tag else tag.capitalize()
114116
if parent and not self._is_webelement(parent):
115117
raise ValueError(
116118
f"Parent must be Selenium WebElement but it was {type(parent)}."
117119
)
118120
if self._is_webelement(locator):
119121
return locator
122+
try:
123+
if parent:
124+
parent_is_shadowdom_host = parent.shadow_root
125+
except NoSuchShadowRootException:
126+
pass
127+
if parent_is_shadowdom_host: # and ??._shadowdom_piercing
128+
parent = parent_is_shadowdom_host
120129
prefix, criteria = self._parse_locator(locator)
121130
strategy = self._strategies[prefix]
122131
tag, constraints = self._get_tag_and_constraints(tag)

0 commit comments

Comments
 (0)
Please sign in to comment.