如何在使用 cssSelector 清除 Chrome 浏览器的浏览数据时与 #shadow-root (open) 中的元素交互 [英] How to interact with the elements within #shadow-root (open) while Clearing Browsing Data of Chrome Browser using cssSelector

查看:20
本文介绍了如何在使用 cssSelector 清除 Chrome 浏览器的浏览数据时与 #shadow-root (open) 中的元素交互的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在关注讨论

使用

注意:我们将参考图片中显示的术语.所以请通过图片更好地理解.

解决方案:

为了使用shadow element,首先我们必须找到shadow dom所附加的shadow host.下面是基于shadowHost获取shadow root的简单方法.

private static WebElement getShadowRoot(WebDriver driver,WebElement shadowHost) {JavascriptExecutor js = (JavascriptExecutor) 驱动程序;return (WebElement) js.executeScript("返回参数[0].shadowRoot", shadowHost);}

然后您可以使用 shadowRoot 元素访问阴影树元素.

//使用findElement获取原始dom中的shadowHostWebElement shadowHost = driver.findElement(By.cssSelector("shadowHost_CSS"));//获取影子根WebElement shadowRoot = getShadowRoot(driver,shadowHost);//访问影子树元素WebElement shadowTreeElement = shadowRoot.findElement(By.cssSelector("shadow_tree_element_css"));

为了简化上述所有步骤,创建了以下方法.

public static WebElement getShadowElement(WebDriver driver,WebElement shadowHost, String cssOfShadowElement) {WebElement shardowRoot = getShadowRoot(driver, shadowHost);返回 shardowRoot.findElement(By.cssSelector(cssOfShadowElement));}

现在您可以通过单个方法调用获取 shadowTree 元素

WebElement shadowHost = driver.findElement(By.cssSelector("shadowHost_CSS_Goes_here));WebElement shadowTreeElement = getShadowElement(driver,shadowHost,"shadow_tree_element_css");

并照常执行.click().getText()等操作.

shadowTreeElement.click()

当您只有一层 shadow DOM 时,这看起来很简单.但是在这里,在这种情况下,我们有多个级别的 shadow dom.所以我们必须通过到达每个影子主机和根来访问元素.

以下是使用上述方法(getShadowElement 和 getShadowRoot)的代码片段

//在当前dom上定位shadowHostWebElement shadowHostL1 = driver.findElement(By.cssSelector("settings-ui"));//现在通过遍历所有阴影级别来定位 shadowElementWebElement shadowElementL1 = getShadowElement(driver, shadowHostL1, "settings-main");WebElement shadowElementL2 = getShadowElement(driver, shadowElementL1,"settings-basic-page");WebElement shadowElementL3 = getShadowElement(driver, shadowElementL2,"settings-section > settings-privacy-page");WebElement shadowElementL4 = getShadowElement(driver, shadowElementL3,"settings-clear-browsing-data-dialog");WebElement shadowElementL5 = getShadowElement(driver, shadowElementL4,"#clearBrowsingDataDialog");WebElement clearData = shadowElementL5.findElement(By.cssSelector("#clearBrowsingDataConfirm"));System.out.println(clearData.getText());clearData.click();

您可以在答案开头提到的单个js调用中完成上述所有步骤(添加在下面只是为了减少混淆).

WebElement clearData = (WebElement) js.executeScript("return document.querySelector('settings-ui').shadowRoot.querySelector('settings-main').shadowRoot.querySelector('settings-basic-page').shadowRoot.querySelector('settings-section > settings-privacy-page').shadowRoot.querySelector('settings-clear-browsing-data-dialog').shadowRoot.querySelector('#clearBrowsingDataDialog').querySelector('#clearBrowsingDataConfirm')");

截图:

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.

解决方案

If you are trying to get 'Clear Data' element then you can use the below js to get the element and then perform.

return document.querySelector('settings-ui').shadowRoot.querySelector('settings-main').shadowRoot.querySelector('settings-basic-page').shadowRoot.querySelector('settings-section > settings-privacy-page').shadowRoot.querySelector('settings-clear-browsing-data-dialog').shadowRoot.querySelector('#clearBrowsingDataDialog').querySelector('#clearBrowsingDataConfirm')

Here is the sample script.

driver.get("chrome://settings/clearBrowserData");
driver.manage().window().maximize();
JavascriptExecutor js = (JavascriptExecutor) driver; 
WebElement clearData = (WebElement) js.executeScript("return document.querySelector('settings-ui').shadowRoot.querySelector('settings-main').shadowRoot.querySelector('settings-basic-page').shadowRoot.querySelector('settings-section > settings-privacy-page').shadowRoot.querySelector('settings-clear-browsing-data-dialog').shadowRoot.querySelector('#clearBrowsingDataDialog').querySelector('#clearBrowsingDataConfirm')");
// now you can click on clear data button
clearData.click();

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 the shadow 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.

private static WebElement getShadowRoot(WebDriver driver,WebElement shadowHost) {
    JavascriptExecutor js = (JavascriptExecutor) driver;
    return (WebElement) js.executeScript("return arguments[0].shadowRoot", shadowHost);
}

And then you can access the shadow tree element using the shadowRoot Element.

// get the shadowHost in the original dom using findElement
WebElement shadowHost = driver.findElement(By.cssSelector("shadowHost_CSS"));
// get the shadow root
WebElement shadowRoot = getShadowRoot(driver,shadowHost);
// access shadow tree element
WebElement shadowTreeElement = shadowRoot.findElement(By.cssSelector("shadow_tree_element_css"));

In order to simplify all the above steps created the below method.

public static WebElement getShadowElement(WebDriver driver,WebElement shadowHost, String cssOfShadowElement) {
    WebElement shardowRoot = getShadowRoot(driver, shadowHost);
    return shardowRoot.findElement(By.cssSelector(cssOfShadowElement));
}

Now you can get the shadowTree Element with single method call

WebElement shadowHost = driver.findElement(By.cssSelector("shadowHost_CSS_Goes_here));
WebElement shadowTreeElement = getShadowElement(driver,shadowHost,"shadow_tree_element_css");

And perform the operations as usual like .click(), .getText().

shadowTreeElement.click()

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)

// Locate shadowHost on the current dom
WebElement shadowHostL1 = driver.findElement(By.cssSelector("settings-ui"));

// now locate the shadowElement by traversing all shadow levels
WebElement shadowElementL1 = getShadowElement(driver, shadowHostL1, "settings-main");
WebElement shadowElementL2 = getShadowElement(driver, shadowElementL1,"settings-basic-page");
WebElement shadowElementL3 = getShadowElement(driver, shadowElementL2,"settings-section > settings-privacy-page");
WebElement shadowElementL4 = getShadowElement(driver, shadowElementL3,"settings-clear-browsing-data-dialog");
WebElement shadowElementL5 = getShadowElement(driver, shadowElementL4,"#clearBrowsingDataDialog");
WebElement clearData = shadowElementL5.findElement(By.cssSelector("#clearBrowsingDataConfirm"));
System.out.println(clearData.getText());
clearData.click();

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).

WebElement clearData = (WebElement) js.executeScript("return document.querySelector('settings-ui').shadowRoot.querySelector('settings-main').shadowRoot.querySelector('settings-basic-page').shadowRoot.querySelector('settings-section > settings-privacy-page').shadowRoot.querySelector('settings-clear-browsing-data-dialog').shadowRoot.querySelector('#clearBrowsingDataDialog').querySelector('#clearBrowsingDataConfirm')");

Screenshot:

这篇关于如何在使用 cssSelector 清除 Chrome 浏览器的浏览数据时与 #shadow-root (open) 中的元素交互的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