Ashraf Mulla
Ashraf Mulla

Reputation: 143

WebDriver wait is not working properly

If you open this link https://www.phptravels.net/ it shows a progress bar kind of thing and then you will see the Hotels option on the top right corner. I have tried implicit wait, WebDriverWait and fluent wait as well. when I used element.isDisplayed() it shows "true" but when I perform click operation it throws below exception.

    driver.manage().window().maximize();
        driver.get("https://www.phptravels.net/");

        String hotelsXpth = "//ul[@class='main-menu go-left RTL']/li/a/span[contains(text(),'Hotels')]";


         WebDriverWait wait = new WebDriverWait(driver, 20);
         wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath
         (hotelsXpth)));
         wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath(
         hotelsXpth)));

         System.out.println(driver.findElement(By.xpath(hotelsXpth)).isDisplayed());
         driver.findElement(By.xpath(hotelsXpth)).click();

Exception

    org.openqa.selenium.WebDriverException: unknown error: Element <span>...
 </span> is not clickable at point (705, 130). Other element would receive 
 the click: <div id="preloader" class="loader-wrapper">...</div>
  (Session info: chrome=63.0.3239.132)
  (Driver info: chromedriver=2.33.506120 
(e3e53437346286c0bc2d2dc9aa4915ba81d9023f),platform=Windows NT 10.0.14393 
x86_64) (WARNING: The server did not provide any stacktrace information)
Command duration or timeout: 0 milliseconds
Build info: version: '3.8.1', revision: '6e95a6684b', time: '2017-12-
01T18:33:54.468Z'
System info: host: 'D-113060768', ip: '10.149.34.102', os.name: 'Windows             
10', os.arch: 'amd64', os.version: '10.0', java.version: '1.8.0_121'
Driver info: org.openqa.selenium.chrome.ChromeDriver
Capabilities {acceptSslCerts: true, applicationCacheEnabled: false, 
browserConnectionEnabled: false, browserName: chrome, chrome: 
{chromedriverVersion: 2.33.506120 (e3e53437346286..., userDataDir: 
C:\Users\AS337139\AppData\L...}, cssSelectorsEnabled: true, databaseEnabled: 
false, handlesAlerts: true, hasTouchScreen: false, javascriptEnabled: true, 
locationContextEnabled: true, mobileEmulationEnabled: false, nativeEvents: 
true, networkConnectionEnabled: false, pageLoadStrategy: normal, platform: 
XP, platformName: XP, rotatable: false, setWindowRect: true, 
takesHeapSnapshot: true, takesScreenshot: true, unexpectedAlertBehaviour: , 
unhandledPromptBehavior: , version: 63.0.3239.132, webStorageEnabled: true}
Session ID: bbfef8e4da0b2a6b98181d54c454d504
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown 
Source)
    at java.lang.reflect.Constructor.newInstance(Unknown Source)

Any suggestions?

Upvotes: 0

Views: 2035

Answers (2)

JeffC
JeffC

Reputation: 25542

The problem is that Selenium knows that the Hotels link is visible, even if it's behind the "Loading..." panel. So your attempts to wait for the Hotels link to be visible, clickable, etc. will immediately pass and it will attempt the click resulting in the Exception you are seeing.

The fix is to wait for the Loading panel to close and THEN click your button. To do that, you just have to get a locator for the Loading panel and wait for it to be invisible.

Since I'm assuming you will be clicking the Hotel menu (and probably other menus) frequently, I would write a function that takes care of that for you.

public static void clickMenu(String menu)
{
    driver.findElement(By.xpath("//nav[@id='offcanvas-menu']//span[contains(.,'" + menu + "')]")).click();
}

The script itself would look like

new WebDriverWait(driver, 20).until(ExpectedConditions.invisibilityOfElementLocated(By.id("preloader"))); // wait for Loading panel to close
clickMenu("Hotels");

I would even probably suggest that since you will likely reuse the code to wait for the Loading panel to close that you put that into a function also. I'll leave that as a exercise for the reader... :)

Upvotes: 1

Bill Hileman
Bill Hileman

Reputation: 2838

I wrote this for a local project that used a shielding method by placing invisible WebElements on the page to block user input. These elements would remain while the page is "busy" and go away when it's ready to accept input. Modify the code below to check for class "preloader" instead of "blockUI" and it should work for you.

public static void waitForBlockUIToDisappear() {
    // This function checks the entire currently-loaded web page for the
    // presence of any web element of the
    // class "blockUI" and loops until there are none. The presence of an
    // element with this class does exactly
    // what it implies: it blocks user input. If you get the error that a
    // different web element would receive
    // the click, for example, this is why and you'd need to call this
    // method before doing a click. Generally,
    // this function should be implemented before sending any input to a web
    // page - click, sendkeys, select...
    String blockUI = "//*[contains(@class,'blockUI')]";
    while (true) {
        if (driver.findElements(By.xpath(blockUI)).size() == 0)
            break;
    }
    ;
}

Upvotes: 0

Related Questions