给定一个 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;
}
}
如果您有针对此问题的其他解决方案,我也会很高兴。
答案 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));
}