How To Use Thread.sleep() in Selenium
Learn how to pause test execution with Thread.sleep() in Selenium. Control timing for effective automation testing.
Join the DZone community and get the full member experience.
Join For FreeWhen performing Selenium automation testing, you might encounter a NoSuchElementException()
when the element you're trying to interact with isn't found.
This error typically occurs due to the element existing on the page but takes a considerable amount of time to load and become visible to the user. During test automation, this delay may cause significant issues and halt the execution of test scripts. This is where Thread.sleep()
in Selenium can be helpful in such cases.
In this blog, we look at how to use Thread.sleep()
in Selenium using Java.
What Are Wait Commands in Selenium?
Before we discuss the Thread.sleep()
method, let’s understand the wait
command in Selenium and its different types.
Selenium wait
commands are placed in the test scripts to tell automation to hold on for a certain amount of time or until a specific condition is met before proceeding with the next step. This prevents errors from occurring if elements on the web page aren't fully loaded or interactive yet.
Here are the different types of wait
commands in Selenium:
Implicit Waits
These waits are used to search for a WebElement
if it needs some time to load and is not immediately available. The implicit waits are globally applied to all the WebElement
s on the web page and remain in the WebDriver
object. It is non-blocking and does not wait for the entire duration, like Thread.sleep()
.
If the WebElement
is not found during the specified time, it will throw the NoSuchElementException()
.
Example:
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
Explicit Waits
These waits are used to wait for a specified time until the expected condition is met. This expected condition can be set using the class ExpectedConditions
in Selenium. Explicit waits can be applied to a specific WebElement
and do not affect the other WebElement
s on the web page. It will throw the TimeOutException
if the WebElement
is not found within the specified time.
Example:
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5)); WebElement checkoutBtn = driver().findElement(By.cssSelector("#check")); wait.until(ExpectedConditions.visibilityOf(checkoutBtn));
In the example code above, the checkout button is located using the explicit wait. The WebDriverWait
class is instantiated in which the WebDriver
instance and the time duration are provided. Using the ExpectedConditions
class, the condition is set to wait until the checkout button is visible.
Fluent Waits
These waits are more advanced and flexible than implicit and explicit waits. They allow the user to define a custom condition and the polling interval. It also provides an option to ignore the specified exceptions during the time duration while waiting for the WebElement
. This helps in waiting for the WebElement
s that may change over time.
Example:
public String successMessageText() { Wait<WebDriver> wait = new FluentWait<>(driver) .withTimeout(Duration.ofSeconds(10)) .pollingEvery(Duration.ofSeconds(2)) .ignoring(NoSuchElementException.class); WebElement successMessage = wait.until(driver -> notificationPopUp().findElement(By.tagName("p"))); return successMessage.getText();
In the above code example, the successMessageText()
method returns a text from a WebElement
using fluent wait. The Wait
interface is used to instantiate the fluent wait of 10 seconds that will be polling at a frequency of every 2 seconds, ignoring NoSuchElementException()
. Finally, it will return the text in String format.
What Is Thread.sleep() in Selenium?
To make the automated test scripts less flaky, there is a need to add waits, which will add some waiting time for an element or all the elements in the web page to load. Implementing these waits depends on the type of wait in the automation script.
The two most commonly used Selenium waits are implicit and explicit. However, there are a few instances where Thread.sleep()
in Selenium would be considered a better choice. Thread.sleep()
is a static Java method that suspends the code for a specific time. It pauses the execution and helps us to know what has happened during the pause. It accepts the time specified in milliseconds. This function is particularly helpful for debugging a website or web page.
Syntax for Thread.sleep() in Selenium
//Pauses test execution for specified time in milliseconds Thread.sleep(1000);
While using this method, you may face a common exception – InterruptedException
, which has to be handled either by using throws or try-catch blocks as shown below:
try{ Thread.sleep(1000); } catch(InterruptedException ie){ } Or public static void main(String args[]) throws InterruptedException{ Thread.sleep(1000); }
In the next sections, we will understand why and how to use Thread.sleep()
in Selenium. Let’s first take a look at why the Thread.sleep()
method is used for Selenium automation.
Why Use Thread.sleep() in Selenium?
As web applications continue to grow in complexity, their loading times vary greatly. The Thread.sleep()
method becomes essential in accounting for these varying load times within our Selenium scripts. Using Thread.sleep()
in Selenium ensures smooth execution of automated tests, preventing script failures.
Here are some key reasons why Thread.sleep()
method is used in Selenium:
Handle Dynamic Elements
There might be times when the web page has dynamic elements, and it will be hard to predict the behavior. For example, most E-commerce websites have a carousel/slider design that changes dynamically. Instead of using Selenium waits to check for the visibility of the web element, we can choose the Thread.sleep()
method to wait for a few seconds.
Debugging
The Thread.sleep()
method helps debug the web automation test failures. For example, the tests failing due to the NoSuchElementException()
can be debugged by adding a Thread.sleep()
method, allowing the code to wait for 2 to 5 seconds.
This will help in better visibility of the failure to know if the test fails as the element could not be loaded during the code execution. After adding the Thread.sleep()
method, if the test passes, then it should be noted that we can add explicit or fluent waits in the test to wait for the WebElement
to be loaded before the test moves to the next line to interact with the WebElement
.
Testing Third-Party Components
When testing web pages that interact with third-party components, it is important to understand how they were designed instead of knowing how long it takes for a WebElement
to be visible on the web page. Hence, predicting the conditions to handle the WebElement
s seems complex and sometimes even impossible. In such situations, we can delay the execution time using the Thread.sleep()
method.
Handle AJAX Calls
Asynchronous JavaScript and XML (AJAX) are advanced communication techniques that allow the web page to request specific information from the server without affecting the current state of the web page. The Thread.sleep()
method will be one of the best choices to handle the AJAX calls on the web page, as the test would wait a certain period for the server to respond.
Difference Between Selenium Waits and Thread.sleep()
In this section, we will dig deeper into the difference between Selenium waits and the Thread.sleep()
method.
Aspect | Selenium Waits (Implicit, Explicit, Fluent) | Thread.sleep() |
---|---|---|
Belongs to | Selenium framework | Thread class of Java |
Execution Suspension | Waits until a specified condition is met or a timeout occurs | Ceases execution thread for a specified time |
Script Execution | Moves to the next line if the element is found before the specified time | Pauses script execution, regardless of element presence |
Applicability | Applies globally; it needs to be written once for the entire WebDriver instance. | Needs to be written for each web element |
Impact on Script Execution Time | Helps reduce script execution time | Increases script execution time |
Preferred Option in Selenium Java | Preferred due to efficient handling of element wait conditions | Less preferred due to its blocking nature |
Demo: Using Thread.sleep() in Selenium for Test Automation
In this section, let’s dive into the demonstration and check how to implement the Thread.sleep()
in Selenium Java.
To showcase its implementation, we will use an example of the LambdaTest eCommerce Playground website. The tests will be executed on a cloud-based testing platform like LambdaTest using Chrome browser on Windows 10.
Test Scenario
- Navigate to the Account Login page.
- Enter the valid details in the E-Mail Address and Password fields and click the Login button.
- After successful login, wait for the next page to load using the
Thread.sleep()
method and verify the page header shows the text My Account on the page.
Login Page - LambdaTest eCommerce Playground Website
My Account Page - LambdaTest eCommerce Playground Website
Test Implementation
Let’s first create a new Java class file named ThreadSleepDemoTests.java
. This class will have all implementations of the test scenario as well as the configuration required for running the tests on the LambdaTest Cloud Grid.
public class ThreadSleepDemoTests { private WebDriver driver; // … }
The setup()
method is created inside the ThreadSleepDemoTests
class, which has the configuration details to run the test on the LambdaTest online Selenium Grid.
@BeforeTest public void setup() { final String userName = System.getenv("LT_USERNAME") == null ? "LT_USERNAME" : System.getenv("LT_USERNAME"); final String accessKey = System.getenv("LT_ACCESS_KEY") == null ? "LT_ACCESS_KEY" : System.getenv("LT_ACCESS_KEY"); final String gridUrl = "@hub.lambdatest.com/wd/hub"; try { this.driver = new RemoteWebDriver(new URL("http://" + userName + ":" + accessKey + gridUrl), getChromeOptions()); } catch (final MalformedURLException e) { System.out.println("Could not start the remote session on LambdaTest cloud grid"); } }
LambdaTest Username and Access Key values are mandatory values without which the tests can not be run on the LambdaTest cloud platform. As these are confidential values, they should not be hardcoded in the code. We will pass these values using environment variables.
Some more capabilities related to the LambdaTest platform, such as browser name, browser version, test name, build name, etc., need to be passed to run the tests on the LambdaTest Cloud Grid. These capabilities can easily be set using the LambdaTest Automation Capabilities Generator. The configuration values will be passed by creating a new method getChromeOptions()
in the ThreadSleepDemoTests
class:
public ChromeOptions getChromeOptions() { final var browserOptions = new ChromeOptions(); browserOptions.setPlatformName("Windows 10"); browserOptions.setBrowserVersion("123.0"); final HashMap<String, Object> ltOptions = new HashMap<String, Object>(); ltOptions.put("project", "Thread.sleep Demo on Cloud"); ltOptions.put("build", "LambdaTest e-commerce website test"); ltOptions.put("name", "Thread.sleep demo test"); ltOptions.put("w3c", true); ltOptions.put("plugin", "java-testNG"); browserOptions.setCapability("LT:Options", ltOptions); return browserOptions; }
As mentioned earlier, we will be running the tests on the Chrome browser on a Windows 10 machine. These respective capabilities are provided in the above method.
The following @Test
method will implement the test scenario we discussed earlier for the demo:
@Test public void testLogin() throws InterruptedException { this.driver.get("https://ecommerce-playground.lambdatest.io/index.php?route=account/login"); final WebElement emailAddress = this.driver.findElement(By.id("input-email")); emailAddress.sendKeys("david.thomson@gmail.com"); final WebElement password = this.driver.findElement(By.id("input-password")); password.sendKeys("Secret@123"); final WebElement loginBtn = this.driver.findElement(By.cssSelector("input.btn-primary")); loginBtn.click(); Thread.sleep(3000); final String myAccountHeaderText = driver.findElement(By.cssSelector("#content h2")).getText(); assertEquals(myAccountHeaderText, "My Account"); }
The test script will first navigate to the Account Login page of the LambdaTest E-commerce Playground website. It will search for the E-Mail Address field and type in the value david.thomson@gmail.com
in it.
Next, the Password field will be located, and the value Secret@123
will be typed in. Finally, it will locate the Login button, and click on it.
After the Login button is clicked, the website will navigate to the My Account page, which will take some time to load. Hence, the Thread.sleep()
method is used here to wait for 3000
milliseconds before it checks the page header of the My Account page.
Using the Thread.sleep()
method here, the My Account page is loaded successfully, and then the assertion is performed.
Test Execution
Following is the screenshot of the test execution performed using IntelliJ IDE:
The test execution details can be found on the LambdaTest Web Automation Dashboard.
You can view the details of test execution for the tests executed on the Chrome 123 version of the Windows 10 platform, which took 10 seconds to run the test.
Details such as logs, video recordings, etc., can be viewed on the Web Automation Dashboard.
How To Avoid Multiple Thread.sleep() in Selenium
While working with some websites that have slow response times and take time to load, it is observed that testers use multiple Thread.sleep()
methods in the test so that WebElement
s can be loaded successfully on the web page before the code tries to locate the WebElement
on the page.
Consider the following code example of LambdaTest E-commerce Playground website where the user navigates to the Home page, waits for it to load before clicking on the Shop by Category menu, and then clicks on the MP3 Players category and again waits for the next page to load.
Shop by Category menu
Here is the test script with multiple Thread.sleep()
methods:
@Test public void testWebsiteNavigation () throws InterruptedException{ this.driver.get("https://ecommerce-playground.lambdatest.io/"); Thread.sleep(1000); this.driver.findElement(By.linkText("Shop by Category")).click(); Thread.sleep(1000); this.driver.findElement(By.cssSelector(".entry-component .entry-widget nav.navbar ul li:nth-child(5) a")).click(); Thread.sleep(1000); }
Test Execution
When this code was executed, it took a total of 14 seconds to run. It also took 3000 milliseconds or 3 seconds, considering the Thread.sleep()
method has 1 second hard wait after every line of code.
Hence, using multiple Thread.sleep()
methods in the tests is not a recommended approach. Instead, explicit waits from Selenium could be used here as it is dynamic in nature and will move to the next line of code once the WebElement is found, saving the time of execution.
Using Explicit Wait Instead of Thread.sleep()
The following code could be used, which uses explicit wait, and can perform faster execution as compared to the code using the Thread.sleep()
method.
Here is the test script with explicit wait instead of Thread.sleep()
method:
@Test public void testWebsiteNavigationWithExplicitWait() { this.driver.get("https://ecommerce-playground.lambdatest.io/"); final WebDriverWait wait = new WebDriverWait(this.driver, Duration.ofSeconds(10)); wait.until(ExpectedConditions.elementToBeClickable(By.linkText("Shop by Category"))).click(); wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector(".entry-component .entry-widget nav.navbar ul li:nth-child(5) a"))).click(); }
Test Execution
When this code was executed, it took a total of 11 seconds to complete the execution. Thus, it saves the 3 seconds that were additionally taken in the previous test execution, which was performed using the Thread.sleep()
method. Hence, it is recommended to use Selenium waits in the tests rather than the Thread.sleep()
method.
Element Is Found Using Thread.sleep() but Not Implicit/Explicit Waits
You might come across some scenarios where the WebElement
could be located using the Thread.sleep()
method only. When you try to use the Selenium waits instead of the Thread.sleep()
method, the WebElement
s are not located, resulting in the failure of the tests.
In such cases, it is recommended to debug the test and check for the actual cause of the error that results in the failure of the tests. Here, the Thread.sleep()
method could be used as a debugging mechanism to diagnose the test failure.
For example, an overlay appears on the page when the user tries to click on a button, which results in ElementClickInterceptionException
and leads to test failures. Alternate ways should be looked out for to handle the failure instead of directly using the Thread.sleep()
method.
There are multiple things that can be checked, like selectors being correct, using appropriate locator strategy, checking if the web page loads correctly, and only the required interaction being performed on the WebElement
.
Another alternative is to look out for the root cause of the test failure to know why the implicit or explicit wait is not working to locate the element. For example, locating the overlay page, clicking on it, and then interacting with the desired WebElement on the page.
pause()
method can be used from the Actions
class in Selenium. The pause()
method will pause the execution of the tests for the specified duration.
Limitations of Using Thread.sleep() in Selenium
Even though the Thread.sleep()
method helps handle dynamic WebElements, debugging, and testing third-party components, it has limitations.
The following are some of the limitations of the Thread.sleep()
in Selenium:
Static Hard Coded Waits
The thread.sleep()
method does not adapt to the actual state of the application under test. It will halt the test execution for the specified duration of time regardless of if the WebElement
is found within the specified time or not. In case of any error or test failures, it will happen after the specified duration of time.
Unreliable
It is not reliable as it might get interrupted due to other threads or processes and could be affected by factors such as network issues.
Not Scalable
It increases the overall test execution time, which may result in delayed builds for testing. This may also lead to delays in getting feedback on the builds.
Alternatives to Thread.sleep() in Selenium
The thread.sleep()
method has been provided by Java, but when used in automation scripts, it is often considered unstable. Ideally, it is not recommended to use the Thread.sleep()
method in test scripts as it may increase the test execution time (as explained in the last section).
Although executing tests with third-party interfaces and AJAX calls might always seem complex, when handled wisely with the proper wait like the Thread.sleep()
method, it will ease the execution with high-accuracy results.
If that’s not the case with you, you might be better off using other Selenium waits like implicit, explicit, or fluent waits.
SmartWait Functionality
Cloud-based testing platforms like LambdaTest offer SmartWait
functionality for Selenium testing that lets you get rid of the unwanted explicit waits and expected conditions in the code. It ensures that the actions are performed on the WebElements, which are ready for interaction.
If the actionability checks fail, it throws the relevant Selenium exceptions, which helps quickly identify and resolve the test automation-related issues.
SmartWait
helps in writing optimized code that is easy to read and maintain. Once the SmartWait
capability is used in the code, there is no need to use explicit, implicit, or fluent waits in the test scripts.
smartWait
capability can be added to the LT:Options
capability, which allows the addition of all the capabilities related to the LambdaTest Cloud Grid.
LT:Options { ... "smartWait": 10 // It accepts integer values as second ... }
The time in seconds needs to be passed in the smartWait
capability. This capability accepts only integers. We will cover the demonstration of smartWait
in the test script in the next section of this blog.
SmartWait for Selenium Test Automation
In the previous section, we learned how to use the Thread.sleep()
method in Selenium automation. Multiple Thread.sleep()
methods were required to be added to the test scripts to make the execution wait while the screen transition happened. These Thread.sleep()
methods helped smooth the execution of the tests, avoiding the flaky tests.
However, as the Thread.sleep()
method is a hard wait, the test execution time increased by an additional 3000 milliseconds. The SmartWait feature by LambdaTest can help us reduce the test execution time by eliminating the use of the Thread.sleep()
method.
Let’s take the same login scenario of the LambdaTest E-Commerce Playground website.
The following smartWait
capability will be added to the getChromeOptions()
method.
public ChromeOptions getChromeOptions() { //... ltOptions.put("smartWait", 20); //... }
The following screenshot shows the implementation of the getChromeOptions()
method.
The testLoginWithSmartWait()
method performs the same login scenario steps as discussed earlier. However, in this test method, there is no Thread.sleep()
method used to wait for the My Account screen to load after the login button is clicked.
LambdaTest SmartWait internally handles all the WebElement readiness for performing actions. This saves the test execution time without writing any extra boilerplate code.
According to the Future of Quality Assurance Survey by LambdaTest, testers spend more than 8% of their time fixing flaky tests. However, the SmartWait
functionality enables testers to focus on performing core testing without worrying about test flakiness, saving them valuable time to write efficient test scripts.
@Test public void testLoginWithSmartWait() { this.driver.get("https://ecommerce-playground.lambdatest.io/index.php?route=account/login"); final WebElement emailAddress = this.driver.findElement(By.id("input-email")); emailAddress.sendKeys("david.thomson@gmail.com"); final WebElement password = this.driver.findElement(By.id("input-password")); password.sendKeys("Secret@123"); final WebElement loginBtn = this.driver.findElement(By.cssSelector("input.btn-primary")); loginBtn.click(); final String myAccountHeaderText = this.driver.findElement(By.cssSelector("#content h2")).getText(); assertEquals(myAccountHeaderText, "My Account"); }
Test Execution
Let’s execute the testLoginWithSmartWait()
method and also the previously written test testLogin()
that has the Thread.sleep()
method implemented that we discussed in the earlier section of this blog, and compare the test execution time taken by both of the tests.
This total time of execution can be verified on the LambdaTest build details screen, as shown in the screenshot below: It can be observed that the test with the Thread.sleep()
method took a total of 8 seconds to run. However, the test with LambdaTest SmartWait took only 6 seconds to run. Thus, saving 2 seconds in the whole test execution.
This is a simple login scenario, so the time difference is much less. However, it can be imagined that in complex scenarios such as end-to-end testing, this execution time can play a vital role.
Conclusion
Thread.sleep()
in Selenium is a kind of hard wait that can be used in Selenium web automated tests.
However, it is not a recommended practice. Instead, we should implement the Selenium waits, which is a more flexible and less time-consuming solution. Thread.sleep()
in Selenium is a useful method for web application debugging and can even be implemented with an online Selenium Grid.
Let us know if you have come across any other scenarios where you have found a better way to effectively implement the Thread.sleep()
method using Selenium with Java. Also, if you have any questions, feel free to reach out via the comment section below.
Published at DZone with permission of Faisal Khatri. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments