Waiting for UI events


When running Selenium tests, in many situations one would like to wait to for some event to take place, before performing an action. For example, after clicking a button, one would need to wait for an element to be displayed until the test can use that element (the element being displayed is the event, using it is the action).

Selenium has a mechanism of waiting for the page to load, for those situations when an action causes a page refresh. In this case, if the button click will cause a page load, the test that interacts with the element to be displayed is very simple:

button.click();

element.performSomeAction();

Here, the button click will perform a page refresh, which takes some amount of time. The action to be performed on the button will be performed only after the page has loaded, that being the same time when the button is available to be interacted with. This is due to the implicit waiting mechanism of Selenium.

In a more complex scenario, where the initial event does not trigger a page refresh, performing the action right after the event will, in most cases, fail, as there is a time needed to pass between the event and the actual action, for the element to have time to be displayed.

There also other scenarios when the page refresh does not occur, or when more than one refresh is occurring, and other types of events to be waited for, like:

  • for the text on an element to have a particular value
  • for the text on an element to contain some value
  • for the attribute of an element to have a particular value
  • for the element not to be displayed anymore
  • for the URL of the page to be a specific one (for example when, after an event, the page gets redirected to another page, then another one, then another one, and so on. In this case you want to perform the action when the page that is loaded has the correct URL).
ExpectedCondition

The most flexible way to wait for any action that is needed, is by using ‘WebDriverWait‘ in conjunction with ‘ExpectedCondition‘ (which is an interface). For example, to wait for 10 seconds for an element to be displayed, can be done by creating the following method:

private void waitUntilElementDisplayed(WebElement webElement) {
WebDriverWait wait = new WebDriverWait(driver, 10);
ExpectedCondition<Boolean> elementIsDisplayed = new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver arg0) {
     return webElement.isDisplayed();
    }
};
wait.until(elementIsDisplayed);
}

What this method does is, for 10 seconds (mentioned as the second parameter in the WebDriverWait constructor), at every half a second, it checks whether the condition that is required is fulfilled. If it is not, the value of ‘elementIsDisplayed’ is false, otherwise it becomes true. Once the value of the ‘elementIsDisplayed’ parameter becomes true, the method exits, and the test will not wait anymore. That is, if the parameter became true in the time interval specified in the test. In this case, the test does not wait for the whole 10 seconds, but exits just as soon as the condition becomes true. If during the specified time  the parameter does not become true, the method exits with an org.openqa.selenium.TimeoutException exception. The body of the ‘apply’ method described above can be replaced by whatever condition needs to be fulfilled, as long it is evaluated to a boolean.

For example, for waiting for the URL opened in the browser to be a  specificied one, the method depicted above will becone:

private void waitUntilCurrentURLIs(String expectedURL) {
WebDriverWait wait = new WebDriverWait(driver, 10);
ExpectedCondition<Boolean> urlIsAsExpected = new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver arg0) {
     return driver.getCurrentUrl().equals(expectedURL);
    }
};
wait.until(urlIsAsExpected);
}

The parameter that is passed to this method is the URL that needs to be opened in the browser at some point. The method will wait for up to 10 seconds for this URL to be the one opened in the browser instance that it runs the test against.  Of course, the value of the timeout can be changed to whatever is suitable for the testing situation.

ExpectedConditions

If this way of waiting for events to occur seems complicated, there is another way to perform it, by using ‘WebDriverWait‘ again, but this time in conjunction with the methods of the ‘ExpectedConditions‘ class (this is different from the ‘ExpectedCondition’ interface mentioned in the above examples). This method to wait for events is not as flexible as the previous one, where you could wait for basically whatever event you wanted. The ‘ExpectedConditions’ class has only around 20 methods to be used, like: waiting for an element to be visible or waiting for it not to be displayed anymore, for the element to be clickable or for it to be selected, and so on. For the full list of the methods, the following reference should be read: http://selenium.googlecode.com/svn/trunk/docs/api/java/org/openqa/selenium/support/ui/ExpectedConditions.html .

The usage of any of the methods belonging to this class is exemplified here, on the visibilityOfElementLocated method, which takes a selector as its’ parameter:

WebDriverWait wait = new WebDriverWait(driver, 10);       wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("someSelector")));

All this does is wait for 10 seconds for the element obtained by evaluating the cssSelector to be displayed.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s