Free Playwright Java Interview Questions

Read selected full answers and explore the sample question list before buying the full ebook.

This page is designed for readers searching for Playwright Java interview questions, Playwright automation interview questions, Playwright framework questions, and scenario-based Playwright interview preparation.

Sample Question List

  1. What is Playwright, and why is it used in test automation? (Playwright)
  2. Why is Playwright considered suitable for testing modern web applications like React, Angular, and Vue apps? (Playwright)
  3. What are the top 10 reasons to use Playwright for modern web automation? (Playwright)
  4. How would you get started with Playwright Java in a new automation project? (Playwright)
  5. How do you create a `BrowserContext` and `Page` in Playwright Java? (Playwright)
  6. Why is it important to close Playwright, browser, and context resources properly? (Playwright)
  7. What is the difference between `install`, `install-deps`, and `install --with-deps`? (Playwright)
  8. Does Playwright install Google Chrome and Microsoft Edge by default? (Playwright)
  9. How do you launch Microsoft Edge using the `channel` option in Playwright Java? (Playwright)
  10. Why should each test usually create a fresh `BrowserContext`? (Playwright)
  11. What are common mistakes with `BrowserContext` in Playwright Java? (Playwright)
  12. What is the difference between `page.waitForPopup()` and `context.waitForPage()`? (Playwright)
  13. How do you get all pages from a `BrowserContext` in Playwright Java? (Playwright)
  14. Why is visibility not enough before clicking an element in Playwright? (Playwright)
  15. How do you remove hard waits from an existing Playwright Java suite? (Playwright)
  16. What are web-first assertions in Playwright Java? (Playwright)
  17. Can you list all commonly used Playwright Java assertions with examples? (Playwright)
  18. How is a Playwright `Locator` different from a one-time element lookup? (Playwright)
  19. What is a good locator priority order in Playwright Java? (Playwright)
  20. How would you debug a locator that unexpectedly matches multiple elements? (Playwright)
  21. Why is it important to use logical key names such as `ArrowRight`, `Backspace`, or `Enter`? (Playwright)
  22. What would you do if `dragTo()` does not trigger drag-and-drop correctly in all browsers? (Playwright)
  23. How would you create storage state for different user roles? (Playwright)
  24. Why should authentication state files not be committed to Git? (Playwright)
  25. How do you handle file downloads in Playwright Java? (Playwright)
  26. How do you remove all selected files from a file input in Playwright Java? (Playwright)
  27. What are handles in Playwright Java? (Playwright)
  28. What kind of values can be passed as the optional argument to `Page.evaluate()`? (Playwright)
  29. What is the difference between navigation and loading in Playwright? (Playwright)
  30. How would you handle a JavaScript alert in Playwright Java? (Playwright)
  31. Why should `waitFor*` methods be preferred when waiting for browser events in Playwright Java? (Playwright)
  32. Why are browser contexts important for test isolation in Playwright? (Playwright)
  33. How do you locate an element inside a nested iframe? (Playwright)
  34. How would you decide whether to mock, modify, or observe network traffic in a test? (Playwright)
  35. What is the best practice for handling service workers in Playwright network tests? (Playwright)
  36. Why should `waitForTimeout()` generally be avoided in Playwright Java tests? (Playwright)
  37. What is the difference between `pauseAt`, `fastForward`, `runFor`, and `resume` in Playwright Clock? (Playwright)
  38. How do you capture screenshots in Playwright Java, and when are they useful? (Playwright)
  39. Why must the `BrowserContext` be closed for Playwright Java videos to be saved? (Playwright)
  40. Is Playwright Java thread-safe? (Playwright)
  41. How do Playwright’s auto-waiting and web-first assertions help reduce flaky tests? (Playwright)
  42. How do you detect slow API calls during UI execution? (Playwright)
  43. How would you refactor Codegen output into Page Objects? (Playwright)
  44. How do you open a Playwright trace in the browser using `trace.playwright.dev`? (Playwright)
  45. How do you register a custom selector engine in Playwright Java? (Playwright)
  46. How do you validate toast notifications in Playwright? (Automation Scenarios & Debugging)
  47. How do you wait for an element to disappear after submitting a form? (Automation Scenarios & Debugging)
  48. How do you test progress indicators during file upload? (Automation Scenarios & Debugging)
  49. How do you test drag-and-drop file upload areas? (Automation Scenarios & Debugging)
  50. How would you test a form that saves data asynchronously? (Automation Scenarios & Debugging)
  51. How do you test whether a modal traps keyboard focus correctly? (Automation Scenarios & Debugging)
  52. How would you validate that a modal closes after saving? (Automation Scenarios & Debugging)
  53. How do you switch between multiple pages in Playwright Java? (Automation Scenarios & Debugging)
  54. How would you test role-based access using Playwright Java? (Automation Scenarios & Debugging)
  55. How would you test access to a protected page without login? (Automation Scenarios & Debugging)
  56. How do you test forbidden access scenarios for role-based users? (Automation Scenarios & Debugging)
  57. How do you test UI updates that happen without full page reload? (Automation Scenarios & Debugging)
  58. How would you test frontend behavior when an API returns an empty response? (Automation Scenarios & Debugging)
  59. A critical end-to-end test is slow because it depends on real backend APIs. Would you mock the APIs? (Automation Scenarios & Debugging)
  60. How would you test an empty-state UI using route mocking? (Automation Scenarios & Debugging)
  61. How do you test responsive UI behavior across desktop, tablet, and mobile profiles in Playwright Java? (Automation Scenarios & Debugging)
  62. How would you test a tooltip using Playwright Java? (Automation Scenarios & Debugging)
  63. How do you validate that duplicate API calls are not triggered by a single UI action? (Automation Scenarios & Debugging)
  64. How does `page.pause()` help during local Playwright Java debugging? (Automation Scenarios & Debugging)
  65. An element is visible on screen, but `getByRole()` cannot find it. How would you debug this? (Automation Scenarios & Debugging)
  66. How would you debug locator failures inside web components or Shadow DOM? (Automation Scenarios & Debugging)
  67. A test fails because the DOM element is detached during interaction. How would you solve it? (Automation Scenarios & Debugging)
  68. A mocked response from one test affects another test. What is the likely design issue? (Automation Scenarios & Debugging)
  69. How do you review a Playwright test for maintainability? (Framework & Test Design)
  70. How would you avoid duplicate or low-value tests in a Playwright Java suite? (Framework & Test Design)
  71. A test uses `.first()` to fix a strict mode violation. How would you review that change? (Framework & Test Design)
  72. A test uses a broad global mock for `**/api/**`. What review concerns would you raise? (Framework & Test Design)
  73. Why is a static `Page` object dangerous in parallel Playwright Java tests? (Framework & Test Design)
  74. How do you design Page Object methods in Playwright Java? (Framework & Test Design)
  75. What are common Page Object Model mistakes in Playwright Java? (Framework & Test Design)
  76. A Page Object has 80 methods and controls many unrelated screens. What would you improve? (Framework & Test Design)
  77. Can a `Browser` be shared across parallel Playwright Java tests? (Framework & Test Design)
  78. What Java framework utilities must be thread-safe for parallel Playwright execution? (Framework & Test Design)
  79. A junior engineer added a helper that automatically retries every click three times. How would you review it? (Framework & Test Design)
  80. How would you migrate a framework from CSS/XPath-heavy locators to Playwright’s recommended locator strategy? (Framework & Test Design)
  81. A team wants to use only `data-testid` locators for all Playwright tests. What would you recommend? (Framework & Test Design)
  82. How would you prevent storage-state files from becoming stale or invalid? (Framework & Test Design)
  83. How would you identify the top 20% of tests that provide 80% of regression value? (Architect/Leadership)
  84. What principles would you follow for risk-based release automation with Playwright Java? (Architect/Leadership)
  85. How would you design a framework policy for using storage state across desktop and mobile Playwright Java suites? (Architect/Leadership)
  86. What code-review checklist would you use for Playwright Java pull requests? (Architect/Leadership)
  87. How would you build a Playwright automation strategy for a product moving from manual testing to continuous testing? (Architect/Leadership)
  88. How do you decide which test cases should be automated using Playwright? (Architect/Leadership)
  89. How do you define a “high-quality Playwright test” in practical terms? (Architect/Leadership)
  90. How do you decide naming conventions for `data-testid` attributes? (Architect/Leadership)
  91. How do you create a locator migration plan for an old Playwright suite? (Architect/Leadership)
  92. How would you prove that Playwright automation improved release speed? (Architect/Leadership)
  93. How do you make tests parallel-safe in Playwright Java? (Architect/Leadership)
  94. How would you recover automation credibility after automation missed a production defect? (Architect/Leadership)
  95. How would you prioritize fixing flaky tests when there are too many to fix immediately? (Architect/Leadership)
  96. Why is API testing useful in a Playwright Java automation framework? (Architect/Leadership)
  97. How do you decide whether a scenario should be tested through UI, API, or both? (Architect/Leadership)
  98. How do you decide whether a generated test should become a UI test, API test, component-level test, or be discarded? (Architect/Leadership)
  99. What are the limitations of using Selenium Grid with Playwright compared to native Playwright execution? (Advanced Playwright Topics)
  100. How would you design a Playwright Java framework to optionally run tests locally or on Selenium Grid? (Advanced Playwright Topics)
  101. When is snapshot testing not suitable? (Advanced Playwright Topics)
  102. How can omitting accessible names or attributes make ARIA snapshot tests more flexible? (Advanced Playwright Topics)
  103. How do you integrate axe accessibility checks with Playwright Java? (Advanced Playwright Topics)
  104. What are the limitations of automated accessibility testing? (Advanced Playwright Topics)
  105. Should every Playwright Java test run on every browser? (Advanced Playwright Topics)
  106. How can locator behavior differ across browsers in Playwright Java tests? (Advanced Playwright Topics)
  107. What makes visual tests flaky in Playwright Java? (Advanced Playwright Topics)
  108. How is Playwright `Locator` different from Selenium `WebElement`? (Advanced Playwright Topics)
  109. How should Selenium XPath-heavy tests be migrated to Playwright Java? (Advanced Playwright Topics)
  110. What are the limitations of Playwright mobile emulation compared with real-device testing? (Advanced Playwright Topics)
  111. When should you prefer `browser.newContext()` viewport configuration over `page.setViewportSize()`? (Advanced Playwright Topics)
  112. How would you make Playwright Java CI execution reliable across different build agents? (Advanced Playwright Topics)
  113. How would you configure headed and headless execution in Playwright Java? (Advanced Playwright Topics)
  114. How would you prevent timezone and locale drift between local and CI Playwright runs? (Advanced Playwright Topics)
  115. What principles would you follow for using AI in a Playwright Java automation program? (Advanced Playwright Topics)
  116. How would you train a Playwright Java team to use AI responsibly? (Advanced Playwright Topics)
  117. How would you prevent AI usage from weakening engineering skills in a Playwright team? (Advanced Playwright Topics)
  118. How would AI help detect weak Page Object design? (Advanced Playwright Topics)
  119. How would you design confidence scoring for AI Playwright failure recommendations? (Advanced Playwright Topics)

