Selenium Javascript:检查元素是否匹配 By-object

时间:2021-01-13 18:36:15

标签: javascript selenium-webdriver

给定一个 WebElement 和一个 By 对象,是否可以找出元素是否与这个 By 对象匹配? 该函数应返回 true 或 false。

例如

foo(myWebElement, By.className("myClass myClass2"));
foo(myWebElement, By.css("div"));
foo(myWebElement, By.id("idA"));

我正在尝试编写一个函数,该函数给出一个 WebElement 和一个 By 对象,它应该返回与 By 对象匹配的第一个父元素。到目前为止,这是我所拥有的,但缺少 doesElementMatch 函数:

const findParentElement = async (current, by) => {
  try {
    do {
      element = await element.findElement(By.xpath("./.."));
    } while (!doesElementMatch(element, by);

    return element;
  } catch (e) {
    // reached top of DOM
    return null;
  }
}

如果您有针对此问题的其他解决方案,我也会很高兴。

2 个答案:

答案 0 :(得分:0)

我还没有找到这个问题的答案,但我还是解决了我的问题。我会在这里分享,也许会有所帮助。

错误的想法

我的想法是找到所有具有与给定 By-selector 匹配的父元素的元素,例如'p' 具有 div,类为 myClass 作为父级。

我的方法是首先选择子元素,然后使用问题中的函数检查它是否具有某个父元素。

工作方法

最好先选择所有匹配 By-selector 的父元素,然后逐个查找子元素。例如

let parents = await driver.findElement(By.css("div.myClass"));
for (let i = 0; i < parents.length; i++) {
  let child = await parents[i].findElement(By.css("p");
  if (child)
    return child;
}
  

其他工作方法

也可以仅使用带有字符 > 的 css 选择器来执行上述操作。例如div.myClass>p。有关详细信息,请参阅 here

答案 1 :(得分:0)

IceRevenge 发布的解决方案对我不起作用,因为我无法预过滤我的顶级元素。我正在处理一个 bug in FireFox,您无法在没有错误的情况下获取根 shadowDom 元素,因此您必须获取整个子项列表。

这是我想出来的。这并不理想,但也不可怕。

private <T> T noSuchElementNull(Supplier<T> supplier) {
    try {
        return supplier.get();
    } catch (NoSuchElementException ex) {
        return null;
    }
}

private WebElement getMatchingShadowDomChild(
        final List<WebElement> children,
        final Function<WebElement, Boolean> topLevelSearch,
        final Function<WebElement, WebElement> grandChildSearch,
        final String errorMessage
) {
    Optional<WebElement> child = children.stream()
            .filter(topLevelSearch::apply)
            .findFirst();
    if (child.isPresent()) {
        return child.get();
    }

    Optional<WebElement> grandChild = children.stream()
            .map(c -> noSuchElementNull(() -> grandChildSearch.apply(c)))
            .filter(Objects::nonNull)
            .findFirst();

    return grandChild.orElseThrow(() -> new NoSuchElementException(errorMessage));
}

然后我可以在大多数用例中非常干净地使用它:

private List<WebElement> getShadowDomChildren(final WebElement rootElement) {
    return (List<WebElement>) ((JavascriptExecutor) browser.getWebDriver())
            .executeScript("return arguments[0].shadowRoot.children", rootElement);
}

private WebElement getInnerShadowElementByTagName(final WebElement rootElement, 
                                                    final String tagName) {
    List<WebElement> children = getShadowDomChildren(rootElement);
    return getMatchingShadowDomChild(
            children,
            c -> StringUtils.equalsIgnoreCase(c.getTagName(), tagName),
            c -> c.findElement(By.tagName(tagName)),
            String.format("Unable to find an inner element with TagName=[%s]", tagName));
}