Selenium WebDriver is one of the most popular tools for automating web application testing. Even though Selenium is a very robust test framework, there are common pitfalls that can lead to exceptions (error messages) during test execution.
Exception handling is a crucial skill for any Selenium tester, as it helps to improve test robustness, prevents abrupt failures and provides insight into underlying issues.
In this article we will explore the top 5 exceptions that are commonly encountered in Selenium WebDriver tests and offer solutions or workarounds.
NoSuchElementException
The NoSuchElementException
occurs when Selenium WebDriver is unable to locate an element on the webpage. This exception is typically thrown when:
- The element locator is incorrect or has changed.
- The element takes time to load and the test script attempts to interact with the element, before it appears on the page or is present in the DOM.
- The page is dynamic and the elements are being updated in real-time (for example through AJAX or JavaScript and WebSockets).
There are some strategies you can use to prevent this type of exception. Some of the most useful workarounds or preventions include:
-
Double-check the Locator: Make sure the locator (e.g.,
By.id()
,By.xpath()
,By.cssSelector()
) is accurate and it uniquely identifies the element you want to interact with. -
Use Explicit Waits:
Use WebDriver's explicit waits (WebDriverWait) to wait until a specific element condition is met, ensuring the element is present before interacting with it.
- Dynamic Locator Strategies: If the element locator is dynamic, consider using more flexible locators like XPath or CSS selectors to match patterns, or use attributes that are more stable over time.
- Page Synchronization: Use synchronization techniques to make sure the webpage is fully loaded before interacting with the elements.
StaleElementReferenceException
The StaleElementReferenceException occurs when the reference to an element is no longer valid. This generally happens when:
- The DOM has been updated or changed after the element was located.
- The page has been refreshed, causing previously referenced elements to become "stale."
Here are some strategies you can use to prevent StaleElementReference exceptions.
-
Re-locate the Element:
When the exception occurs, attempt to re-locate the element to get a fresh reference.
-
Use Explicit Waits:
Explicit waits can help to ensure that elements are interacted with only after the DOM has stabilized.
- Try-Catch Block: Implement a try-catch block to handle the StaleElementReferenceException and re-attempt the action after a small wait.
TimeoutException
The TimeoutException occurs when a command or wait fails to complete within a specified time. This usually happens when:
- An explicit wait condition is not met within the allotted time.
- The page takes longer than expected to load.
- Network or server issues are slowing down page response times.
Some possible workarounds for timeout exceptions are listed below:
-
Increase Timeout Duration:
Increase the wait time for WebDriverWait or page load time to accommodate slower loading pages.
-
Use Multiple Wait Strategies:
Combine different types of waits (implicit, explicit, or fluent waits) to handle different scenarios effectively.
- Check Network Conditions: If the issue is related to network instability, consider running tests during low-traffic hours or using local test environments to avoid such delays.
ElementNotInteractableException
The ElementNotInteractableException is thrown when an element is present in the DOM but is not interactable. This can happen when:
-
The element is hidden (e.g., hidden input fields or elements with
display: none
CSS). - The element is covered by another element, such as a loading spinner or popup.
- The element has not yet loaded completely.
Some possible solutions to prevent not-interactable exceptions include:
-
Scroll Into View:
If the element is present but not visible, use JavaScript to scroll it into view before interacting with it.
-
Wait for Visibility:
Use an explicit wait to ensure the element is visible before interacting with it.
-
Handle Overlapping Elements:
Ensure there are no other elements (e.g., popups) overlapping the target element. Consider using JavaScript to click the element if it remains covered.
WebDriverException
The WebDriverException is a generic exception that can occur due to many reasons, such as:
- Issues with the WebDriver executable (e.g., ChromeDriver, GeckoDriver) not starting or stopping unexpectedly.
- Browser crashes or WebDriver losing the connection to the browser instance.
- Incompatibility between the WebDriver and the browser version.
The number one workaround for these type of exceptions is to use TestingBot! We make sure machines are properly updated, have adequate CPU + RAM and that all versions are compatible.
-
Match WebDriver and Browser Versions:
Ensure the WebDriver version matches the browser version. For example, ChromeDriver should be compatible with the installed version of Chrome.
-
Check System Resources:
If browser crashes are frequent, make sure that the system has adequate resources (CPU, RAM and IO) to run both the tests and the browser.
-
Handle Overlapping Elements:
Ensure there are no other elements (e.g., popups) overlapping the target element. Consider using JavaScript to click the element if it remains covered.
General Exception Handling Strategies in Selenium WebDriver
While specific solutions for the top exceptions are essential, having a general strategy for handling unexpected exceptions in Selenium WebDriver can significantly improve your test reliability. Below we will go over a few effective strategies that you can utilize.
1. Graceful Error Handling
Implement try-catch blocks in your test code to handle exceptions gracefully without causing abrupt test failures.
try {
WebElement element = driver.findElement(By.id("someElement"));
element.click();
} catch (NoSuchElementException e) {
System.out.println("Element not found, skipping test.");
}
2. Retry Logic
For flaky tests, implement retry logic to attempt actions more than once in case of failure. This helps deal with intermittent issues such as network latency or timing issues.
public void clickWithRetry(By locator, int attempts) {
int retries = 0;
while (retries < attempts) {
try {
driver.findElement(locator).click();
return;
} catch (Exception e) {
retries++;
if (retries == attempts) {
throw e;
}
}
}
}
3. Page Object Model (POM)
Implementing a Page Object Model can reduce the impact of changes in the DOM and make exception handling more centralized and efficient. By encapsulating element locators and interactions, it's easier to handle changes and exceptions in one place.
public class LoginPage {
private WebDriver driver;
private By usernameField = By.id("username");
private By passwordField = By.id("password");
private By loginButton = By.id("loginBtn");
public LoginPage(WebDriver driver) {
this.driver = driver;
}
public void login(String username, String password) {
driver.findElement(usernameField).sendKeys(username);
driver.findElement(passwordField).sendKeys(password);
driver.findElement(loginButton).click();
}
}
4. Logging and Reporting
Add logging to track what happens during test execution, especially in the event of an exception. Libraries like Log4j can be integrated with Selenium to provide detailed logs, which are extremely helpful for diagnosing issues.
import org.apache.log4j.Logger;
public class TestLogger {
private static Logger log = Logger.getLogger(TestLogger.class);
public static void main(String[] args) {
log.info("Test execution started");
try {
// Test code here
} catch (Exception e) {
log.error("An error occurred: ", e);
}
log.info("Test execution ended");
}
}
5. Use TestingBot
Selenium Grids such as TestingBot's Grid, can be highly beneficial in preventing some of the common exceptions encountered in Selenium WebDriver tests. By distributing test execution across multiple environments and configurations, TestingBot Grid helps with:
-
Reduced Test Flakiness:
Running tests in parallel on multiple browsers and operating systems helps in identifying environment-specific issues, thus reducing flakiness.
-
Improved Resource Utilization:
The TestingBot Grid allows scaling up test execution by running tests simultaneously, reducing the load on individual systems and improving reliability.
-
Testing Different Configurations:
TestingBot's Selenium Grid offers access to a wide range of browser and operating system configurations, ensuring that issues like WebDriverException due to incompatibility can be identified and addressed early.