Playwright vs Selenium: Mastering Test Automation Waits

Waits in Playwright vs Selenium

Introduction

Web Applications can be hard to test. Different components of a web page can take different amount of time to get loaded. To automate the testing of these applications, it is very essential to add “waits” to our test cases. In this blog, we will explore how the concept of wait is supported by two of the most popular Test Automation tool, playwright vs selenium.

Playwright

Whenever a playwright script is executed, the playwright framework performs a set of checks on the web elements. These checks are known as ‘Actionability’ checks. The main objective of these checks is to ensure that the element on which a particular action needs to be performed, is ready for that action. This ensures that the Test script does not behave in an unexpected manner. This reduces the flakiness of our test case.

Some time is allocated for the actionability checks. If the checks pass within the stipulated time frame, the action is performed. If the checks fail, the action is not performed. This causes Timeout Error.

Example of Actionability check in Playwright

Let us take the click action as an example. This action is performed by the following snippet

locator.click()

Whenever playwright encounters the above snippet of code, it ensures the following :

  • locator resolves to an exactly one element
  • element is Visible
  • element is Stable, as in not animating or completed animation
  • element Receives Events, as in not obscured by other elements
  • element is Enabled

Now the next question that naturally comes to the curious minds is that “How do we give a fixed timeout waits for our scripts?” For that we can use the page.waitForTimeout method. This does not require us to specify any condition for the test script to wait.

await page.waitForTimeout(2000)

The above line will return true after waiting for 2 seconds. But we must use this method very sparingly. They can cause delays in the script execution. It is generally better to use specific conditions to determine when to continue, such as waiting for a specific element to be present or for a page to load. This command will wait for 2 seconds regardless of the actual response time, which may be less or more than 2 seconds. This is detrimental in both cases: in the first case, it unnecessarily waits for a longer time when the object is already loaded, and in the second scenario, it fails after waiting for 2 seconds if the object is not going to load at all.

Explicit waits

There may be scenarios where the above mentioned waiting mechanisms may not be sufficient or an efficient approach to handle. For such scenarios, we have the following methods that are provided by the playwright.

Waiting for page navigations and API responses

  1. page.waitForNavigation to wait until a page navigation (new URL or page reload) has completed.
  2. page.waitForLoadState This waits until the required load state has been achieved.
  3. page.waitForURL This waits until a navigation to the target URL.
  4. page.waitForResponse waits till the response from the given API is received.

Wait for element

In lazy-loaded pages, it can be useful to wait until an element is visible with locator.waitFor(). Alternatively, page interactions like page.click() auto-wait for elements.

// Navigate and wait for element

await page.goto('https://ikalamtech.com');
await page.getByText(' An Example Domain').waitFor();

// Navigate and click element. Click will auto-wait for the element

await page.goto('https://ikalatech.com');
await page.getByText('An Example Domain').click();

Selenium

Selenium WebDriver provides three types of waits for the Tests.They are enumerated as follows.

  1. Implicit Wait
  2. Explicit Wait
  3. Fluent Wait

Implicit Wait in Selenium

Implicit Wait tells the Selenium Webdriver to wait for a certain amount of time. Once this time is set, WebDriver will wait for the element before the exception occurs.

Implicit wait is applied for the entire browser session.

To add implicit waits in test scripts, import the following package.

import java.util.concurrent.TimeUnit;

Implicit Wait Syntax

driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

Example of Implicit Wait Command

Package waitExample;

import java.util.concurrent.TimeUnit;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

public class ImplicitWaitTest {

private WebDriver driver;
private String baseUrl;
private WebElement element;

@BeforeMethod
public void setUp() throws Exception {
driver = new FirefoxDriver();
baseUrl = "http://www.google.com";
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
}

@Test
public void testUntitled() throws Exception {
driver.get(baseUrl);
element = driver.findElement(By.id("lst-ib"));
element.sendKeys("Selenium WebDriver Interview questions");
element.sendKeys(Keys.RETURN);
List<WebElement> list = driver.findElements(By.className("_Rm"));
System.out.println(list.size());

}

@AfterMethod
public void tearDown() throws Exception {
driver.quit();
}
}

