Several years back, I wanted to understand if it’s really necessary to use thread.sleep in test automation code. Here is what stuck in my mind: Thread.Sleep(n) means blocking the current thread for the number of time slices that occur within “n” milliseconds.
There are a few things to consider before using thread.sleep in your test automation code. They include:
- The thread time slice varies from OS to OS and processor to processor. This means that once your thread goes to sleep, it’s going to wait for its turn to come back into the scheduler. So it’s highly likely that the thread.sleep time means more than what you really intended. For example, with thread.sleep(1000), you intended 1,000 milliseconds, but it could potentially sleep for more than 1,000 milliseconds too as it waits for its turn in the scheduler.
- Each thread has its own use of CPU and virtual memory. That means our thread acquired its resources (say 1MB virtual memory, some CPU cycles and some context switching cycles), and is simply not using them.
- If it’s a foreground thread, it’s preventing the application from exiting as well.
- What about Thread.Sleep(0)? This tells the processor that I’m ready to lose the remainder of my time slice, and you may pick up the next thread from the queue. On one hand, it feels good and efficient. But on the other hand, you are also telling the processor that you are better at scheduling than the processor. (I don’t know the side effects this can cause, but I’m not smarter than the processor.)
We are talking about milliseconds when dealing with thread.sleep, but it’s important to understand that the more we use thread.sleep, the more we defer solving the real problem, which is how to handle async in modern web apps.
Typically, we tend to use thread.sleep when the front-end waits for the backend to complete some action. During this time, the front-end traditionally shows a spinner. Automation needs to wait until the spinner goes off, but that doesn’t mean the target element is ready right after the spinner disappears. For example, that element might not be clickable or enabled, or in the expected state. So, a better approach is to check for right state instead of using thread.sleep or relying on the spinner’s visibility.
Selenium provides a set of common conditions that can be leveraged on top of webdriverwait.
We can create a wrapper method that takes the web element, max timeout and the condition:
` var wait = new WebDriverWait(driver,timeout); wait.IgnoreExceptionTypes(typeof(NoSuchElementException)); return wait.Until(x=>condition(element)); `
It’s worth following webdriver.io internal implementation to understand this better. For example, waitForVisible API implementation starts here. They check if the desired element is in the DOM; if yes, they send a protocol command to the webdriver server to check if it’s displayed. All this happens for a maximum time limit, and if the element is still not visible, an error is thrown.
This approach helps make the test more stable and reliable.