Selected full answers

Full answers are shown below for selected sample questions.

Question 1.1

What is Playwright, and why is it used in test automation?

Interview-Style Answer

Playwright is a modern end-to-end testing and browser automation tool used to test modern web applications reliably.

It is used because modern applications are dynamic and need stable automation. Playwright makes tests more reliable with features like auto-waiting, web-first assertions, browser context isolation, tracing which help reduce flaky test failures.

Playwright provides one API to test across different browsers, platforms, and languages. It supports Chromium, Firefox, WebKit, Windows, Linux, macOS, and languages like Java, JavaScript, TypeScript, Python, and .NET.

It also supports important real-project testing needs such as mobile web emulation, multiple tabs, multiple users, iframes, Shadow DOM, API testing, mock APIs, and network interception.

For faster test creation and debugging, Playwright provides useful tools like Codegen, Playwright Inspector, and Trace Viewer. Codegen helps generate test scripts by recording user actions, Inspector helps debug step by step, and Trace Viewer helps analyze failures with screenshots, DOM snapshots, actions, and network details.

Detailed Explanation

Playwright is useful because modern web applications are not simple static pages. They are usually dynamic, asynchronous, and heavily dependent on JavaScript, APIs, animations, validations, and real-time UI updates. Because of this, automation tools must wait correctly, interact like real users, and provide strong debugging support. Playwright solves these needs by providing reliable browser automation with built-in waiting, strong assertions, and powerful test execution features.

