ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

使用cssSelector清除Chrome浏览器的浏览数据时,如何与#shadow-root(open)中的元素进行交互

2019-09-16 17:02:36  阅读:332  来源: 互联网

标签:java css css-selectors selenium shadow-dom


我一直在讨论How to automate shadow DOM elements using selenium?讨论与#shadow-root(open)元素一起工作.

在通过Selenium访问url chrome:// settings / clearBrowserData时出现的清除浏览数据弹出窗口中找到清除数据按钮的过程中,我无法找到以下元素:

#shadow-root (open)
<settings-privacy-page>

快照:

settings-privacy-page

使用Selenium以下是我的代码试验和遇到的相关错误:

>尝试1:

WebElement root5 = shadow_root4.findElement(By.tagName("settings-privacy-page"));

>错误:

Exception in thread "main" org.openqa.selenium.JavascriptException: javascript error: b.getElementsByTagName is not a function

>尝试2:

WebElement root5 = shadow_root4.findElement(By.cssSelector("settings-privacy-page"));

>错误:

Exception in thread "main" org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"css selector","selector":"settings-privacy-page"}

>尝试3:

WebElement root5 = (WebElement)((JavascriptExecutor)shadow_root4).executeScript("return document.getElementsByTagName('settings-privacy-page')[0]");

>错误:

Exception in thread "main" java.lang.ClassCastException: org.openqa.selenium.remote.RemoteWebElement cannot be cast to org.openqa.selenium.JavascriptExecutor

如果它有用,初始代码块(直到上面的行)完美运行:

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()完美无瑕.

有人可以帮帮我吗?

解决方法:

如果您正在尝试获取“清除数据”元素,那么您可以使用以下js来获取元素然后执行.

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

这是示例脚本.

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();

编辑2:解释

问题:Selenium没有为使用Shadow DOM elements提供明确的支持,因为它们不在当前的dom中.这就是我们在尝试访问阴影dom中的元素时会得到NoSuchElementException异常的原因.

影子DOM:
enter image description here

注意:我们将参考图片中显示的条款.所以请仔细阅读图片以便更好地理解.

解:

为了首先使用阴影元素,我们必须找到阴影dom所附着的阴影主机.以下是基于shadowHost获取阴影根的简单方法.

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

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

// 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"));

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

public static WebElement getShadowElement(WebDriver driver,WebElement shadowHost, String cssOfShadowElement) {
    WebElement shardowRoot = getShadowRoot(driver, shadowHost);
    return 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时,这看起来很简单.但在这里,在这种情况下,我们有多个级别的阴影doms.所以我们必须通过到达每个影子主机和root来访问该元素.
enter image description here

下面是使用上面提到的方法的片段(getShadowElement和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();

您可以在单个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')");

截图:
enter image description here

标签:java,css,css-selectors,selenium,shadow-dom
来源: https://codeday.me/bug/20190916/1807445.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有