Showing posts with label Java Automation. Show all posts
Showing posts with label Java Automation. Show all posts

Selenium vs Playwright

 



Below is the detailed comparison of Playwright and Selenium which are two popular open-source web automation tools.


Selenium

Selenium is one of the oldest and most widely used web automation frameworks. It supports multiple programming languages such as Java, Python, C#, Ruby, and JavaScript, and works across many browsers. Selenium operates using the WebDriver protocol, which communicates with browsers to perform actions like clicking, typing, or navigating. 

It has a large community, strong ecosystem, and compatibility with many third-party tools like TestNG, JUnit, or Maven. However, Selenium often requires explicit waits to handle dynamic content, and test execution can sometimes be slower compared to modern frameworks. 

Its biggest advantage is its maturity, stability, and wide industry adoption.


Playwright

Playwright is a relatively newer automation framework developed by Microsoft. It supports JavaScript/TypeScript, Python, Java, and .NET. Unlike Selenium, Playwright does not rely on WebDriver; it directly communicates with browsers using native DevTools protocols, which makes it faster and more reliable. Playwright provides built-in auto-waiting mechanisms, making it easier to handle dynamic web applications without adding many explicit waits. 

It also has advanced features like intercepting network requests, handling multiple browser contexts, working with iframes, and supporting modern browsers including Chromium, Firefox, and WebKit. 

Additionally, Playwright supports parallel execution and cross-browser testing out of the box. Its modern design makes it well-suited for today’s single-page applications.










FeaturePlaywrightSelenium
ArchitectureModern, browser automation through WebSocket protocolTraditional, uses WebDriver protocol
Languages SupportedJavaScript, TypeScript, Python, C#, JavaJava, Python, C#, Ruby, JavaScript, Kotlin, etc.
Browsers SupportedChromium, Firefox, WebKit (Safari engine)Chrome, Firefox, Safari, IE, Edge
Cross-browser TestingYes (via single API)Yes (via WebDriver, requires separate drivers)
Headless ModeBuilt-in for all browsersSupported but configuration-heavy
Mobile EmulationBuilt-in (Android/iOS simulation)Supported via Chrome DevTools or Appium
Multi-tab/Context SupportExcellent (isolated browser contexts)Limited (each tab requires handling in a new driver instance)
Auto-wait for ElementsYes (automatic waiting for DOM/state readiness)Manual waits often needed (e.g., WebDriverWait)
Screenshots/VideosBuilt-in support for screenshots, videos, and tracesScreenshots supported, video needs external integration
Debugging ToolsBuilt-in tracing, time-travel debuggingBasic logs, stack traces, external tools needed for deep debug
Execution SpeedFaster (uses WebSocket and optimized browser contexts)Slower (uses HTTP/WebDriver protocol)
Parallel ExecutionBuilt-in support (workers, test sharding)Needs external config (e.g., Selenium Grid, TestNG parallel)
Ease of SetupEasy, single binary for all supported browsersComplex, needs drivers for each browser
CI/CD IntegrationGood support (GitHub Actions, Jenkins, etc.)Excellent support and maturity



Final Take:

Use Playwright for modern, high-speed automation with features like auto-wait, parallel testing, and browser context isolation.

Use Selenium for broad browser compatibility (example: legacy IE), or if you already have a mature Selenium-based infrastructure.


Suggested Posts:

1. First Script in Playwright
2. Automate GET API in Playwright
3. Comma Selectors in Playwright
4. Handle Alerts in Playwright
5. Find Web Elements by XPath in Playwright

Integration of Playwright, Cucumber, and TestNG

 



Integrating CucumberPlaywright, and TestNG in Java enables you to write BDD (Behavior Driven Development) style tests using Gherkin (.feature files), automate browser interactions using Playwright, and manage execution using TestNG.


Role of Each Component

Playwright:

A powerful automation framework that interacts with modern browsers (Chromium, Firefox, WebKit). It is mainly responsible for performing browser-based actions like navigating pages, clicking elements, validating results, handling alerts, and more. It provides the engine for execution of test steps.