One major reason Playwright is reliable is auto-waiting. Before performing actions like click(), fill(), or selectOption(), Playwright automatically waits until the element is ready for action. This reduces the need for hard waits like Thread.sleep(), which often make tests slow and flaky. Its web-first assertions also retry validations until the expected condition is met, making checks more stable for dynamic pages.

Playwright also gives better test isolation using browser contexts. Each test can run in a fresh browser context, similar to a new browser profile, with separate cookies, local storage, sessions, and permissions. This prevents one test from affecting another. At the same time, authentication state can be saved and reused, so teams can avoid repeated login steps while still keeping tests isolated.

It is also suitable for real project scenarios because it supports cross-browser testing, mobile web emulation, multiple tabs, multiple users, iframes, Shadow DOM, API testing, mock APIs, and network interception. This means the same framework can validate both UI behavior and backend/API behavior, and it can also mock responses to test success, failure, empty data, or server-error scenarios.

For faster development and debugging, Playwright provides tools like Codegen, Playwright Inspector, and Trace Viewer. Codegen helps create test scripts by recording user actions. Inspector helps debug tests step by step. Trace Viewer helps analyze failures using screenshots, DOM snapshots, actions, source code, and network details.

Common mistake: treating Playwright only as a browser automation tool. In real projects, it is a complete end-to-end testing framework for reliable, isolated, cross-browser, API-enabled, mock-supported, and debuggable automation.



Question 1.2

Why is Playwright considered suitable for testing modern web applications like React, Angular, and Vue apps?

Interview-Style Answer

Playwright is suitable for modern web applications because it is designed to handle dynamic UI behavior, asynchronous DOM updates, auto-waiting, reliable locators, and stable assertions. This makes it effective for testing applications built with frameworks like React, Angular, and Vue, where elements can appear, disappear, or change state without a full page reload.

Detailed Explanation

Modern web applications are usually dynamic. In frameworks like React, Angular, and Vue, the page does not always reload fully after every action. Instead, the application updates only parts of the DOM.

For example:

  • A button may become enabled after an API response.
  • A list may update after filtering.
  • A modal may appear after a user action.
  • A component may re-render after state change.
  • A loading spinner may disappear after data is loaded.

Traditional automation tools may struggle with these asynchronous changes because they often try to interact with elements before the UI is ready.

Playwright helps solve this problem through auto-waiting. Before performing actions, Playwright waits for the element to be ready for interaction. It checks conditions such as:

  • Element is visible.
  • Element is stable.
  • Element is enabled.
  • Element is ready to receive user action.

This reduces the need for hard waits like Thread.sleep() and makes tests more reliable.

Playwright also provides web-first assertions. These assertions automatically retry until the expected condition becomes true or the timeout is reached. This is very useful in SPAs because UI updates may happen after a short delay.

Another major advantage is its locator strategy. Playwright encourages user-facing locators such as:

  • getByRole()
  • getByText()
  • getByLabel()

These locators are based on how users see and interact with the application, rather than depending heavily on fragile DOM structures. This is especially useful in React, Angular, and Vue applications where DOM structure may change because of component re-rendering.

Example Scenario

Suppose a React application loads a “Submit” button only after form validation is complete.

With Playwright, we can write:

page.getByRole(AriaRole.BUTTON,
  new Page.GetByRoleOptions().setName("Submit")).click();

Playwright will wait until the button is ready for interaction before clicking it.

Common mistake:

A common mistake is treating modern web apps like static HTML pages.

In SPAs, the UI changes dynamically. So, using fixed waits, fragile XPath, or immediate assertions can create flaky tests. Playwright is preferred because it works naturally with dynamic UI behavior through auto-waiting, retrying assertions, and reliable locators.



Question 1.11

What are the top 10 reasons to use Playwright for modern web automation?

Interview-Style Answer

The top 10 reasons to use Playwright are:

  • It handles modern web applications smoothly.
  • It provides auto-waiting for stable execution.
  • It supports smart web-first assertions.
  • It offers reliable user-centric locators.
  • It supports real mobile device emulation.
  • It provides strong test isolation using browser contexts.
  • It handles multiple tabs and windows efficiently.
  • It supports reusable authentication.
  • It provides advanced network interception and API mocking.
  • It supports both UI and API testing in the same framework.

Detailed Explanation

Playwright is a strong choice for modern web automation because it is designed for today’s dynamic web applications.

Modern applications built using frameworks like React, Angular, and Vue update the page dynamically without full page reloads. Elements may appear, disappear, or change state asynchronously. Playwright handles these changes well because it waits for elements to be ready before performing actions. This makes it suitable for testing SPAs and highly interactive web applications.

The first major reason is auto-waiting. Playwright automatically waits for elements to become:

  • Visible
  • Stable
  • Enabled
  • Ready for interaction

