Does Selenium findElements() have to implicitly wait to return 0 elements?

1.7k Views Asked by At

I come here with a question about Selenium. In my test, I need to delete some item in web app and then I want to verify if items list is empty. I know that it looks trivial but I have some small problem. This is how I want to check if my items list is empty:

Assert.assertEquals(page.getSearchResultList().size(), 0);

Simply and works but... slow because of implicitlyWait.

driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

Due to fact when I delete item, then getSearchResultList().size() is 0 and Selenium always waits 10 seconds before findElements() returns 0 size.

To avoid this 10 seconds waiting I have a workaround to modify implicitlyWait just before my Assertion but I think it's not a good idea.

page.getDriver().manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
Assert.assertEquals(page.getSearchResultList().size(), 0);

Is there any another, better solution?

Update for request @KunduK

Assert without WebDriverWait:

    Instant start = Instant.now();
    List<WebElement> resultSearchList = page.getDriver().findElements(By.cssSelector("[ng-repeat='searchResult in $ctrl.searchResults']"));
    Assert.assertEquals(resultSearchList.size(), 0);
    Instant stop = Instant.now();
    log.debug("Assert Took: " + Duration.between(start, stop).getSeconds() + " sec");

Output:

10:49:59.081 [main] DEBUG impl.AssertNewEntityPage - Assert Took: 10 sec

Assert with WebDriverWait

    Instant start = Instant.now();
    new WebDriverWait(page.getDriver(), 10).until(ExpectedConditions.invisibilityOfElementLocated(By.cssSelector("[ng-repeat='searchResult in $ctrl.searchResults']")));
    List<WebElement> resultSearchList = page.getDriver().findElements(By.cssSelector("[ng-repeat='searchResult in $ctrl.searchResults']"));
    Assert.assertEquals(resultSearchList.size(), 0);
    Instant stop = Instant.now();
    log.debug("Assert Took: " + Duration.between(start, stop).getSeconds() + " sec");

Output:

10:57:08.215 [main] DEBUG impl.AssertNewEntityPage - Assert Took: 20 sec
3

There are 3 best solutions below

1
On BEST ANSWER

stalenessOf()

stalenessOf() is the expectation to wait until an element is no longer attached to the DOM.


This usecase

This usecase of ...deleting an item in web app... maps to the ExpectedConditions of stalenessOf(WebElement element). So effectively your code block will be:

new WebDriverWait(driver, 10).until(ExpectedConditions.stalenessOf(By.cssSelector("cssSelector_of_element_to_be_stale")));
Assert.assertEquals(page.getSearchResultList().size(), 0);

Note: As your usecase already involves implicitlyWait and this answer suggests to induce WebDriverWait i.e. ExplicitWait, as per the documentation, ...Do not mix implicit and explicit waits. Doing so can cause unpredictable wait times. For example setting an implicit wait of 10 seconds and an explicit wait of 15 seconds, could cause a timeout to occur after 20 seconds...

You can find a relevant discussion in How to combine implicit and explicit timeouts in Selenium?

0
On

You could wait for the page to be completely loaded..

public static boolean waitForJSandJQueryToLoad() {
    log.info("Waiting for jQuery to load...");
    ExpectedCondition<Boolean> jQueryLoad = d -> {
        try {
            log.info("jQuery presented.");
            return ((Long) ((JavascriptExecutor) driver).executeScript("return jQuery.active") == 0);
        } catch (Exception e) {
            log.info("No jQuery presented.");
            return true;
        }
    };
    log.info("Waiting for javascript to load...");
    ExpectedCondition<Boolean> jsLoad = d -> ((JavascriptExecutor) driver).executeScript("return document.readyState")
            .toString().equals("complete");
    return wait.until(jQueryLoad) && wait.until(jsLoad);
}    
4
On

You can use ExpectedConditions.invisibilityOfElementLocated() to wait for element invisible and then take the size() of the elements.

new WebDriverWait(driver, 10).until(ExpectedConditions.invisibilityOfElementLocated(By.xpath("locator xpath")));
List<WebElement> elements = driver.findElements(By.xpath("locator xpath"));
Assert.assertEquals(elements.size(), 0);