There is much more about synchronization than waiting for elements
The most common action in a Selenium script is finding an element:
WebElement textbox = driver.findElement(textboxId);
textbox.sendKeys(keyword);
It works well if the element is in the page when this code executes.
It fails if the element is not yet in the page since findElement() will not wait for the element.
Adding a wait helps with this failure.
Implicit waits are a bad practice so I am not going to say anything about them.
Explicit waits allow waiting until the element is in the page and the element has a specific state:
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(30));
wait.until(ExpectedConditions.visibilityOfElementLocated(textboxId));
WebElement textbox = driver.findElement(textboxId);
textbox.sendKeys(keyword);
In this case, the code waits first for maximum 30 seconds for the element to be in the page and for the element to be visible.
After that, the code proceeds to finding the element and interacting with it.
You may assume that, since you are waiting for elements to be present before using them, that your test is well synchronized with the page.
The test may do many other things in addition to finding elements:
switch to a frame
execute a Javascript snippet
work with a list of elements
work with inner elements
work with very slow pages
work with browser tabs
work with alerts
work with stale elements
work with elements that are loaded asynchronously
Any of these can make the test unstable especially when the site is slow.
Having a test that is synchronized with the site means that we need to wait for all these actions.
How do we do it?
No, I am not suggesting that you build your own wait methods.
There is no need for that.
The ExpectedConditions class provides conditions that are useful for each case:
1. switch to a frame
ExpectedCondition<WebDriver> frameToBeAvailableAndSwitchToIt(int frameLocator)
An expectation for checking whether the given frame is available to switch to.
ExpectedCondition<WebDriver> frameToBeAvailableAndSwitchToIt(String frameLocator)
An expectation for checking whether the given frame is available to switch to.
ExpectedCondition<WebDriver> frameToBeAvailableAndSwitchToIt(By locator)
An expectation for checking whether the given frame is available to switch to.
ExpectedCondition<WebDriver> frameToBeAvailableAndSwitchToIt(WebElement frameLocator)
An expectation for checking whether the given frame is available to switch to.
2. execute a Javascript snippet
ExpectedCondition<Boolean> javaScriptThrowsNoExceptions(String javaScript)
An expectation to check if js executable.
ExpectedCondition<Object> jsReturnsValue(String javaScript)
An expectation for String value from javascript
3. work with a list of elements
ExpectedCondition<List<WebElement>> numberOfElementsToBe(By locator, Integer number)
An expectation for checking number of WebElements with given locator
ExpectedCondition<List<WebElement>> numberOfElementsToBeLessThan(By locator, Integer number)
An expectation for checking number of WebElements with given locator being less than defined number
ExpectedCondition<List<WebElement>> numberOfElementsToBeMoreThan(By locator, Integer number)
An expectation for checking number of WebElements with given locator being more than defined number
4. work with inner elements
ExpectedCondition<WebElement> presenceOfNestedElementLocatedBy(By locator, By childLocator)
An expectation for checking child WebElement as a part of parent element to present
ExpectedCondition<WebElement> presenceOfNestedElementLocatedBy(WebElement element, By childLocator)
An expectation for checking child WebElement as a part of parent element to be present
ExpectedCondition<List<WebElement>> presenceOfNestedElementsLocatedBy(By parent, By childLocator)
An expectation for checking child WebElement as a part of parent element to present
5. work with very slow pages
ExpectedCondition<Boolean> titleContains(String title)
An expectation for checking that the title contains a case-sensitive substring
ExpectedCondition<Boolean> titleIs(String title)
An expectation for checking the title of a page.
ExpectedCondition<Boolean> urlContains(String fraction)
An expectation for the URL of the current page to contain specific text.
ExpectedCondition<Boolean> urlMatches(String regex)
Expectation for the URL to match a specific regular expression
ExpectedCondition<Boolean> urlToBe(String url)
An expectation for the URL of the current page to be a specific url.
6. work with browser tabs
ExpectedCondition<Boolean> numberOfWindowsToBe(int expectedNumberOfWindows)
7. work with alerts
ExpectedCondition<Alert> alertIsPresent()
8. work with stale elements
ExpectedCondition<Boolean> stalenessOf(WebElement element)
Wait until an element is no longer attached to the DOM.
9. work with elements that are loaded asynchronously
ExpectedCondition<Boolean> attributeContains(By locator, String attribute, String value)
An expectation for checking WebElement with given locator has attribute which contains specific value
ExpectedCondition<Boolean> attributeContains(WebElement element, String attribute, String value)
An expectation for checking WebElement with given locator has attribute which contains specific value
ExpectedCondition<Boolean> attributeToBe(By locator, String attribute, String value)
An expectation for checking WebElement with given locator has attribute with a specific value
ExpectedCondition<Boolean> attributeToBe(WebElement element, String attribute, String value)
An expectation for checking given WebElement has attribute with a specific value
ExpectedCondition<Boolean> attributeToBeNotEmpty(WebElement element, String attribute)
An expectation for checking WebElement any non empty value for given attribute
ExpectedCondition<Boolean> textMatches(By locator, Pattern pattern)
An expectation for checking WebElement with given locator has text with a value as a part of it
ExpectedCondition<Boolean> textToBe(By locator, String value)
An expectation for checking WebElement with given locator has specific text
ExpectedCondition<Boolean> textToBePresentInElement(WebElement element, String text)
An expectation for checking if the given text is present in the specified element.
ExpectedCondition<Boolean> textToBePresentInElementLocated(By locator, String text)
An expectation for checking if the given text is present in the element that matches the given locator.
ExpectedCondition<Boolean> textToBePresentInElementValue(By locator, String text)
An expectation for checking if the given text is present in the specified elements value attribute.
ExpectedCondition<Boolean> textToBePresentInElementValue(WebElement element, String text)
An expectation for checking if the given text is present in the specified elements value attribute.
It pays off to read the documentation and the code of a library,
There are many similar treasures that you can use for making your work much better.
Thanks for reading.