Because of this, we do not need to depend heavily on Thread.sleep() or unnecessary manual waits. This directly improves test stability.

The second major advantage is web-first assertions. Playwright assertions automatically retry until the expected condition becomes true or the timeout is reached. This is very useful for dynamic UIs where the expected text, element, or state may take a short time to appear.

Another important reason is its robust locator strategy. Playwright promotes user-facing locators such as:

  • getByRole()
  • getByText()
  • getByLabel()

These locators are closer to how real users interact with the application, so tests become more readable and maintainable.

Playwright also supports real mobile device emulation. We can emulate devices like iPhone, Pixel, and iPad, along with screen size and touch behavior. This helps test mobile responsiveness without always needing physical devices.

A very important feature is test isolation using browser contexts. Each test can run in a separate browser context with its own:

  • Cookies
  • Sessions
  • Local storage
  • Clean browser state

This prevents one test from affecting another test and makes execution more reliable.

Playwright also makes it easier to handle real-world browser scenarios such as:

  • Multiple tabs
  • New windows
  • Popups
  • Payment gateway redirects
  • Report windows

Another useful reason is reusable authentication. We can log in once, save the authenticated state, and reuse it across multiple tests. This saves execution time, especially in large regression suites.

Playwright also provides network interception and API mocking. This allows us to:

  • Intercept network requests
  • Mock API responses
  • Simulate backend failures
  • Test UI even when backend services are unstable

Finally, Playwright supports both UI testing and API testing. This makes it useful for end-to-end testing because we can prepare backend data, test the UI flow, and validate server-side results within the same automation framework.

Common mistake:

A common mistake is thinking Playwright is only another browser automation tool.

In reality, Playwright is useful because it combines many modern automation needs in one framework:

  • Stable UI automation
  • Cross-browser testing
  • Mobile emulation
  • Test isolation
  • Network control
  • Debugging support
  • API testing

This makes it more suitable for modern end-to-end automation than tools that focus only on simple browser actions.


2. Get Started

Part I - Core Questions


Question 2.1

How would you get started with Playwright Java in a new automation project?

Interview-Style Answer

To get started with Playwright Java in a new automation project, I would first create a Maven or Gradle project, add the Playwright Java dependency, and write a simple test to launch a browser, open a page, perform a basic action, and validate the result.

After confirming that the basic setup works, I would introduce a test framework such as JUnit or TestNG. Then I would organize the project with proper setup and teardown methods, browser/context management, reusable page objects, configuration handling, assertions, and reporting.

In real projects, I would also make sure the framework supports browser selection, environment selection, headless/headed execution, CI execution, screenshots, traces, and proper cleanup of Playwright resources.

Detailed Explanation

Getting started with Playwright Java should be done step by step. The first goal is to verify that Playwright is installed correctly and can control a browser successfully. So I would begin with a simple Maven or Gradle project and add the Playwright Java dependency.

A basic starting flow would be:

1. Create a Maven or Gradle project.
2. Add the Playwright Java dependency.
3. Install or ensure Playwright browser binaries are available.
4. Create a simple Java test.
5. Create a Playwright instance.
6. Launch Chromium, Firefox, or WebKit.
7. Create a BrowserContext and Page.
8. Navigate to the application.
9. Perform a basic action or assertion.
10. Close resources properly.

The basic Playwright object flow is:

Playwright → Browser → BrowserContext → Page → Locator → Actions / Assertions

Example Maven dependency:

<dependency>
  <groupId>com.microsoft.playwright</groupId>
  <artifactId>playwright</artifactId>
  <version>${playwright.version}</version>
</dependency>

Using a property for the version is better in real projects because it keeps dependency upgrades easier.

Example Java code:

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

public class FirstPlaywrightTest {
    public static void main(String[] args) {
        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://example.com");
            assertThat(page.locator("h1")).hasText("Example Domain");

            context.close();
            browser.close();
        }
    }
}

Once this basic script works, I would move from a simple main method to a proper test framework like JUnit or TestNG. The framework should manage setup and teardown, create a fresh BrowserContext for each test, close resources after execution, and support command-line execution using Maven or Gradle.

For a real automation project, I would gradually add:

- Base test setup
- Browser and environment configuration
- Page Object Model
- Reusable locators and actions
- Playwright assertions
- Test data handling
- Screenshots on failure
- Trace and video capture
- CI/CD execution support
- Reporting integration

This approach keeps the project simple at the beginning and scalable later. The important point is not just to launch a browser, but to build the foundation correctly so that tests are reliable, maintainable, and easy to run in local and CI environments.

Common mistake: starting with a complex framework before verifying the basic Playwright Java setup. In real projects, first confirm that Playwright can launch the browser, open the application, perform actions, validate results, and close resources properly; then build the framework layer step by step.



Question 2.6

How do you create a BrowserContext and Page in Playwright Java?

Interview-Style Answer

Create a browser context using browser.newContext(), then create a page using context.newPage(). The context gives test isolation, and the page represents the browser tab used for automation.

In Playwright Java, this matters because a BrowserContext provides an isolated browser session with its own cookies, storage, permissions, and session data, while a Page represents the tab where navigation, actions, and validations are performed.

Detailed Explanation

A BrowserContext acts like an isolated browser profile. It has its own cookies, local storage, session storage, permissions, and other browser state. This helps keep tests independent and prevents one test from affecting another.

A Page is created inside a browser context. It represents a browser tab or window and is used to perform actions such as navigation, clicking, typing, uploading files, and validating UI behavior.

Example:

Browser browser = playwright.chromium().launch();

BrowserContext context = browser.newContext();

Page page = context.newPage();

page.navigate("https://example.com");

context.close();
browser.close();

For reliable test automation frameworks, each test should usually get a fresh browser context. This avoids state leakage between tests and makes execution more predictable, especially in CI or parallel runs.

