Playwright Tutorial: Exploring Test Automation with Java

Playwright Tutorial: Exploring Test Automation with Java

Introduction

Playwright, developed by Microsoft and launched in early 2020, is a powerful framework for web testing and automation. It offers a range of benefits:

  • Cross-browser: Supports Chromium, Firefox, and WebKit with a single API, in both headed and headless modes.
  • Cross-platform: Compatible with Windows, Linux, and macOS, suitable for local and CI/CD pipeline integration.
  • Cross-language: Supports JavaScript, TypeScript, Python, .NET, and Java.
  • Native Mobile Emulation
  • Increased Test Robustness: Features built-in auto-wait for elements, web-first assertions, and tracing to minimize flaky tests.
  • Test Isolation: Achieved through browser contexts.
  • Support for multiple tabs, origins, and users
  • Event Hooks
  • Seamless automation for IFrame and Shadow DOM

In this post, we will explore the most commonly used features of Playwright using Java.

What Does a Playwright Test Look Like?

Setup

To begin writing tests with Playwright, add the library as a dependency to your project using Maven or Gradle. Additionally, consider adding a testing framework like JUnit or TestNG as a dependency.

Test

package tests;


import com.microsoft.playwright.*;
import com.microsoft.playwright.options.AriaRole;
import org.junit.jupiter.api.Test;


import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;


public class PlaywrightTests {
   @Test
   public void simplePlaywrightTest() {
       try (Playwright playwright = Playwright.create()) {
           Browser browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(false));
           BrowserContext context = browser.newContext();
           Page page = context.newPage();


           page.navigate("https://www.automatetheplanet.com");


           Locator heading = page.getByRole(AriaRole.HEADING).first();


           assertThat(page).hasTitle("Home Page - Automate The Planet");
           assertThat(heading).hasText("Your Ultimate Test Automation Partner");
       }
   }
}

Analysis

The first thing we might notice are the essential objects in the Playwright API: Playwright, Browser, BrowserContext, Page, and Locator.

  • Playwright: Provides methods to launch a Browser instance. Closing it will terminate all associated browsers.
  • Browser: Represents the launched browser.
  • BrowserContext: Allows multiple independent browser sessions.
  • Page: Provides methods to interact with the browser tab.
  • Locator: Represents a way to find elements on the page but is not a direct reference to the HTML elements.

In the following sections, we will explore these objects in detail.

Another key point is that the Playwright object is initialized in a try-with-resources statement. Java’s try-with-resources ensures that resources like files, database connections, or sockets are closed automatically after use, even if an exception occurs. This is done by implementing the AutoCloseable interface, which includes the close() method.

Both Playwright and Browser implement this interface. If they are not closed properly, the opened browser won’t close after the test. While you can manually call the close() method, it is error-prone and can lead to resource leaks, especially in complex code with multiple exit points or exceptions. Thus, using try-with-resources is the preferred and safer practice.

You don’t need to manually close the Browser in Playwright. Closing the Playwright object automatically handles closure of all associated Browser objects, including their BrowserContexts and Pages.

Finally, Playwright provides its own assertions. To use them, you can either:

  • Write PlaywrightAssertions.assertThat and import com.microsoft.playwright.assertions.PlaywrightAssertions.
  • Write assertThat directly and statically import com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat.

We will discuss the assertions in detail later.

Writing tests with Playwright is intuitive and simple, yet very powerful.

Launching Playwright Browser

As mentioned already, launching Playwright happens with a few steps: Create a Playwright instance, from that instance create a Browser instance, from which BrowserContext and Page objects are created.

When launching browsers, there are 3 basic options: Chromium, Firefox, and WebKit.

browser = playwright.chromium().launch();
browser = playwright.firefox().launch();
browser = playwright.webkit().launch();

Additionally, one can pass an argument to the launch method which is the launching options.

Let’s take a look at them.

var launchOptions = new BrowserType.LaunchOptions();

You can customize the browser by defining many different settings, such as: headless, channel, chromiumSandbox, devtools, executablePath, proxy, slowMo (slow motion), timeout, and tracesDir.

Maybe you are wondering how to launch Chrome or Edge browser, not just Chromium. It is done by setting the channel option to either “chrome” or “msedge”, when launching chromium.

playwright.chromium().launch(new BrowserType.LaunchOptions().setChannel("chrome"));
playwright.chromium().launch(new BrowserType.LaunchOptions().setChannel("msedge"));

Other available channels for chromium include: chrome-beta, msedge-beta, and msedge-dev.

