How to add synchronization to driver.findElement(by)
driver.findElement(by) finds an element that is present in the DOM, regardless of the element state (visible, hidden, clickable).
If the element is in the DOM, driver.findElement() finds it. If the element is not yet in the DOM, driver.findElement() throws an exception.
For this reason, any Selenium automated test should wait for an element to be present with a specific state (enabled, visible, hidden) before the element is used.
This is done with explicit waits and expected conditions (not with implicit waits) as follows:
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(30));
wait.until(ExpectedConditions.visibilityOfElementLocated(by));
WebElement label = driver.findElement(by);
String labelText = label.getText();
Or
wait.until(ExpectedConditions.elementToBeClickable(by));
WebElement link = driver.findElement(by);
link.click();
Or
wait.until(ExpectedConditions.elementToBeClickable(by));
WebElement textbox = driver.findElement(by);
textbox.sendKeys(keyword);
The problem with synchronization is that it needs to be done every time before an element is found.
This generates a lot of duplicated code.
How can we remove the duplicated code?
One way of removing the duplicated code would be by creating a utility class with static methods as follows:
public class Utilities {
private static final int TIMEOUT = 30;
public static void waitAndClick(By by, WebDriver driver) {
WebDriverWait wait = new WebDriverWait(driver,
Duration.ofSeconds(TIMEOUT));
wait.until(ExpectedConditions.elementToBeClickable(by));
WebElement element = driver.findElement(by);
element.click();
}
public static void waitAndType(By by, String keyword, WebDriver driver) {
WebDriverWait wait = new WebDriverWait(driver,
Duration.ofSeconds(TIMEOUT));
wait.until(ExpectedConditions.elementToBeClickable(by));
WebElement textbox = driver.findElement(by);
textbox.sendKeys(keyword);
}
public static String waitAndGetText(By by, WebDriver driver) {
WebDriverWait wait = new WebDriverWait(driver,
Duration.ofSeconds(TIMEOUT));
wait.until(ExpectedConditions.visibilityOfElementLocated(by));
WebElement element = driver.findElement(by);
return element.getText();
}
//other similar methods
}
The previous code can be changed with
String labelText = Utilities.waitAndGetText(by, driver);
Utilities.waitAndClick(by, driver);
Utilities.waitAndType(by, keyword, driver);
The code is much shorter and without any code duplication.
Still, this approach is not good because:
utility classes are a bad practice
each method does too many things:
waiting for the element
finding the element
interacting with the element
static methods should be avoided as they lead to code that is not object oriented
each method needs the driver as parameter
What is the better way?
Keep reading with a 7-day free trial
Subscribe to Selenium For Beginners to keep reading this post and get 7 days of free access to the full post archives.