Common mistake: using one shared page or browser context for many unrelated tests. This can cause test dependency, session leakage, unstable failures, and incorrect results.



Question 2.12

Why is it important to close Playwright, browser, and context resources properly?

Interview-Style Answer

It is important to close Playwright, browser, and context resources properly because unclosed resources can leave browser processes running, consume memory, lock files, slow down execution, and make CI pipelines unstable.

In Playwright Java, tests communicate with real browser processes. If these resources are not closed after execution, they may remain active in the background and affect later tests. Proper cleanup keeps the framework stable, prevents memory leaks, and ensures predictable test execution.

Detailed Explanation

Playwright Java creates and manages real automation resources during test execution. Playwright starts the Playwright engine, Browser launches the browser process, BrowserContext creates an isolated browser profile, and Page opens a browser tab.

If these resources are not closed correctly, the browser process or context may continue running even after the test has finished. Over time, especially in large test suites or CI/CD pipelines, this can lead to memory usage issues, hanging test runs, locked files, port/resource conflicts, and unstable execution.

A good practice is to use try-with-resources for Playwright and explicitly close the BrowserContext and Browser.

try (Playwright playwright = Playwright.create()) {
    Browser browser = playwright.chromium().launch();
    BrowserContext context = browser.newContext();
    Page page = context.newPage();

    page.navigate("https://example.com");

    context.close();
    browser.close();
}

In real frameworks, cleanup is usually handled using JUnit or TestNG lifecycle methods such as @AfterEach, @AfterMethod, @AfterAll, or @AfterSuite. This ensures that resources are closed even when a test fails.

Common mistake: closing only the page and forgetting to close the browser context, browser, or Playwright instance. In real projects, proper cleanup is part of framework stability, not just code hygiene.


3. Installation & Browser

Part I - Core Questions


Question 3.8

What is the difference between install, install-deps, and install --with-deps?

Interview-Style Answer

In Playwright Java, these commands are related to browser setup, but they solve different setup problems.

install              -> installs Playwright browser binaries
install-deps         -> installs required OS/system dependencies
install --with-deps  -> installs both browser binaries and OS/system dependencies

install is mainly for downloading Playwright-supported browser binaries such as Chromium, Firefox, and WebKit. install-deps is mainly for Linux, Docker, or CI machines where required system libraries may be missing. install --with-deps combines both and is commonly useful for clean CI or container setup.

Detailed Explanation

Playwright tests run against real browser engines. For those browsers to run correctly, two things may be needed:

1. Playwright-managed browser binaries
2. Operating system libraries required by those browsers

The install command downloads browser binaries:

mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install"

This is useful during local setup, fresh machine setup, or after upgrading the Playwright version. Without the browser binary, Playwright may not be able to launch Chromium, Firefox, or WebKit.

Example test that needs the browser binary:

try (Playwright playwright = Playwright.create()) {
    Browser browser = playwright.chromium().launch();
    Page page = browser.newPage();

    page.navigate("https://example.com");

    PlaywrightAssertions.assertThat(page)
        .hasTitle(Pattern.compile("Example"));

    browser.close();
}

The install-deps command installs OS-level dependencies:

mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install-deps"

These dependencies include system libraries needed for graphics, fonts, audio, sandboxing, rendering, and shared Linux libraries. This matters most in minimal environments such as Docker images, Linux build agents, and CI runners.

You can also install dependencies for a specific browser:

mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install-deps chromium"

This is useful when the framework runs only Chromium and does not need Firefox or WebKit dependencies.

The install --with-deps command installs both browser binaries and system dependencies:

mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps chromium"

This is often the safest option for clean CI or Docker setup because it reduces the chance of installing the browser but forgetting the required OS packages.

Simple comparison:

install
- Installs browser binaries
- Useful for local setup and Playwright upgrades

install-deps
- Installs OS/system dependencies
- Useful for Linux, Docker, and CI environments

install --with-deps
- Installs browser binaries and OS dependencies together
- Useful for clean CI/Docker setup

A good Playwright Java framework should document these setup steps clearly in the README, Dockerfile, or CI pipeline. If tests fail with missing shared libraries, sandbox errors, browser launch failures, or dependency-related Linux errors, the setup may be missing install-deps or install --with-deps.

Common mistake: Running only install in a Linux or CI environment and assuming setup is complete. install downloads browser binaries, but it does not always guarantee that the operating system has all libraries required to run those browsers.



Question 3.14

Does Playwright install Google Chrome and Microsoft Edge by default?

Interview-Style Answer

No. Playwright does not install branded Google Chrome or Microsoft Edge by default.

By default, Playwright installs and uses Playwright-managed browser builds such as Chromium, Firefox, and WebKit. Playwright-managed Chromium is not the same as branded Google Chrome or Microsoft Edge.

If a project needs to run tests on branded Chrome or Edge, those browsers must be available on the machine, and the test should launch them using the channel option.

Detailed Explanation

Playwright can run tests using both Playwright-managed browsers and supported branded Chromium-based browser channels.

Default Chromium execution:

Browser browser = playwright.chromium().launch();

This launches Playwright-managed Chromium. It does not automatically launch Google Chrome installed on the machine.

To launch branded Google Chrome:

Browser browser = playwright.chromium().launch(
    new BrowserType.LaunchOptions().setChannel("chrome")
);

To launch branded Microsoft Edge:

Browser browser = playwright.chromium().launch(
    new BrowserType.LaunchOptions().setChannel("msedge")
);

Common branded browser channels include:

1. chrome
2. msedge
3. chrome-beta
4. msedge-beta
5. chrome-dev
6. msedge-dev
7. chrome-canary
8. msedge-canary

This is useful when the test strategy requires validation on the same branded browser used by customers, enterprise users, or production support teams. For example, an organization may run most regression tests on Playwright-managed Chromium but add a smaller smoke suite on branded Chrome Stable or Edge Stable.

