5

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
Omeniq
  • 178
  • 11

3 Answers3

2

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);
KunduK
  • 32,888
  • 5
  • 17
  • 41
  • Thank you for your sugestion. I also was trying to use `invisibilityOfElementLocated` but it does not work like I want in this case. When I use this, is worse because driver waits ~20 second before return 0 elements. The reason I guess is mixing both implicit and explicit waits. – Omeniq Dec 31 '19 at 09:31
  • Why this will wait for 20 seconds I have provided 10 seconds only.However If the element still there then this wait until 10 seconds only.Please update your code trail so far what you have done. – KunduK Dec 31 '19 at 09:38
  • @Omeniq : I have tested on my way If the element is not attached to page it should worked and if still attached to page it will wait for 10 seconds and throw exception.By the way you don't need to use implicit wait `WebDriverWait` will handle that. – KunduK Dec 31 '19 at 10:18
  • I know that it works without implicit wait for this particular case but I need implicit wait for whole project. When I disable implicit wait then it works as you said, but tests crashes in many other places. Finally I've handled that by disabling/enabling implicit wait for this assertion only. – Omeniq Dec 31 '19 at 10:25
1

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?

undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
  • 1
    Thank you for your answer. I wasn't aware about stalenessOf method. Unfortunately this does not work for me, not sure why, everytime I get `NoSuchElementException`. Maybe the problem is an Angular App and it won't work with Selenium smoothly :) However I can accept this answer (and your link to anohter question) because it gives me some light about problem with both 'waits' in Selenium. Probably I will use the solution with disabling/enabling or decreasing time from 10 to eg. 2 sec of ImplicitWait for this assertion. – Omeniq Dec 30 '19 at 07:38
0

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);
}    
Mr Cas
  • 628
  • 1
  • 6
  • 12