Implicit wait often slows down the overall execution time of the tests. Even when all the elements are loaded, the test script continues to wait for the specified period of time. Hence implicit waits must be used with caution.

Explicit Wait in Selenium

Explicit wait is an intelligent form of wait. In an explicit wait, WebDriver is directed to wait until a certain condition occurs before proceeding with executing the code. Implicit wait causes the test script to wait for a fixed amount of time . If the elements are loaded before that time, this can lead to unnecessary delay. However, Explicit waits wait for a particular condition to occur on a specific element. When the condition occurs, the execution resumes. Hence this can save a lot of execution time.

In order to declare explicit wait, one has to use ExpectedConditions. The following Expected Conditions can be used in Explicit Wait.

  1. alertIsPresent()
  2. elementSelectionStateToBe()
  3. elementToBeClickable()
  4. elementToBeSelected()
  5. frameToBeAvaliableAndSwitchToIt()
  6. invisibilityOfTheElementLocated()
  7. invisibilityOfElementWithText()
  8. presenceOfAllElementsLocatedBy()
  9. presenceOfElementLocated()
  10. textToBePresentInElement()
  11. textToBePresentInElementLocated()
  12. textToBePresentInElementValue()
  13. titleIs()
  14. titleContains()
  15. visibilityOf()
  16. visibilityOfAllElements()
  17. visibilityOfAllElementsLocatedBy()
  18. visibilityOfElementLocated()

To use Explicit Wait in test scripts, import the following packages into the script.

import org.openqa.selenium.support.ui.ExpectedConditions

Then, Initialise A Wait Object using WebDriverWait Class.

Explicit Wait Syntax

WebDriverWait wait = new WebDriverWait(driver,30);

Here, <wait>  is the reference variable for the <WebDriverWait> class. We instantiate it using the WebDriver instance. The maximum time to wait  must be set for the execution to layoff. Note that the wait time is measured in seconds.

Example of Explicit Wait Command

In the following example, the test script is for logging into “gmail.com” with a username and password. After a successful login, the code waits for the “compose” button to be available on the home page. Here, you have to wait until the element is visible (Compose Button in this case) using the explicit wait command. Finally, it clicks on the button.

package waitExample;

import java.util.concurrent.TimeUnit;

import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class ExpectedConditionExample {
// created reference variable for WebDriver
WebDriver driver;

@BeforeMethod
public void setup() throws InterruptedException {

// initializing driver variable using FirefoxDriver
driver=new FirefoxDriver();
// launching gmail.com on the browser
driver.get("https://gmail.com");
// maximized the browser window
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
}

@Test
public void test() throws InterruptedException {
// saving the GUI element reference into a "element" variable of WebElement type
WebElement element = driver.findElement(By.id("Email"));
// entering username
element.sendKeys("dummy@gmail.com");
element.sendKeys(Keys.RETURN);
// entering password
driver.findElement(By.id("Passwd")).sendKeys("password");
// clicking signin button
driver.findElement(By.id("signIn")).click();
// explicit wait - to wait for the compose button to be click-able
WebDriverWait wait = new WebDriverWait(driver,30);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//div[contains(text(),'COMPOSE')]")));
// click on the compose button as soon as the "compose" button is visible
driver.findElement(By.xpath("//div[contains(text(),'COMPOSE')]")).click();
}

@AfterMethod
public void teardown() {
// closes all the browser windows opened by web driver
driver.quit();
}

}

The above code instructs Selenium WebDriver to wait for 30 seconds before throwing a TimeoutException. If it finds the element before 30 seconds, then it will return immediately. After that, it will click on the “Compose” button. In this case, the program will not wait for the entire 30 seconds, thus saving time and executing the script faster.

Fluent Wait in Selenium

Fluent Wait in Selenium marks the maximum amount of time for Selenium WebDriver to wait for a certain condition (web element) becomes visible. It also defines how frequently WebDriver will check if the condition appears before throwing the “ElementNotVisibleException”.

Simply put, Fluent Wait searches for a web element repeatedly at regular intervals until a timeout occurs or until the object is found.