The normal browser installation command:

mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install"

installs Playwright-managed browsers. It does not install branded Google Chrome or Microsoft Edge.

If the framework uses:

new BrowserType.LaunchOptions().setChannel("chrome")

or:

new BrowserType.LaunchOptions().setChannel("msedge")

then the CI agent, Docker image, or developer machine must already have that branded browser installed and accessible.

Common mistake: assuming mvn exec:java -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install" installs Google Chrome or Microsoft Edge. It installs Playwright-managed browser binaries; branded Chrome or Edge must be installed separately before launching them with setChannel("chrome") or setChannel("msedge").



Question 3.17

How do you launch Microsoft Edge using the channel option in Playwright Java?

Interview-Style Answer

In Playwright Java, Microsoft Edge is launched through playwright.chromium() because Edge is a Chromium-based browser. To use the installed Microsoft Edge browser instead of Playwright-managed Chromium, set the browser channel to msedge.

Browser browser = playwright.chromium().launch(
    new BrowserType.LaunchOptions().setChannel("msedge")
);

This is useful when the project needs Edge-specific validation, customer-browser certification, enterprise policy testing, or reproduction of an issue that appears only in branded Microsoft Edge.

Detailed Explanation

Playwright-managed Chromium is used by default when we call:

Browser browser = playwright.chromium().launch();

But Microsoft Edge is a branded Chromium-based browser installed separately on the machine. To launch it, we still use the Chromium browser type, but specify the Edge channel.

Complete example:

import com.microsoft.playwright.*;
import java.util.regex.Pattern;

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

public class EdgeLaunchExample {
  public static void main(String[] args) {
    try (Playwright playwright = Playwright.create()) {
      Browser browser = playwright.chromium().launch(
        new BrowserType.LaunchOptions()
          .setChannel("msedge")
          .setHeadless(true)
      );

      Page page = browser.newPage();
      page.navigate("https://example.com");

      assertThat(page).hasTitle(Pattern.compile("Example"));

      browser.close();
    }
  }
}

Common Edge channels include:

msedge          -> Microsoft Edge Stable
msedge-beta     -> Microsoft Edge Beta
msedge-dev      -> Microsoft Edge Dev
msedge-canary   -> Microsoft Edge Canary

Use Edge channel testing when:

1. Customers officially use Microsoft Edge.
2. Release certification requires Edge validation.
3. A defect reproduces only in Edge.
4. Enterprise policies affect browser behavior.
5. The team needs to compare Edge behavior with Playwright-managed Chromium.

This should be configured carefully in CI. Playwright does not install branded Microsoft Edge by default, so the CI image or execution machine must already have Edge installed. The framework should also document which browser channels are supported locally and in CI to avoid browser launch failures.

Common mistake: Assuming Playwright automatically installs Microsoft Edge when using setChannel("msedge"). Playwright-managed Chromium is installed by Playwright, but branded Edge must already be available on the machine or CI image.


4. BrowserContext

Part I - Core Questions


Question 4.3

Why should each test usually create a fresh BrowserContext?

Interview-Style Answer

Each test should usually create a fresh BrowserContext because the context is the main unit of browser-session isolation in Playwright Java. It keeps cookies, local storage, session storage, permissions, cache, viewport settings, and authentication state separate between tests.

This prevents session leakage, order-dependent failures, false positives, and unstable parallel execution. A common framework pattern is to reuse Playwright and Browser where appropriate, but create a new BrowserContext and Page for each test.

Detailed Explanation

A BrowserContext behaves like an independent browser profile. If multiple tests share the same context, they can accidentally share login state, cart data, permissions, cached data, local storage, feature flags, or application state.

A good lifecycle is:

@BeforeEach
void setup() {
    context = browser.newContext();
    page = context.newPage();
}

@AfterEach
void cleanup() {
    context.close();
}

This pattern gives each test a clean browser session. One test does not depend on whether another test logged in, accepted a cookie banner, changed a language setting, granted a permission, added an item to a cart, or stored data in local storage.

Benefits of a fresh context include:

1. No login-state leakage.
2. No cookie or token leakage.
3. No local storage or session storage leakage.
4. No permission leakage.
5. No cart, order, or workflow-state leakage.
6. Better parallel execution.
7. Easier debugging because each test starts from a known state.
8. Safer role-based testing.
9. Cleaner artifact capture and teardown.
10. More reliable CI execution.

For example, if one test logs in as an admin and another test expects a guest user, sharing the same context can produce a false result. The second test may pass or fail because it inherited the admin session instead of starting clean.

For different users, separate contexts are also required:

BrowserContext adminContext = browser.newContext();
Page adminPage = adminContext.newPage();

BrowserContext customerContext = browser.newContext();
Page customerPage = customerContext.newPage();

This keeps admin and customer cookies, tokens, permissions, and storage separate.

Fresh contexts are especially important in CI/CD and parallel execution because tests may run in a different order or at the same time. Without proper context isolation, failures can become difficult to reproduce because they depend on hidden browser state from another test.

Common mistake: Reusing one BrowserContext across many tests to save setup time. This can leak cookies, storage, permissions, and application state between tests, creating false positives, false failures, and order-dependent behavior that becomes worse in parallel CI execution.



Question 4.9

What are common mistakes with BrowserContext in Playwright Java?

Interview-Style Answer

Common mistakes with BrowserContext include reusing one context for all tests, using the same context for different users, sharing a static Page, not closing contexts after tests, misusing storage state, and configuring permissions, viewport, locale, or timezone at the wrong level.

In Playwright Java, BrowserContext is the main unit of browser-session isolation. A good framework should create a fresh context per test or per independent user session, configure context-level options before creating the page, and close the context during teardown to avoid state leakage and resource issues.

Detailed Explanation