As you might know, Chrome and Edge are based on Chromium. Testing on the latest Chromium keeps you ahead of stable browser releases, ensuring upcoming updates won’t break your website. However, regression testing often requires testing against the latest publicly available browsers. Therefore, it’s crucial to know how to set the channel in Chromium launch options.

After initializing the Browser object, there are two methods to initialize a Page object for testing.

  • Using BrowserContext:
BrowserContext browserContext = browser.newContext();
Page page = browserContext.newPage();

This approach first creates a new BrowserContext using browser.newContext(), and then initializes a Page object using browserContext.newPage().

  • Directly from Browser:
Page page = browser.newPage();

This method directly initializes a Page object from the Browser object. Internally, Playwright automatically creates a BrowserContext and then initializes the Page from that context.

Both methods ultimately provide a Page object that can be used to interact with and automate actions on a web page during testing. The choice between these methods depends on whether additional control over the BrowserContext settings is needed or if a simple default context is sufficient for the test scenario.

Locators and ElementHandles

Locators encapsulate methods to find and interact with elements on the page. Each time a locator is utilised for an action, it dynamically locates the most current DOM element on the page. This approach is fundamental to reducing test flakiness.

Locating

  • getByRole()

This locator reflects what function the element represents, for example, a button, or a checkbox, or an input field. This method accepts 1 or 2 arguments, the first being a value from the enum AriaRole (e.g., AriaRole.HEADING), and the second being optional is the options for locating by role.

getByRole(AriaRole.HEADING)
getByRole(AriaRole.TEXTBOX, new Page.GetByRoleOptions().setName("billing address"));
getByRole(AriaRole.CHECKBOX, new Page.GetByRoleOptions().setChecked(true));
getByRole(AriaRole.RADIO, new Page.GetByRoleOptions().setDisabled(true));
  • getByLabel()

This locator is used to find input elements with a label attached to them. It is useful to have a direct locator by label when dealing with forms for example.

getByLabel("Password");
getByLabel(Pattern.compile("(?i).*name.*"));
  • getByPlaceholder()

Many inputs may have a placeholder attribute which will hint to the user what they are supposed to write.

getByPlaceholder("name@example.com");
getByPlaceholder("^[\\w.%+-]+@[\\w.-]+\\.[a-zA-Z]{2,}$");
  • getByText()

When dealing with non-interactive elements which have the role of simply conveying information in the form of a text, searching by it is straightforward. The interesting part is that Playwright normalises whitespace, so you don’t have to worry about that!

getByText("Your Ultimate Test Automation Partner");
getByText("Ultimate Test Automation", new Page.GetByTextOptions().setExact(false));
getByText(Pattern.compile("Partner$"));
  • getByAltText()

It’s generally recommended to include an ‘alt’ attribute when adding images to HTML. This attribute provides text that displays if the image fails to load. Searching for or  elements using this attribute is highly reliable.

getByAltText("Parallel on Agents", new Page.GetByAltTextOptions().setExact(true));
getByAltText(Pattern.compile("^people"));
  • getByTitle()

This locator searches by the title attribute of elements.

getByTitle("Automate the Planet Logo");
getByTitle(Pattern.compile("Logo$"));
  • getByTestId()

In an ideal scenario where test automation is integrated into the development process and both test engineers and developers collaborate by adding test IDs to elements for automated tests, Playwright provides a straightforward method to search by these IDs. Even if the page content changes, the test ID remains consistent.

Before using test IDs for locating elements, it’s important to configure Playwright to recognize the attribute that qualifies as a test ID on your website. By default, Playwright uses “data-testid”.

playwright.selectors().setTestIdAttribute("bellatrix-testid");

After you have instructed Playwright which attribute is the test id, you can easily locate elements by it as follows:

page.getByTestId("username-input");
page.getByTestId(Pattern.compile("^username"));
  • locate()

While basic methods of locating elements are straightforward, test automation often requires writing complex CSS or XPath selectors to handle more challenging scenarios.

The method for these selectors in Playwright is used like this:

locator("//img[@alt='people_image' and contains(@src, 'Forbes.jpeg')]");
locator("[id='logo']");

You might want to add in the beginning of the locator “xpath=” or “css=” accordingly, as even though Playwright often guesses correctly which is which, it might fail.

It’s often discouraged to copy-paste CSS Selectors or XPath directly from the devtools inspector, as they can generate unreliable locators. For more information on creating reliable CSS and XPath selectors, check out these blog posts:

Most Exhaustive CSS Locators Cheat Sheet

Most Exhaustive XPath Locators Cheat Sheet

Shadow DOM

