22

How can I use WebDriverWait to wait until an attribute changes?

In my AUT I have to wait for a button to become enabled before continuing, unfortunately due to the way the developer coded the page I can't use WebElement's isEnabled() method. The developer is using some CSS to just make the button look like it's disabled so the user can't click on it and the method isEnabled always returns true for me. So what I have to do is get the attribute "aria-disabled" and check whether the text is "true" or "false". What I've been doing so far is a for loop with Thread.sleep, something like this:

for(int i=0; i<6; ++i){
    WebElement button = driver.findElement(By.xpath("xpath"));
    String enabled = button.getText()
    if(enabled.equals("true")){ break; }
    Thread.sleep(10000);
 }

(disregard the code above if incorrect, just pseudo code of what I'm doing)

I'm sure there's a way to achieve something similar using WebDriverWait which is the preferred method I just can't figure out how. This is what I'm trying to achieve even though the following won't work:

WebDriverWait wait = new WebDriverWait(driver, 60);
wait.until(ExpectedConditions.visibilityOf(refresh.getText() == "true")); 

Obviously it doesn't work because the function is expecting a WebElement not String but it's what I'm trying to evaluate. Any ideas?

T J
  • 42,762
  • 13
  • 83
  • 138
so cal cheesehead
  • 2,515
  • 4
  • 29
  • 50

5 Answers5

36

The following might help your requirement. In the following code, we override apply method incorporating the condition that we are looking for. So, as long as the condition is not true, in our case, the enabled is not true, we go in a loop for a maximum of 10 seconds, polling every 500 ms (this is the default) until the apply method returns true.

WebDriverWait wait = new WebDriverWait(driver,10);

wait.until(new ExpectedCondition<Boolean>() {
    public Boolean apply(WebDriver driver) {
        WebElement button = driver.findElement(By.xpath("xpath"));
        String enabled = button.getAttribute("aria-disabled");
        if(enabled.equals("true")) 
            return true;
        else
            return false;
    }
});
ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
Sridevi Yedidha
  • 1,183
  • 1
  • 12
  • 13
2

If someone wants to use @Sri as a method in a Selenium wrapper, here is a way to do it (thanks to this answer btw):

public void waitForAttributeChanged(By locator, String attr, String initialValue) {
    WebDriverWait wait = new WebDriverWait(this.driver, 5);

    wait.until(new ExpectedCondition<Boolean>() {           
        private By locator;
        private String attr;
        private String initialValue;

        private ExpectedCondition<Boolean> init( By locator, String attr, String initialValue ) {
            this.locator = locator;
            this.attr = attr;
            this.initialValue = initialValue;
            return this;
        }

        public Boolean apply(WebDriver driver) {
            WebElement button = driver.findElement(this.locator);
            String enabled = button.getAttribute(this.attr);
            if(enabled.equals(this.initialValue)) 
                return false;
            else
                return true;
        }
    }.init(locator, attr, initialValue));
}
Community
  • 1
  • 1
Arthur
  • 3,717
  • 7
  • 28
  • 44
1

You can use the xpath to define the element with an attribute of your desired value and then wait until it occurs on the page. In Python it could look like this:

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC    

xp = '//*[@id="element_id"][@aria-disabled="false"]'
WebDriverWait(browser, 60).until(EC.presence_of_element_located((By.XPATH, xp)))
Miro
  • 49
  • 9
0

This worked for me when automating against a pretty slow bootstrap page waiting for the sort button to take effect.

    new WebDriverWait(webDriver, 10)
.until(ExpectedConditions.attributeContains(BUTTON_SORT_ASCENDING_PRICE, "class", "sortButtonActive"));
  • "webDriver" - my current instance of WebDriver
  • "10" - timeout seconds
  • "BUTTON_SORT_ASCENDING_PRICE" - The By locator for the element
  • "class" - the attribute
  • "sortButtonActive" - the value of 'class' i am waiting for

Selenium V3.01

0

It can also be done using a simple do-while loop, System.currentTimeMillis(); method can be used to avoid an infinite loop

long startTime = System.currentTimeMillis();
String disabled;
do{
   disabled = element.getAttribute("attributeName").trim();
}while(disabled!="false" && System.currentTimeMillis()-startTime<10000);
Mohammad Faisal
  • 573
  • 5
  • 13