I had been following the discussion How to automate shadow DOM elements using selenium? to work with #shadow-root (open)
elements.
While in the process of locating the Clear data button within the Clear browsing data popup, which appears while accessing the url chrome://settings/clearBrowserData
through Selenium I am unable to locate the following element:
#shadow-root (open)
<settings-privacy-page>
Snapshot:
Using Selenium following are my code trials and the associated errors encountered:
Attempt 1:
WebElement root5 = shadow_root4.findElement(By.tagName("settings-privacy-page"));
Error:
Exception in thread "main" org.openqa.selenium.JavascriptException: javascript error: b.getElementsByTagName is not a function
Attempt 2:
WebElement root5 = shadow_root4.findElement(By.cssSelector("settings-privacy-page"));
Error:
Exception in thread "main" org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"css selector","selector":"settings-privacy-page"}
Attempt 3:
WebElement root5 = (WebElement)((JavascriptExecutor)shadow_root4).executeScript("return document.getElementsByTagName('settings-privacy-page')[0]");
Error:
Exception in thread "main" java.lang.ClassCastException: org.openqa.selenium.remote.RemoteWebElement cannot be cast to org.openqa.selenium.JavascriptExecutor
Incase if it is helpful the initial code block (till the above line) works perfect:
driver.get("chrome://settings/clearBrowserData");
WebElement root1 = driver.findElement(By.tagName("settings-ui"));
WebElement shadow_root1 = expand_shadow_element(root1);
WebElement root2 = shadow_root1.findElement(By.cssSelector("settings-main#main"));
WebElement shadow_root2 = expand_shadow_element(root2);
WebElement root3 = shadow_root2.findElement(By.cssSelector("settings-basic-page[role='main']"));
WebElement shadow_root3 = expand_shadow_element(root3);
WebElement root4 = shadow_root3.findElement(By.cssSelector("settings-section[page-title='Privacy and security']"));
WebElement shadow_root4 = expand_shadow_element(root4);
PS: expand_shadow_element()
works flawless.
Can anyone help me out please?
If you are trying to get 'Clear Data' element then you can use the below js to get the element and then perform.
Here is the sample script.
Edit 2: Explanation
Problem: Selenium does not provide explicit support to work with Shadow DOM elements, as they are not in the current dom. That's the reason why we will get
NoSuchElementException
exception when try to access the elements in theshadow dom
.Shadow DOM:
Note: We will be referring to the terms shown in the picture. So please go through the picture for better understanding.
Solution:
In order to work with shadow element first we have to find the
shadow host
to which the shadow dom is attached. Here is the simple method to get the shadow root based on the shadowHost.And then you can access the shadow tree element using the shadowRoot Element.
In order to simplify all the above steps created the below method.
Now you can get the shadowTree Element with single method call
And perform the operations as usual like
.click()
,.getText()
.This Looks simple when you have only one level of shadow DOM. But here, in this case we have multiple levels of shadow doms. So we have to access the element by reaching each shadow host and root.
Below is the snippet using the methods that mentioned above (getShadowElement and getShadowRoot)
You can achieve all the above steps in single js call as at mentioned at the beginning of the answer (added below just to reduce the confusion).
Screenshot:
@supputuri's answer is the working and accepted answer as the Locator Strategy through
document.querySelector()
works perfect through google-chrome-devtoolsHowever, as the desired element opens from the shadow-dom you need to induce WebDriverWait for the
elementToBeClickable()
and you can you the following solution:Code Block:
Console Output:
I had to do a similar test which required clearing browsing the chrome history. A minor difference was that I was clearing the data after going to the advanced section of the pop-up. As you are struggling to click only the "Clear data" button, I'm quite sure that you've missed one or two hierarchy elements mistakenly. Or got confused between sibling and parent elements probably. As per seeing your code, I assume that you already know that to access a particular shadow DOM element you need proper sequencing and it has been explained also quite nicely above.
Coming right at your problem now, here is my code snippet which is working correctly. The code waits until the data is cleaned and then will proceed to your next action-
It should work properly in your case too if you don't intend to change any of the options selected by default in the pop-up (In that case, you will have to add a few more codes regarding selecting those checkboxes). Please tell me if this solves your issue. Hope this is helpful I've added a snapshot of the the screen here too- image
I am wondering, if this is a separate child window as it's on foreground and thats why unable to find the uielement on the screen . Once you get the child window handle, you should be able to grab the uielement?