如何将明确等待的条件缩小到给定的 SearchContext?

How do I narrow down the condition of an explicit wait to a given SearchContext?

我想等到特定视图消失。一般来说,我可以用下面的代码来完成:

val wait = WebDriverWait(driver, Duration.ofSeconds(3)) // where driver is e.g. WebDriver
val condition = ExpectedConditions.invisibilityOfElementLocated(
    By.id("my.app:id/someId") // or another locator, e.g. XPath
)
wait.until(condition)

但是,这种方式不是很精确。

想象一个场景,两个不同的视图匹配同一个谓词(定位器)。在下面的示例中,我使用了“按 ID”定位器,但它也可以是其他任何东西。

在下图中,有 3 个视图:

当我只想找到视图“C”时,例如为了点击它,我可以这样做:

driver.findElement(By.id("anotherId")).findElement("someId").click()

所以当我知道它包含视图“C”时,我可以通过首先搜索视图“B”来缩小视图“C”的搜索范围。

这是可能的,因为 findElement 方法返回的 WebElement 实现了 SearchContext 接口,就像 WebDriver 一样。因此,我可以选择是要在整个屏幕上还是在特定的 WebElement.

内搜索

如何在等待视图消失的情况下缩小搜索范围?

理想情况下,我希望是这样的:

ExpectedConditions.invisibilityOfElementLocated(
    searchContext, // either a driver or WebElement
    By.id(...) // the locator
)

但我还没有找到类似的东西。

我看过 org.openqa.selenium.support.ui.ExpectedConditions 方法..

还有一些类似的方法:

  • visibilityOfNestedElementsLocatedBy(final By parent, final By childLocator)

  • visibilityOfNestedElementsLocatedBy(final WebElement element, final By childLocator)

invisibility 没有相同的方法。

所以,我建议实施自定义的:

import org.openqa.selenium.support.ui.ExpectedCondition
import org.openqa.selenium.support.ui.ExpectedConditions

public static ExpectedCondition<Boolean> invisibilityOfNestedElementLocated(WebElement parent, By nested) {
    return new ExpectedCondition<Boolean>() {
        private boolean wasFound = false;

        @Override
        public Boolean apply(WebDriver driver) {
            wasFound = ExpectedConditions.invisibilityOfAllElements(parent.findElements(nested)).apply(driver);
            return wasFound;
        }

        @Override
        public String toString() {
            return String.format("element \"%s\" from parent \"%s\", found: \"%b\"", nested.toString(), parent.toString(), wasFound);
        }
    };
}

举个例子:

WebElement searchContext = driver.findElement(By.id("anotherId");
new WebDriverWait(driver, Duration.ofSeconds(10)).until(
    invisibilityOfNestedElementLocated(searchContext, By.id('someId'))
)