BrowserContext controls browser-session state such as cookies, local storage, permissions, viewport, locale, timezone, geolocation, extra headers, downloads, and storage state. Many flaky tests come from misunderstanding this responsibility.

Common mistakes include:

1. Reusing one BrowserContext for all tests.
2. Sharing a static Page across tests.
3. Using the same context for admin, customer, and other users.
4. Not closing the context after each test.
5. Loading the wrong storage-state file for a role.
6. Reusing expired or stale authentication state.
7. Expecting cookies or local storage to automatically cross contexts.
8. Setting permissions after the page has already started the workflow.
9. Forgetting viewport, locale, timezone, and geolocation are context-level settings.
10. Running parallel tests without isolated users, data, downloads, and storage state.

A better framework pattern is:

@BeforeEach
void setUp() {
    context = browser.newContext(
        new Browser.NewContextOptions()
            .setViewportSize(1366, 768)
            .setLocale("en-IN")
            .setTimezoneId("Asia/Kolkata")
    );

    page = context.newPage();
}

@AfterEach
void tearDown() {
    context.close();
}

For multiple users, create separate contexts instead of multiple pages in the same context:

BrowserContext adminContext = browser.newContext(
    new Browser.NewContextOptions()
        .setStorageStatePath(Paths.get("auth/admin.json"))
);
Page adminPage = adminContext.newPage();

BrowserContext customerContext = browser.newContext(
    new Browser.NewContextOptions()
        .setStorageStatePath(Paths.get("auth/customer.json"))
);
Page customerPage = customerContext.newPage();

This keeps cookies, tokens, local storage, permissions, and session data separate. It is especially important for role-based tests, parallel execution, CI stability, and tests that depend on clean user state.

Storage state should also be used carefully. It can speed up authenticated tests, but each role should have its own storage-state file, and those files should not expose sensitive tokens in Git, reports, traces, screenshots, or logs. If authentication expires often, the framework should refresh storage state in a controlled way.

A clean approach is:

- Reuse Playwright and Browser where appropriate.
- Create a fresh BrowserContext per test.
- Use a separate BrowserContext per user.
- Configure context options before creating the Page.
- Keep storage-state files role-specific.
- Isolate test data, files, downloads, and users for parallel runs.
- Close the BrowserContext after each test.

Common mistake: Treating BrowserContext as just a browser container and then sharing it across tests or users. This causes hidden state leakage through cookies, local storage, permissions, cached data, and storage-state files, leading to flaky, order-dependent, and unsafe parallel execution.


5. Page

Part I - Core Questions


Question 5.5

What is the difference between page.waitForPopup() and context.waitForPage()?

Interview-Style Answer

page.waitForPopup() waits for a popup opened by a specific Page. It is best when a known action on the current page opens a new tab or window.

context.waitForPage() waits for any new Page created inside the BrowserContext. It is useful when the new page may be created from anywhere in the context, or when the opener page is not the main focus.

Detailed Explanation

In Playwright Java, both methods return a Page, but they listen at different levels.

page.waitForPopup() is tied to a specific opener page. Use it when the current page action clearly opens the popup. This keeps the relationship between the original page and the popup easy to understand.

Page popup = page.waitForPopup(() -> {
    page.getByRole(AriaRole.LINK,
        new Page.GetByRoleOptions().setName("Open Report")
    ).click();
});

popup.waitForLoadState();

PlaywrightAssertions.assertThat(
    popup.getByText("Report Details")
).isVisible();

Here, the popup is expected to be opened by page. This is common for links with target="_blank", report links, payment windows, invoice pages, or external help pages.

context.waitForPage() listens at the BrowserContext level. It captures a new page created anywhere inside that context.

Page docsPage = context.waitForPage(() -> {
    page.getByText("Open documentation").click();
});

docsPage.waitForLoadState();

PlaywrightAssertions.assertThat(
    docsPage.getByText("Documentation")
).isVisible();

This is useful when the test cares about any newly created page in the context, or when the source of the new page is less direct. For example, a popup may be triggered indirectly by application code, another page, a redirect flow, or a shared context-level workflow.

The practical rule is simple: use page.waitForPopup() when one known page action opens the popup. Use context.waitForPage() when you want to capture any new page created in the context.

Both should be started before the action that creates the new page. If the click happens first and the wait starts later, Playwright may miss the page creation event.

Common mistake: using context.waitForPage() everywhere even when page.waitForPopup() would make the opener relationship clearer and reduce confusion in multi-page tests.



Question 5.10

How do you get all pages from a BrowserContext in Playwright Java?

Interview-Style Answer

In Playwright Java, you can get all currently open pages in a BrowserContext using context.pages().

List<Page> allPages = context.pages();

This returns the current list of Page objects, including normal tabs and popup pages inside that context. It is useful for inspecting, logging, debugging, or cleaning up multiple pages, but it should not be used as the primary way to capture a page opened by a known action.

Detailed Explanation

A single BrowserContext can contain multiple Page objects. Each Page represents a tab or popup-like browser page that belongs to that isolated context.

Example:

BrowserContext context = browser.newContext();

Page productsPage = context.newPage();
Page cartPage = context.newPage();

productsPage.navigate("https://example.com/products");
cartPage.navigate("https://example.com/cart");

List<Page> allPages = context.pages();

System.out.println("Total pages: " + allPages.size());

You can iterate through the current pages when debugging or managing multiple tabs:

for (Page p : context.pages()) {
    System.out.println("Page URL: " + p.url());
    System.out.println("Page title: " + p.title());
}

This is useful for scenarios such as:

- Checking how many pages are open in a context
- Debugging unexpected tabs or popups
- Logging page URLs during failure analysis
- Closing extra pages after validation
- Inspecting multi-tab workflows

However, context.pages() only gives the current snapshot of pages. It does not wait for a new page to open. If a specific user action should open a new tab, use context.waitForPage() instead:

