1

Suppose there is a HTML block

<div id='list'>
   <p>hello</p>
   <div class='locked'>world</div>
   <p>你好</p>
   <div class='locked'>世界</div>
</div>

how to use selenium with python to wait for a while until all the <div class='locked'> tags become something else.(eg. <div class='unlock'>xxx</div>

Thanks!

undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
X.C.
  • 703
  • 9
  • 18
  • 1
    Hi, please tell what have you tried and what language do you use? – Yevgen Mar 04 '20 at 12:12
  • I am using python. I tried "WebDriverWait(driver, 10).until(EC.invisibility_of_element_located) " , but this is only for one element. – X.C. Mar 04 '20 at 12:15

3 Answers3

4

One could write a custom expected condition checking for the specific state that you need to attain. Like in your scenario you want the controls with locked state or class to be at count 0 to proceed further. I have given a sample of the code that could be used for custom Sync function I am new to python based Selenium but it think this should do the trick assuming you are using xpath for identifying the locked state controls.

--------------Updated with Python Code---------------------------

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

class WaitForLockStateChange:
def __init__(self, locator):
    self.locator = locator

def __call__(self, driver):
    return len(driver.find_elements_by_xpath(self.locator)) == 0 


wait = WebDriverWait(driver, 10)
element = wait.until(WaitForLockStateChange("//div[@class='locked']"))
X.C.
  • 703
  • 9
  • 18
Gleeson
  • 231
  • 2
  • 5
  • Could you write in python please? I am not familar with Java.. But the idea to check the count of elements sounds good. I will have a try first. – X.C. Mar 04 '20 at 12:34
1

I've got a custom built class I created for a very similar purpose (in my case I was interested in "value" property changes, but I modified it to fit your "class" change example):

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

class WaitForAttrValueChange:
    def __init__(self, locator, val_):
        self.locator = locator
        self.val = val_

    def __call__(self, driver):
        try:
            attr_value = EC._find_element(driver, self.locator).get_property('className')
            return attr_value.startswith(self.val)
        except SE.StaleElementReferenceException:
            return False 

You can then use it with WebDriverWait(obviously you can use any By identification method instead of By.ID, this is just an example):

WebDriverWait(driver, 20).until(WaitForAttrValueChange((By.ID, 'id'), 'locked'))
0buz
  • 3,443
  • 2
  • 8
  • 29
  • But this seems only to detect one web element. – X.C. Mar 04 '20 at 12:30
  • 1
    Loop through all the divs you need checking. Update your question with how you identify **all** elements in scope please, and I will update the answer accordingly. – 0buz Mar 04 '20 at 12:43
  • Loop through all the divs and check it one by one should also be good. Thanks. – X.C. Mar 05 '20 at 01:40
0

Using Selenium with to wait for all the <div class='locked'> tags become <div class='unlock'>xxx</div> you have to induce WebDriverWait for the visibility_of_all_elements_located() and you can use either of the following Locator Strategies:

  • Using CSS_SELECTOR:

    WebDriverWait(driver, 10).until(EC.visibility_of_all_elements_located((By.CSS_SELECTOR, "div#list div.unlock")))
    
  • Using XPATH:

    WebDriverWait(driver, 10).until(EC.visibility_of_all_elements_located((By.XPATH, "//div[@id='list']//div[@class='unlock']")))
    
  • Note : You have to add the following imports:

    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support import expected_conditions as EC
    
undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
  • 2
    This won't work because if only one element currently matches `div.unlock` then the wait will end. OP is asking about how to detect that there are 0 `div.lock` elements. – JeffC Mar 05 '20 at 00:42