selenium webdriver (chromedriver) and accessing shadow dom

懵懂的女人 提交于 2019-11-28 14:20:22

One way would be to use a piercing CSS selector (/deep/ or >>>). Though it's not supported by all the browsers and it may be removed in a future release.

This one should give you the close button with Chrome 62:

driver.findElement(By.css("* /deep/ button[title='Close']"))

It's possible, but it will take a couple steps. As a preliminary, check out this page about accessing shadow dom. I found it really informative.

Start with two methods to get the shadow dom element:

private WebElement shadowDom;

private WebElement expandRootElement(WebElement element) {
    WebElement ele = (WebElement) ((JavascriptExecutor) driver).executeScript("return arguments[0].shadowRoot",element);
    return ele;
}
private void findByShadowRoot(WebDriver driver) {
    shadowDom = expandRootElement(driver.findElement(By.id("whatEverTheShadowDomIdIs")));
}

From there, you create methods as a pseudo POM

private WebElement findByShadowButton() {
    findByShadowRoot(driver);
    return shadowDom.findElement(By.cssSelector("div.th_fp_Close"));
}

Basically the first two methods are for creating a starting point, and then all the other methods call those methods and say, "from this starting point, find the element beneath it".

Then you can statements like:

findByShadowButton().click();

You can try this "heavy" approach (C# but depending on your language it can be something like that):

public IWebElement DeepFind(By search)
{
    try
    {
        // search a result in the main dom
        return Driver.FindElement(search);
    }
    catch (NoSuchElementException)
    {
        // if nothing we will take a look to the shadow dom(s)
        var shadowRoots = new List<IWebElement>();
        try
        {
            // will use the recursive method that search for all shadow roots
            ListShadowRoots(search, Driver.FindElements(By.XPath("//*")), shadowRoots);
        }
        catch (NoSuchElementException)
        {
            //
        }
        // return the first element that match the By search
        return shadowRoots.FirstOrDefault(s => s.FindElement(search) != null);
    }
}

private void ListShadowRoots(By search, ReadOnlyCollection<IWebElement> elements, List<IWebElement> shadowRoots)
{
    elements.ToList().ForEach(e =>
    {
        var jsResult = (IWebElement)ExecuteJavascript("return arguments[0].shadowRoot", new object[] { e });
        if (jsResult != null)
        {
            shadowRoots.Add(jsResult);
            try
            {
                ListShadowRoots(search, jsResult.FindElements(By.XPath("//*")), shadowRoots);
            }
            catch (NoSuchElementException)
            {
                //
            }
        }
    });
}

private object ExecuteJavascript(string code, object[] args)
{
    IJavaScriptExecutor js = (IJavaScriptExecutor)Driver;
    js.ExecuteScript(code, args);
}

Driver is the web driver (IWebDriver)

Performances are not so bad and it does the job ;) Hope that it can help

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!