I am working on an automation project which uses shadow DOMs extensively.
I use the execute_script
function to access shadow root elements.
For example:
root = driver.execute_script('return document.querySelector(".flex.vertical.layout").shadowRoot')
Then I use the root element to access the elements within. Since we have shadow root elements at many levels, this is annoying me a lot. Is there any better solution to access elements within shadow root elements?
I am using Chrome 2.20 driver.
Shadow DOM refers to the ability of the browser to include a subtree of DOM elements into the rendering of a document, but not into the main document DOM tree. Shadow DOM enables encapsulation. With Shadow DOM, a component can have its own “shadow” DOM tree that cannot be accidentally accessed from the main document.
Shadow DOM allows DOM elements to contain child nodes and CSS, which helps web developers by better encapsulating their code. But this creates challenges for automation testing, because elements inside a shadow root technically don't exist in the main DOM.
By googling I found another workaround for this problem - which is using the "/deep/
combinator".
For example, I was able to access all the shadow roots elements with
driver.find_elements_by_css_selector('body/deep/.layout.horizontal.center')
This will have access to the element with the compound class name layout horizontal center
regardless of the number of shadow roots it has.
But this only works for the chromedriver and /deep/
is a deprecated approach.
The WebDriver spec still doesn't have anything specific to say about Shadow DOM.
Nor the Selenium project pages - which is understandable, as they closely follow the spec. Yet there is some low-level code in existence.
So, the short answer is: no, there is no special support in the spec, in Selenium's WebDriver API or implementation code at present.
Yes, the capability seems to exist in ChromeDriver 2.14 (as a wrapper around Chrome). However, as far as I can tell there are no Selenium or WebDriver-level bindings to let you use it.
But for more detail and possible workarounds, see also: Accessing Shadow DOM tree with Selenium, also: Accessing elements in the shadow DOM, and especially: Finding elements in the shadow DOM
You can write extension methods to operate on IWebElement
to expand the root as below.
public static class SeleniumExtension
{
public static IWebElement ExpandRootElement(this IWebElement element, IWebDriver driver)
{
return (IWebElement)((IJavaScriptExecutor)driver)
.ExecuteScript("return arguments[0].shadowRoot", element);
}
}
You can use the above extension method to traverse through the element's hierarchy to reach the element of interest.
By downloads_manager_ShadowDom= By.TagName("downloads-manager");
By downloadToolBarShadowDom = By.CssSelector("downloads-toolbar");
By toolBarElement = By.CssSelector("cr-toolbar");
IWebElement ToolBarElement = driver.FindElement(downloads_manager_ShadowDom).ExpandRootElement(driver).FindElement(downloadToolBarShadowDom).ExpandRootElement(driver).FindElement(toolBarElement);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With