With Playwright, you don’t need to worry about elements being unreachable due to being within a shadow root. Whether using CSS selectors or the getBy methods provided, Playwright locators can find elements even within the shadow DOM seamlessly.

Interaction

When using Locator objects to interact with elements on a page in Playwright, you will not encounter errors like ‘StaleElementReferenceException’. This is because Locators are not direct references to elements; instead, they are strategies to find elements. Each time you interact with an element through a Locator, Playwright re-finds the element, creates an ElementHandle (which acts as a pointer to the element), performs the action, and then disposes of the ElementHandle. This ensures that interactions are always with the most current instance of the element.

Now, let’s take a look at some of the most common methods of Locator and what they do.

  • check() and uncheck()

Used with checkboxes and radio buttons.

check() will ensure it’s checked, while uncheck() will ensure it’s unchecked.

  • clear()

Used with inputs, it will clear the input field.

  • click()

Might be used with any element, but most notably buttons and anchors.

Via the ClickOptions which are optional one can:

Set the mouse button (left, right, middle):

button.click(new Locator.ClickOptions().setButton(MouseButton.RIGHT));

Set the click count:

button.click(new Locator.ClickOptions().setClickCount(5));

Set the delay between mousedown and mouseup events:

button.click(new Locator.ClickOptions().setDelay(300));

Set keyboard modifiers (e.g., Alt, Control, Shift):

button.click(new Locator.ClickOptions().setModifiers(List.of(KeyboardModifier.SHIFT)));
  • evaluate()

Used to perform JavaScript against the element.

element.evaluate("el => el.innerHTML;");
  • fill()

Sets the value of an input field.

  • focus()

Focuses on the element.

  • hover()

Hovers the element.

  • selectOption()

Used with select elements.

// selects either by label or by value
element.selectOption("lamborghini");
// explicitly selects by label
element.selectOption(new SelectOption().setLabel("Lamborghini"));
// explicitly selects by value
element.selectOption(new SelectOption().setValue("lamborghini"));
// explicitly selects by index
element.selectOption(new SelectOption().setIndex(1));
// selects multiple
element.selectOption(new String[] { "lamborghini", "jaguar", "mustang"});

And some information methods include:

  • boundingBox()

This method will return a BoundingBox object, which has the following values: X, Y, Width, and Height.

  • innerHTML()

Returns the inner HTML as String.

  • innerText()

Returns the inner text as String.

  • isChecked()

If the corresponding element is either a checkbox or a radio button, it will return a boolean value. Otherwise it will throw an exception.

  • isDisabled()

If the corresponding element is interactable and thus can be disabled, it will return a boolean value.

  • isEditable()

Returns a boolean value if the corresponding element is editable.

  • isEnabled()

If the corresponding element is interactable and thus enabled, it will return a boolean value.

  • isHidden()

Returns whether the element is hidden.

  • isVisible()

Returns whether the element is visible.

Auto-Waiting

One of the core benefits of Playwright is its auto-waiting feature for elements. Before performing an action on an element, Playwright checks if the element meets specific criteria to receive the action.

For example, when clicking an element, Playwright validates if the element is visible, stable, capable of receiving events, and enabled. Similarly, when setting text in an input field, it checks if the element is visible, enabled, and editable.

While this auto-waiting generally enhances reliability and reduces flakiness, there are situations where you may want to disable it. Most methods in the Locator class provide an option in their corresponding Options object to force the action, thereby bypassing non-essential checks for actionability.

Let’s briefly look at the checks and what they do:

Visible

Elements will be considered visible if they:

  • Have non-empty bounding box
  • They don’t have computed visibility:hidden style
  • Their size is not zero
  • There is no display:none
  • The opacity is not zero

Stable

Elements will be considered stable if they maintain the same bounding box for two consecutive animation frames.

Enabled

Elements will be considered enabled unless they are interactable (buttons, selects, inputs) and they have a disabled attribute.

Editable

Elements are considered editable if they are enabled and don’t have a readonly attribute.

Receives Events

Element is considered receiving pointer events when there is no other element on top of it which will capture the click.

Playwright Assertions

Playwright includes a comprehensive set of assertions for elements, pages, and API responses. Let’s explore some of these assertions and how they are used!

The PlaywrightAssertions.assertThat() method takes one parameter, which should be an object implementing either the Page interface, APIResponse interface, or Locator interface. Depending on the type of object passed, it returns an instance of PageAssertions, APIResponseAssertions, or LocatorAssertions.

Each assertion type provides a not() method, which negates the assertion. This allows validation of conditions to be either true or false, depending on testing requirements.

