Chapter 3: Handling Waits and Synchronization
To eliminate test flakiness, you must understand the architectural mismatch between a test automation runner and a modern web browser. Selenium WebDriver executes instructions sequentially at machine speed — measured in microseconds. A web browser, however, is an asynchronous, event-driven distributed system.
When your script clicks a button, that single action triggers a cascade of asynchronous browser operations: an HTTP Fetch/XHR request across the network, server processing, JSON parsing, React or Angular state updating, Virtual DOM diffing, and CSS layout recalculation. If your next line of code asks WebDriver to locate an element while any part of that pipeline is still running, WebDriver immediately queries the current DOM tree. If the node is not present, ChromeDriver instantly throws a fatal exception.
// The Exact Production Stack Trace You Encounter:
org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element:
{"method":"css selector","selector":"#account-balance"}
(Session info: chrome=129.0.6668.71)
For documentation on this error, please visit: https://www.selenium.dev/documentation/webdriver/troubleshooting/errors#no-such-element-exception
Build info: version: '4.25.0', revision: '8a8aea2337'
System info: os.name: 'Linux', os.arch: 'amd64', os.version: '6.5.0-1025-azure'
Driver info: org.openqa.selenium.chrome.ChromeDriver
Command: [4b89f81d8a4e3..., findElement {value=#account-balance, using=css selector}]
Capabilities {acceptInsecureCerts: false, browserName: chrome, ...}
at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:62)
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:502)
at org.openqa.selenium.remote.ErrorCodec.decode(ErrorCodec.java:167)
at org.openqa.selenium.remote.codec.w3c.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:138)
at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExecutor.java:190)
at org.openqa.selenium.remote.service.DriverCommandExecutor.invokeExecute(DriverCommandExecutor.java:216)
at org.openqa.selenium.remote.service.DriverCommandExecutor.execute(DriverCommandExecutor.java:174)
at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:545)
at org.openqa.selenium.remote.ElementLocation$ElementFinder$2.findElement(ElementLocation.java:165)
at org.openqa.selenium.remote.ElementLocation.findElement(ElementLocation.java:59)
at org.openqa.selenium.remote.RemoteWebDriver.findElement(RemoteWebDriver.java:368)
at org.openqa.selenium.remote.RemoteWebDriver.findElement(RemoteWebDriver.java:362)
at com.testerrank.tests.BankingTest.testBalanceDisplay(BankingTest.java:34)Let us analyze what happens inside the browser thread versus the WebDriver execution thread when automating a fund transfer or login scenario:
| Timestamp | WebDriver Client (JVM Thread) | Browser Thread (V8 & DOM) | Network / Server Layer |
|---|---|---|---|
| T + 0ms | Dispatches click command on #login-btn | Dispatches synthetic mouse click event | Idle |
| T + 12ms | ChromeDriver returns HTTP 200 (click OK) | Executes onClick() handler; fires fetch() | Dispatches POST /api/auth/login |
| T + 25ms | Executes driver.findElement(By.id("balance")) | Main thread busy parsing network payload | Packet in transit over TCP/TLS |
| T + 28ms | Queries DOM tree for #balance node | DOM contains login form; #balance NOT mounted | Server executing database lookup |
| T + 30ms | FATAL: NoSuchElementException thrown! Test fails! | DOM unchanged | Server generates HTTP 200 response |
| T + 210ms | Test execution aborted; failure log dumped | Receives HTTP 200 response; updates state | Connection closed |
| T + 235ms | Process teardown | React mounts #balance into DOM (Too late!) | Idle |
Notice the tragedy at T+30ms: the test failed completely, even though the feature worked perfectly just 180 milliseconds later! This is why test suites fail intermittently: if the network or CPU latency fluctuates by a fraction of a second, the test crashes.
Why does this issue multiply in CI/CD pipelines compared to local developer laptops?
Key Point: Browsers are asynchronous; WebDriver is sequential. Without dynamic synchronization, tests crash on normal microsecond network and rendering fluctuations.