Cucumber:

A BDD (Behavior-Driven Development) framework that allows writing test scenarios in Gherkin language (Given-When-Then format). Its purpose is to make test cases readable and understandable for both technical and non-technical stakeholders. It provides the structure for test scenarios and bridges the gap between business requirements and automated test scripts.

TestNG:

A test management and execution framework in Java. It provides advanced features like test configuration, grouping, parallel execution, annotations, data-driven testing, and detailed reporting. It manages how and when tests are executed, integrates with build tools (Maven/Gradle), and generates structured results.


How Integration Works

Step 1: Cucumber defines test scenarios

Business or QA teams write scenarios in Gherkin. Example:

  • Given user launches the browser
  • When user logs in with valid credentials
  • Then homepage should be displayed

Step 2: Step Definitions in Java call Playwright

Each step in the feature file is mapped to a step definition (Java method). Inside these step definitions, Playwright APIs are used to perform browser actions like opening a page, entering data, or verifying results.

Step 3: TestNG executes scenarios

TestNG acts as the test runner. It executes Cucumber feature files (via Cucumber runner classes) and manages the lifecycle of the tests. TestNG annotations help configure test execution order, parallel runs, retries, or grouping of test suites.

Step 4: Unified Reporting and Logs

TestNG generates test execution reports (HTML/XML), while Cucumber generates BDD reports. These can also be integrated into advanced reporting dashboards like Allure or Extent Reports. This way, both the technical (developer/QA) and business teams can consume the results in formats they understand.


Benefits of Integration

Readable Scenarios: Cucumber ensures tests are described in plain English, improving collaboration.

Powerful Browser Automation: Playwright provides modern, fast, and cross-browser execution.

Robust Test Management: TestNG handles execution strategies (parallelism, suites, groups).

Scalability: The combination is suited for enterprise-level projects where test readability, execution speed, and configurability are crucial.

Flexible Reporting: Both business-friendly BDD reports and developer-focused TestNG reports are available.



Tools Used:

  • Cucumber for BDD feature files and step definitions

  • Playwright for Java for browser automation

  • TestNG for test execution and reporting

  • Maven for dependency management


Website to be automated: https://example.com










Below are the steps showing integration of Cucumber, Playwright and TestNG



pom.xml:

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>cucumber-playwright-testng</artifactId>
  <version>1.0</version>

  <dependencies>
    <!-- Cucumber Dependencies -->
    <dependency>
      <groupId>io.cucumber</groupId>
      <artifactId>cucumber-java</artifactId>
      <version>7.14.0</version>
    </dependency>
    <dependency>
      <groupId>io.cucumber</groupId>
      <artifactId>cucumber-testng</artifactId>
      <version>7.14.0</version>
    </dependency>

    <!-- TestNG -->
    <dependency>
      <groupId>org.testng</groupId>
      <artifactId>testng</artifactId>
      <version>7.9.0</version>
      <scope>test</scope>
    </dependency>

    <!-- Playwright Java -->
    <dependency>
      <groupId>com.microsoft.playwright</groupId>
      <artifactId>playwright</artifactId>
      <version>1.44.0</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <!-- Surefire for TestNG -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>3.2.5</version>
        <configuration>
          <suiteXmlFiles>
            <suiteXmlFile>testng.xml</suiteXmlFile>
          </suiteXmlFiles>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

Title.feature (Gherkin feature file)

Below is the feature file having feature as 'Check title' and Scenario as 'Open login page and check title'. Steps in feature file are implemented by gherkins keywords and expected title of page is 'Example Domain'

Feature: Check title

  Scenario: Open login page and check title
    Given I launch the application
    Then I should see the page title as "Example Domain"


PlaywrightFactory.java

PlaywrightFactory is a utility class which consists of Playwright, Browser and Page objects, it also contain init() to initialize browser and close() to close browser and Playwright object.


package utils;

import com.microsoft.playwright.*;