Page reportPage = context.waitForPage(() -> {
    page.getByRole(
        AriaRole.LINK,
        new Page.GetByRoleOptions().setName("Open report")
    ).click();
});

reportPage.waitForLoadState();

PlaywrightAssertions.assertThat(
    reportPage.getByText("Report Summary")
).isVisible();

For a popup opened from a specific page, page.waitForPopup() is often more precise:

Page popup = page.waitForPopup(() -> {
    page.getByText("Open invoice").click();
});

So, use context.pages() when you need the current list of pages. Use context.waitForPage() or page.waitForPopup() when the test must reliably capture a newly opened page from a known action.

Common mistake: using context.pages() and assuming the last page in the list is always the newly opened tab. In stable automation, capture known new pages with context.waitForPage() or page.waitForPopup() instead of guessing from the page list.


6. Autowait

Part I - Core Questions


Question 6.6

Why is visibility not enough before clicking an element in Playwright?

Interview-Style Answer

Visibility only means the element is present and can be seen on the page. It does not guarantee that the element is ready for a real user click.

Before clicking, Playwright checks more than visibility. The element should be stable, enabled, attached to the DOM, and able to receive pointer events. If the element is covered by a modal, sticky header, loader, animation, badge, or overlay, it may be visible but still not practically clickable.

Detailed Explanation

In real web applications, an element can be visible but still not safe to click. For example, a button may appear on the screen while the page is still loading, an animation may still be moving it, or another invisible overlay may be sitting above it. A user would not be able to click the element correctly in that state, so Playwright should not click it blindly.

Example:

Locator accountCard = page.locator("#account-card");
accountCard.click();

Before performing the click, Playwright checks whether the locator resolves to an actionable element. It verifies conditions such as visibility, stability, enabled state, and whether the element can receive pointer events. This prevents the test from passing by doing something a real user could not do.

A common case is an overlapping element:

Visible card:        #account-card
Overlapping element: status badge / loader / sticky header / modal overlay

Even though #account-card is visible, the actual click point may be blocked. In that situation, Playwright may fail the click instead of incorrectly pretending that the user can interact with the card.

A better test should wait for the real clickable state or remove the blocking condition through a valid user flow:

Locator accountCard = page.locator("#account-card");

PlaywrightAssertions.assertThat(accountCard).isVisible();
accountCard.click();

If a loader or overlay is expected, wait for it to disappear:

Locator loader = page.locator(".loading-overlay");
PlaywrightAssertions.assertThat(loader).isHidden();

page.locator("#account-card").click();

Using force: true should be rare because it bypasses Playwright’s actionability checks. It may hide a real product issue where the UI looks visible but is not actually usable.

Common mistake: forcing the click as soon as the element is visible instead of checking why the element is not receiving pointer events.



Question 6.15

How do you remove hard waits from an existing Playwright Java suite?

Interview-Style Answer

To remove hard waits from an existing Playwright Java suite, first identify what each wait was trying to protect, then replace it with a real synchronization condition. That condition could be a locator assertion, URL assertion, API response wait, download wait, popup wait, navigation wait, or business-state validation.

The goal is not just to delete waitForTimeout(). The goal is to replace time-based waiting with condition-based waiting so the test proceeds when the application is actually ready.

Detailed Explanation

Hard waits like page.waitForTimeout(3000) make tests slower and still unreliable. If the application is ready in 500 milliseconds, the test wastes time. If the application takes 5 seconds, the test may still fail. So the correct approach is to understand why the hard wait was added and replace it with a meaningful signal.

Common replacements:

waitForTimeout after login
-> assert dashboard heading or user profile is visible

waitForTimeout after search
-> assert result row, result count, or empty state is visible

waitForTimeout after save
-> assert success message or updated row status is visible

waitForTimeout after export
-> use waitForDownload()

waitForTimeout after popup click
-> use waitForPopup()

waitForTimeout after API-triggering action
-> use waitForResponse() and then assert the visible UI result

Weak approach:

page.getByRole(AriaRole.BUTTON,
    new Page.GetByRoleOptions().setName("Save")
).click();

page.waitForTimeout(3000);

PlaywrightAssertions.assertThat(
    page.getByText("Saved successfully")
).isVisible();

Better approach:

page.getByRole(AriaRole.BUTTON,
    new Page.GetByRoleOptions().setName("Save")
).click();

PlaywrightAssertions.assertThat(
    page.getByText("Saved successfully")
).isVisible();

Here, the web-first assertion automatically retries until the success message appears or the timeout is reached.

For API-based synchronization, wait for the relevant response and then verify the user-visible result:

Response response = page.waitForResponse(
    res -> res.url().contains("/api/orders")
        && res.status() == 200,
    () -> {
        page.getByRole(AriaRole.BUTTON,
            new Page.GetByRoleOptions().setName("Submit Order")
        ).click();
    }
);

PlaywrightAssertions.assertThat(
    page.getByText("Order submitted successfully")
).isVisible();

For downloads:

Download download = page.waitForDownload(() -> {
    page.getByRole(AriaRole.BUTTON,
        new Page.GetByRoleOptions().setName("Export")
    ).click();
});

download.saveAs(Paths.get("downloads/report.xlsx"));

For popups:

Page popup = page.waitForPopup(() -> {
    page.getByRole(AriaRole.LINK,
        new Page.GetByRoleOptions().setName("Open Report")
    ).click();
});

popup.waitForLoadState();

In real projects, removing hard waits should be done carefully. Each wait should be replaced with the exact condition the test depends on. This improves speed, stability, and debugging because failures now point to the missing condition instead of an arbitrary timeout.

Common mistake: removing waitForTimeout() without replacing it with the actual readiness condition, which makes the test faster but more flaky.


7. Assertions

Part I - Core Questions

Ready to prepare with the complete 1800+ question ebook?

Buy the Full Ebook