Fluent Wait commands are most useful when interacting with web elements that can take longer durations to load. This is something that often occurs in Ajax applications.

While using Fluent Wait, it is possible to set a default polling period as needed. The user can configure the wait to ignore any exceptions during the polling period.

Fluent waits earned the moniker “smart waits” because they don’t wait out the entire duration defined in the code. Instead, the test continues execution as soon as the element is detected – once the condition specified in the .until(YourCondition) method becomes true.

Fluent Wait Syntax

Wait wait = new FluentWait(WebDriver reference)
.withTimeout(timeout, SECONDS)
.pollingEvery(timeout, SECONDS)
.ignoring(Exception.class);

WebElement foo=wait.until(new Function<WebDriver, WebElement>() {
public WebElement applyy(WebDriver driver) {
return driver.findElement(By.id("foo"));
}
});

Example of Fluent Wait Command

//Declare and initialise a fluent wait
FluentWait wait = new FluentWait(driver);
//Specify the timout of the wait
wait.withTimeout(5000, TimeUnit.MILLISECONDS);
//Sepcify polling time
wait.pollingEvery(250, TimeUnit.MILLISECONDS);
//Specify what exceptions to ignore
wait.ignoring(NoSuchElementException.class)

//This is how we specify the condition to wait on.
//This is what we will explore more in this chapter
wait.until(ExpectedConditions.alertIsPresent());

This command operates with two primary parameters: timeout value and polling frequency. The above code defines the time out value as 5 seconds and polling frequency as 0.25 seconds. It directs WebDriver to wait for no more than 5 seconds to verify a specific condition. If the condition occurs during those 5 seconds, it will execute the next step in the test script. If not, it will return “ElementNotVisibleException”.

A few other associated commands are:

  • PageLoadTimeout Command

This command establishes the time WebDriver must wait for a page to completely load before triggering an error. In case the timeout set is negative, the page load time can be indefinite.

driver.manage().timeouts().pageLoadTimeout(100, SECONDS);
  • SetScriptTimeout Command

This command establishes the time WebDriver will wait for an asynchronous script to finish executing before triggering an error. Like the previous command, the script will run indefinitely if the timeout is set to a negative value.

driver.manage().timeouts().setScriptTimeout(100,SECONDS);
  • Sleep Command

Rarely used, the Thread Sleep command is quite ineffective. It forces WebDriver to wait for a specific time, preventing it from running faster even if the condition is met. Selenium wait commands are a smarter, more effective alternative to the Sleep command.

thread.sleep(1000);

Conclusion

In this blog, we’ve explored the significance of waits in automating test cases for web applications using two popular tools: Selenium and Playwright. These waits are crucial for ensuring that our tests run reliably and efficiently, as they account for the varying load times of different web elements.

Playwright offers sophisticated actionability checks and methods like page.waitForTimeout, which help in reducing test flakiness by ensuring elements are ready before actions are performed. Its explicit wait mechanisms, such as page.waitForNavigation and locator.waitFor(), provide fine-grained control over when to proceed with test steps, making it a robust choice for modern web applications.

Selenium provides multiple types of waits to handle different scenarios:

  • Implicit Waits apply a global wait time for the entire session but can slow down tests if overused.
  • Explicit Waits offer a more intelligent approach, waiting for specific conditions before proceeding, thus optimizing test execution time.
  • Fluent Waits provide flexibility by repeatedly checking for conditions at regular intervals, which is especially useful for dynamic content that may take varying amounts of time to appear.

By leveraging these wait strategies effectively, we can ensure that our test scripts are both efficient and resilient, capable of handling real-world web application behavior. Whether using Selenium or Playwright, understanding and implementing the right wait mechanisms is essential for any QA engineer aiming to deliver high-quality, reliable software.

For those starting their automation journey, understanding these waiting strategies is a foundational step. We at iKalamTech are dedicated to providing comprehensive resources and insights to help you master these tools and excel in your test automation endeavours.

If you would like to read about Selenium 4 & its new features in Detail, click here

Share your love

Leave a Reply

Your email address will not be published. Required fields are marked *