20
votes
<div id="loader-mid" style="position: absolute; top: 118.5px; left: 554px; display: none;">
    <div class="a">Loading</div>
    <div class="b">please wait...</div>
</div>

And want to wait until it disappears. I have following code but it wait sometimes too long and at some point of code it suddenly freeze all process and I don't know why.

from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait

self.wait = WebDriverWait(driver, 10)

self.wait.until(EC.invisibility_of_element_located((By.XPATH, "//*[@id='loader_mid'][contains(@style, 'display: block')]")))

and also I tried this one:

self.wait.until_not(EC.presence_of_element_located((By.XPATH, "//*[@id='loader_mid'][contains(@style, 'display: block')]")))

I don't know exactly how to check but maybe my element is always present on the page and selenium thought that it is there, the only thing that changes is parameter display changes from none to block. I think I can get attribute like string and check if there is word "block" but it is so wrong I thing... Help me please.

3
Have you tried checking for the visibility of an element that is hidden behind the loader? - ExperimentsWithCode
Yes and it didn't help me. But somehow now second variant works. strange. - Michael
Yea that is pretty weird. - ExperimentsWithCode

3 Answers

28
votes

Reiterated your answer (with some error handling) to make it easier for people to find the solution :)

Importing required classes:

from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait

Configuration variables:

SHORT_TIMEOUT  = 5   # give enough time for the loading element to appear
LONG_TIMEOUT = 30  # give enough time for loading to finish
LOADING_ELEMENT_XPATH = '//*[@id="xPath"]/xPath/To/The/Loading/Element'

Code solution:

try:
    # wait for loading element to appear
    # - required to prevent prematurely checking if element
    #   has disappeared, before it has had a chance to appear
    WebDriverWait(driver, SHORT_TIMEOUT
        ).until(EC.presence_of_element_located((By.XPATH, LOADING_ELEMENT_XPATH)))

    # then wait for the element to disappear
    WebDriverWait(driver, LONG_TIMEOUT
        ).until_not(EC.presence_of_element_located((By.XPATH, LOADING_ELEMENT_XPATH)))

except TimeoutException:
    # if timeout exception was raised - it may be safe to 
    # assume loading has finished, however this may not 
    # always be the case, use with caution, otherwise handle
    # appropriately.
    pass 
6
votes

Use expected condition : invisibility_of_element_located

This works fine for me.

from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait


WebDriverWait(driver, timeout).until(EC.invisibility_of_element_located((By.ID, "loader-mid")))
1
votes

The following code creates an infinite loop until the element disappears:

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException

while True:
        try:
            WebDriverWait(driver, 1).until(EC.presence_of_element_located((By.XPATH, 'your_xpath')))
        except TimeoutException:
            break