public class PlaywrightFactory {
    public static Playwright playwright;
    public static Browser browser;
    public static Page page;

    public static void init() {
        playwright = Playwright.create();
        browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(false));
        page = browser.newPage();
    }

    public static void close() {
        browser.close();
        playwright.close();
    }
}


LoginSteps.java

LoginSteps is a step definition class, which is implimentation of Title.feature file. In this, all feature file steps are implemented by annotations like @Given, @Then, etc. which are gherkin keywords of respective steps in feature file. @Before and @After is used for initialization and tear down work respectively.


package steps;

import com.microsoft.playwright.Page;
import io.cucumber.java.After;
import io.cucumber.java.Before;
import io.cucumber.java.en.*;
import utils.PlaywrightFactory;

import static org.testng.Assert.assertEquals;

public class LoginSteps {
    Page page;

    @Before
    public void setup() {
        PlaywrightFactory.init();
        page = PlaywrightFactory.page;
    }

    @Given("I launch the application")
    public void i_launch_the_application() {
        page.navigate("https://example.com");
    }

    @Then("I should see the page title as {string}")
    public void i_should_see_the_page_title_as(String expectedTitle) {
        String actualTitle = page.title();
        assertEquals(actualTitle, expectedTitle);
    }

    @After
    public void tearDown() {
        PlaywrightFactory.close();
    }
}


TestRunner.java (Cucumber TestNG runner)

TestRunner class is used to execute tests written in feature files and implemented in step definition files. Here path of feature file is given by 'features' keyword and path of step definition by 'glue' keyword. All these things are implemented under @CucumberOptions annotation. This TestRunner class is implemented by Cucumber and TestNG.


package runners;

import io.cucumber.testng.AbstractTestNGCucumberTests;
import io.cucumber.testng.CucumberOptions;
import org.testng.annotations.DataProvider;

@CucumberOptions(
    features = "src/test/resources/features",
    glue = "steps",
    plugin = {"pretty", "html:target/cucumber-reports.html"},
    monochrome = true
)
public class TestRunner extends AbstractTestNGCucumberTests {
    @Override
    @DataProvider(parallel = true)
    public Object[][] scenarios() {
        return super.scenarios();
    }
}


testng.xml

TestNG.xml is optional file which contains TestRunner class path represented in class tag. We can execute TestRunner class by TestNG.xml also.

<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Cucumber Playwright TestNG Suite">
  <test name="Cucumber Tests">
    <classes>
      <class name="runners.TestRunner"/>
    </classes>
  </test>
</suite>


Suggested Posts:

1. Playwright with TestNG Integration
2. Automate Login Page in Playwright
3. Comma Selectors in Playwright
4. Handle Alerts in Playwright
5. How to Show Visible Elements in Playwright

Thread Local in Playwright




What is Thread Local?

  • ThreadLocal is a Java utility class that provides thread-local variables.
  • Each thread accessing a ThreadLocal variable has its own, independent copy of the variable.
  • Changes made to a ThreadLocal variable in one thread do not affect the value of the same variable in another thread.
  • This is particularly useful when working in multi-threaded environments, such as parallel test execution, where shared resources may lead to race conditions or inconsistent results.

Why Thread Local in Playwright Java?
  • Playwright allows parallel execution of tests across multiple threads (browsers, contexts, or pages).
  • If all threads share the same Playwright objects (like BrowserContext or Page), one test could unintentionally interfere with another.
  • To avoid this, we use ThreadLocal storage so that: Each thread maintains its own Browser, Context, and Page. No data leakage or object collision happens across test executions.

How to Handle Thread Local in Playwright Java

Define ThreadLocal Variables
  • For objects like Playwright, Browser, BrowserContext, and Page, you create ThreadLocal instances.
  • This ensures each thread holds its own version of these objects.

Initialize Per Thread
  • When a test thread starts, it initializes its own Playwright, Browser, Context, and Page inside its ThreadLocal storage.
  • Other threads will do the same, but with their own isolated objects.