By default, all assertions include a retry mechanism with a timeout until the condition is met. To customize this timeout, simply pass an Options object of the corresponding type as an argument and specify the desired timeout for the assertion method.

assertThat(page).hasURL("https://www.automatetheplanet.com", new PageAssertions.HasURLOptions().setTimeout(30_000));

Another way to customize the timeout is to directly set it from PlaywrightAssertions which will influence all assertions:

PlaywrightAssertions.setDefaultAssertionTimeout(15_000);

Page Assertions

  • hasURL()

Asserts the URL of the page and accepts 1 argument in the form of either a string or a regex pattern. The Options class has an option to perform a case-insensitive match.

  • hasTitle()

Asserts the title of the page and accepts 1 argument of either type String or type Pattern. It ensures that the page has or does not have the specified title.

API Response Assertions

  • isOK()

When testing, it’s crucial to monitor the API requests and responses alongside visible elements. Even though they aren’t seen by the user, they provide vital validation steps. If an API assertion fails, it helps pinpoint issues during test result analysis.

As expected, this method validates whether the status code falls within the 200-299 range.

Locator Assertions

Compared to other Assertion classes, the assertions for elements on the page are the most extensive in Playwright. Since the primary focus of testing is often on the elements visible to users, there are numerous states and conditions we can validate for these elements.

The most common assertion methods are:

  • containsText()

This validation ensures that the element contains the given text. This method also accepts in the form of an Options object an interesting setting: useInnerText which determines whether to use element.innerText or element.textContent.

Playwright normalizes whitespace when asserting the text.

  • hasText()

Similarly to the previously mentioned validation, this too ensures the element’s text. This time, it is the whole text. This method too has the userInnerText option.

  • hasValue()

Used with input fields, it will ensure that the value is the same as expected.

  • isDisabled()

When dealing with HTML elements such as buttons, inputs, select elements, textarea elements, etc. This assertion method will ensure that the element is disabled by checking if the “disabled” attribute is present. Note that this method won’t work with other elements.

  • isEnabled()

The opposite of the above method, works on the same interactable elements and will ensure the element is enabled.

  • isVisible()

Ensures that the element is visible by the criteria mentioned previously in the section about auto-waiting.

Summary

Discover Playwright, a robust tool for test automation with immense potential. We covered writing typical tests, navigating Locators, interacting with page elements, leveraging Playwright’s auto-wait feature for stability, and asserting website behavior. 

For deeper insights, explore Playwright’s official documentation.

Related Articles

Web Automation Java

Playwright Tutorial: Mastering Element Locators

This article explores the various techniques Playwright offers for locating elements, including basic methods such as CSS selectors and text selectors, as well

Playwright Tutorial: Mastering Element Locators

Web Automation Java

Deep Dive into JUnit Assertions with WebDriver and Custom Assertions

JUnit assertions are a cornerstone of Java testing, enabling developers to write tests that verify code behavior. In this article, we'll explore the various JUn

Deep Dive into JUnit Assertions with WebDriver and Custom Assertions

Web Automation Java

Design Grid Control Automated Tests with Java Part 3

In the previous articles, Design Grid Control Automated Tests Part 1 and Design Grid Control Automated Tests with Java Part 2, I started this mini-series about

Design Grid Control Automated Tests with Java Part 3

Web Automation Java

Playwright Tutorial: IFrame and Shadow DOM Automation

In this post, we will go through the basics of IFrames and Shadow DOM, and we will learn the strategies of automating these complex HTML structures with Playwri

Playwright Tutorial: IFrame and Shadow DOM Automation

Resources, Web Automation Java

Most Complete Selenium WebDriver Java Cheat Sheet

As you know, I am a big fan of Selenium WebDriver. You can find tonnes of useful Java code in my Web Automation Java Series. I lead automated testing courses an

Most Complete Selenium WebDriver Java Cheat Sheet

Web Automation Java

Design Grid Control Automated Tests with Java Part 1

In the previous article, I showed you how to automate complex custom-tuned controls like a grid. In my article Automate Telerik Kendo Grid with WebDriver and Ja

Design Grid Control Automated Tests with Java Part 1
Anton Angelov

About the author

Anton Angelov is Managing Director, Co-Founder, and Chief Test Automation Architect at Automate The Planet — a boutique consulting firm specializing in AI-augmented test automation strategy, implementation, and enablement. He is the creator of BELLATRIX, a cross-platform framework for web, mobile, desktop, and API testing, and the author of 8 bestselling books on test automation. A speaker at 60+ international conferences and researcher in AI-driven testing and LLM-based automation, he has been recognized as QA of the Decade and Webit Changemaker 2025.