bc14
bc14

Reputation: 39

How can I wait for a page loader, which appears and disappears based on API call, to disappear before performing action on element

As the title states, I am trying to perform an action (i.e., sendkeys or click etc.) on an element but the loader (which has ID) is making the action inconsistent.

I have tried quite a few different methods, now I am onto a gimmicky method of sorts with using thread sleep which works semi-consistently, but still gets false-positives to move forward once in a while which results in test failure.

The loader (id="spinner") disappears from the page after an API call completes (sending a signal to script that it is good to go forward), but upon the start of the next call, the loader comes back, and then disappears upon completion for (currently) 3 API calls. I would like to devise a way for this to work regardless of how many calls are implemented.

public void Loader()
{    
   WebDriverWait wait=new WebDriverWait(driver,50);
   WebElement CPloader = driver.findElement(By.id("spinner"));
   boolean test = wait.until(ExpectedConditions.invisibilityOfElementLocated(By.id("spinner")));         

   if(test==false) {
       wait.until(ExpectedConditions.invisibilityOfElementLocated(By.id("spinner")));
       wait.until(ExpectedConditions.invisibilityOf(CPloader));
       threadsleep(2000);
       wait.until(ExpectedConditions.invisibilityOfElementLocated(By.id("spinner")));
       wait.until(ExpectedConditions.invisibilityOf(CPloader));
       threadsleep(2000);
       wait.until(ExpectedConditions.invisibilityOfElementLocated(By.id("spinner")));
       wait.until(ExpectedConditions.invisibilityOf(CPloader));
   }

}

In the test script code, I am usually putting loader method, threadsleep, loader method in an attempt to get it to hold off for long enough but I know this isn't proper... example below:

Util.Loader();
Util.threadsleep(2000);
Util.Loader();
//click element or send keys etc

I am imagining this to be a loop of sorts with an invisibility wait but can't seem to figure it out.

Any pointers in the right direction would be of great help.

Upvotes: 0

Views: 1606

Answers (2)

JeffC
JeffC

Reputation: 25714

I would approach this by waiting for the loader to appear then disappear... and do this in a loop. Once the loader stops appearing, the wait will throw a TimeoutException. Catch that with a try-catch and break out of the loop. You may need to tweak the 10s wait up or down depending on how much time generally passes between loading spinners.

public static void Loader()
{
    By loader = By.id("spinner");
    WebDriverWait wait = new WebDriverWait(driver, 10);
    while (true)
    {
        try
        {
            wait.until(ExpectedConditions.visibilityOfElementLocated(loader));
            wait.until(ExpectedConditions.invisibilityOfElementLocated(loader));
        }
        catch (Exception e)
        {
            break;
        }
    }
}

Upvotes: 1

undetected Selenium
undetected Selenium

Reputation: 193338

AS you mentioned the loader (which has ID) is making the action inconsistently so instead of invoking invisibilityOfElementLocated() method for the loader you can invoke elementToBeClickable() method for the desired element for which you intent to invoke click() or sendKeys() as follows :

  • Using cssSelector and click :

    new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.cssSelector("cssSelector_of_element_to_interact"))).click();
    
  • Using xpath and sendKeys :

    new WebDriverWait(driver, 30).until(ExpectedConditions.elementToBeClickable(By.xpath("xpath_of_element_to_interact']"))).sendKeys("Test");
    

Upvotes: 0

Related Questions