Accessing Thread-Safe Objects
  • During test execution, instead of directly accessing shared variables, you get the instance from the ThreadLocal.
  • This guarantees that the actions being performed belong only to that thread’s browser/page.

Cleaning Up
  • Once the test finishes, you remove the objects from ThreadLocal storage.
  • This prevents memory leaks and ensures resources are freed.


In Playwright Java, ThreadLocal is often used in test automation frameworks (like TestNG or JUnit) to ensure thread safety when running tests in parallel. ThreadLocal allows each thread to maintain its own isolated instance of a variable — like the Playwright BrowserPage, or BrowserContext.














Use Case:

When you run tests in parallel, sharing a single instance of Browser or Page across threads can cause data corruption or flaky tests. ThreadLocal ensures each test thread uses its own BrowserContext, and Page.


Example: Thread-safe Playwright with ThreadLocal in Java

Website to be automated for showing ThreadLocal concept:
https://www.google.com









PlaywrightFactory.java


Below is the PlaywrightFactory class which consists of Threadlocal class objects of type Playwright, Browser, BrowserContext, and Page classes. It also consists of getter and setter methods of these objects. In the last objects are closed by close() and removed by remove()

import com.microsoft.playwright.*;

public class PlaywrightFactory {
    private static ThreadLocal<Playwright> tlPlaywright = new ThreadLocal<>();
    private static ThreadLocal<Browser> tlBrowser = new ThreadLocal<>();
    private static ThreadLocal<BrowserContext> tlContext = new ThreadLocal<>();
    private static ThreadLocal<Page> tlPage = new ThreadLocal<>();

    public static void initPlaywright() {
        tlPlaywright.set(Playwright.create());
    }

    public static void initBrowser() {
        BrowserType.LaunchOptions options = new BrowserType.LaunchOptions().setHeadless(false);
        tlBrowser.set(getPlaywright().chromium().launch(options));
    }

    public static void initContext() {
        tlContext.set(getBrowser().newContext());
    }

    public static void initPage() {
        tlPage.set(getContext().newPage());
    }

    public static Playwright getPlaywright() {
        return tlPlaywright.get();
    }

    public static Browser getBrowser() {
        return tlBrowser.get();
    }

    public static BrowserContext getContext() {
        return tlContext.get();
    }

    public static Page getPage() {
        return tlPage.get();
    }

    public static void closeAll() {
        getPage().close();
        getContext().close();
        getBrowser().close();
        getPlaywright().close();

        // Remove from ThreadLocal
        tlPage.remove();
        tlContext.remove();
        tlBrowser.remove();
        tlPlaywright.remove();
    }
}



SampleTest.java

In below code, There is a TestNG class which has @BeoreMethod, @Test, @AfterMethod annotations.

@BeforeMethod initialises Playwright, Browser, BrowserContext and Page classes by methods mentioned in PlaywrightFactory class.

@Test will create Page class object and call webpage google.com and print the title

@AfterMethod will close all objects by closell() mentioned in PlaywrightFactory class


import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import com.microsoft.playwright.*;

public class SampleTest {

    @BeforeMethod
    public void setUp() {
        PlaywrightFactory.initPlaywright();
        PlaywrightFactory.initBrowser();
        PlaywrightFactory.initContext();
        PlaywrightFactory.initPage();
    }

    @Test
    public void testGoogleSearch() {
        Page page = PlaywrightFactory.getPage();
        page.navigate("https://www.google.com");
        System.out.println("Page Title: " + page.title());
    }

    @AfterMethod
    public void tearDown() {
        PlaywrightFactory.closeAll();
    }
}

Parallel Execution

To run parallel tests safely:

  • Use TestNG with <parallel="methods"> or <parallel="classes">

  • Each test thread will get its own isolated Playwright Page due to ThreadLocal


Suggested Posts:

1. Playwright with TestNG Integration
2. Automate Login Page in Playwright
3. Comma Selectors in Playwright
4. Trace Viewer in Playwright
5. Handle GET API in Playwright