Docs

Documentation versions (currently viewingVaadin 25.2 (pre-release))

This page covers the Playwright-specific aspects of load testing. For general load testing concepts, running tests, configuring think times, understanding k6 output, and more, see Load Testing.

Overview

Unlike the TestBench path, which requires a BrowserMob Proxy to capture HTTP traffic, the Playwright path uses native HAR recording built into the browser. This results in simpler setup, fewer moving parts, and no proxy configuration.

The workflow is as follows:

  1. Write standard Playwright integration tests that simulate real user scenarios

  2. Record HTTP traffic automatically via Playwright’s native HAR capture

  3. Convert the captured HAR into Vaadin-aware k6 scripts

  4. Run the generated k6 scripts at scale against any target server

All steps after writing the tests are fully automated by the Maven plugin.

Playwright vs TestBench

Aspect Playwright TestBench

Recording method

Native HAR recording (built-in)

BrowserMob Proxy (MITM)

Proxy required

No

Yes

Element selection

page.getByLabel(), page.getByRole()

$(ElementClass).first()

Setup complexity

Minimal

Requires BrowserMob Proxy configuration and certificate handling

Maven goal

loadtest:record-playwright

loadtest:record

Prerequisites

The Playwright path requires the same base tools as the TestBench path (Java 21+, Maven 3.9+, k6), but does not require Chrome or ChromeDriver. Playwright downloads and manages its own browser binaries automatically.

Writing Playwright Tests

Playwright tests for load testing are standard JUnit 5 integration tests. The only requirement is using PlaywrightHelper.createBrowserContext(browser) to create the browser context — this enables transparent HAR recording when the test is run by the Maven plugin.

Test Structure

Source code
Java
import com.microsoft.playwright.*;
import com.vaadin.testbench.loadtest.PlaywrightHelper;
import org.junit.jupiter.api.*;

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

public class MyScenarioPlaywrightIT {

    private Playwright playwright;
    private Browser browser;
    private BrowserContext context;
    private Page page;

    @BeforeEach
    public void setUp() {
        playwright = Playwright.create();
        browser = playwright.chromium()
                .launch(new BrowserType.LaunchOptions().setHeadless(true));
        context = PlaywrightHelper.createBrowserContext(browser);  1
        page = context.newPage();
        page.navigate(PlaywrightHelper.getBaseUrl() + "/my-view");  2
    }

    @AfterEach
    public void tearDown() {
        if (context != null) context.close();
        if (browser != null) browser.close();
        if (playwright != null) playwright.close();
    }

    @Test
    public void myUserScenario() {
        // Simulate user actions
        page.getByLabel("Name").fill("Test User");
        page.getByRole(AriaRole.BUTTON,
                new Page.GetByRoleOptions().setName("Submit")).click();

        // Verify expected outcome
        assertThat(page.locator("vaadin-notification-card"))
                .containsText("Success");
    }
}
  1. PlaywrightHelper.createBrowserContext() enables HAR recording when the k6.harOutputPath system property is set by the Maven plugin. When running tests normally (e.g., during development), it creates a plain browser context with no recording overhead.

  2. PlaywrightHelper.getBaseUrl() resolves the deployment URL from the HOSTNAME environment variable and server.port system property, defaulting to http://localhost:8080.

Example: Hello World Scenario

A simple workflow that enters a name and clicks a button:

Source code
Java
@Test
public void helloWorldWorkflow() {
    page.getByLabel("Your name").fill("Vaadin User");

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

    assertThat(page.locator("vaadin-notification-card"))
            .containsText("Hello Vaadin User");
}

Example: CRUD Scenario

A more complex workflow that interacts with a grid, creates a record, and deletes it:

Source code
Java
@Test
public void crudWorkflow() {
    Locator grid = page.locator("vaadin-grid");
    grid.waitFor();

    // Select a random row in the grid
    int rowCount = (int) grid
            .evaluate("g => g._dataProviderController.rootCache.size");
    int randomRow = new Random().nextInt(Math.min(rowCount, 5));
    grid.evaluate(
            "(g, idx) => {"
                    + "  g.scrollToIndex(idx);"
                    + "  g.activeItem = g._dataProviderController"
                    + "    .rootCache.items[idx];"
                    + "}",
            randomRow);

    // Fill form and save
    page.locator("#cancel-button").click();
    form.getByLabel("First Name").fill("TestName");
    form.getByLabel("Email").fill("test@example.com");
    page.locator("#save-button").click();

    // Delete the created record
    grid.locator("vaadin-grid-cell-content").getByText("TestName").click();
    page.locator("#delete-button").click();
}

Best Practices for Test Scenarios

  • Use semantic locators — prefer getByLabel(), getByRole(), and getByText() over CSS selectors. They are more resilient to UI changes and produce more readable tests.

  • One scenario per test class — each test class maps to one k6 script. Keep scenarios focused on a single user journey.

  • Include assertions — assertions verify correctness during recording and serve as documentation. They don’t affect the generated k6 script.

  • Avoid destructive-only tests — if a test only deletes data, mark it with @Destructive so it can be skipped during recording runs. Prefer tests that create-then-delete.

  • Keep headless mode configurable — use setHeadless(true) for CI/recording and setHeadless(false) for debugging.

Project Setup

Application Module Dependencies

Add the testbench-loadtest-support and Playwright dependencies to your Vaadin application module:

Source code
XML
<dependency>
    <groupId>com.vaadin</groupId>
    <artifactId>testbench-loadtest-support</artifactId>
    <version>${vaadin.testbench.version}</version>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>com.microsoft.playwright</groupId>
    <artifactId>playwright</artifactId>
    <version>1.58.0</version>
    <scope>test</scope>
</dependency>

Load Test Orchestration Module

Create a separate Maven module (packaging pom) that orchestrates the recording and load test execution. This module depends on your application module and configures the testbench-converter-plugin.

The key difference from the TestBench orchestration module is using the record-playwright goal instead of the record goal.

Source code
Minimal pom.xml
<project>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>my-app-loadtest</artifactId>
    <packaging>pom</packaging>

    <properties>
        <app.port>8081</app.port>
        <management.port>8082</management.port>
        <k6.vus>100</k6.vus>
        <k6.duration>30s</k6.duration>
        <k6.testDir>${project.build.directory}/k6/tests</k6.testDir>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.example</groupId>
            <artifactId>my-app</artifactId>
            <version>${project.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <!-- Copy the application JAR -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy-app</id>
                        <phase>package</phase>
                        <goals><goal>copy</goal></goals>
                        <configuration>
                            <artifactItems>
                                <artifactItem>
                                    <groupId>com.example</groupId>
                                    <artifactId>my-app</artifactId>
                                    <type>jar</type>
                                    <destFileName>my-app.jar</destFileName>
                                </artifactItem>
                            </artifactItems>
                            <outputDirectory>${project.build.directory}</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

            <!-- Load test plugin -->
            <plugin>
                <groupId>com.vaadin</groupId>
                <artifactId>testbench-converter-plugin</artifactId>
                <version>${vaadin.testbench.version}</version>
                <executions>
                    <!-- 1. Start the application -->
                    <execution>
                        <id>start-server</id>
                        <goals><goal>start-server</goal></goals>
                        <configuration>
                            <serverJar>${project.build.directory}/my-app.jar</serverJar>
                            <serverPort>${app.port}</serverPort>
                            <managementPort>${management.port}</managementPort>
                        </configuration>
                    </execution>

                    <!-- 2. Record Playwright scenarios -->
                    <execution>
                        <id>record</id>
                        <phase>integration-test</phase>
                        <goals><goal>record-playwright</goal></goals>
                        <configuration>
                            <testClasses>
                                <testClass>MyScenarioPlaywrightIT</testClass>
                            </testClasses>
                            <appPort>${app.port}</appPort>
                            <testWorkDir>${project.basedir}/../my-app</testWorkDir>
                            <harDir>${project.build.directory}</harDir>
                            <outputDir>${k6.testDir}</outputDir>
                        </configuration>
                    </execution>

                    <!-- 3. Run k6 load tests -->
                    <execution>
                        <id>run</id>
                        <phase>integration-test</phase>
                        <goals><goal>run</goal></goals>
                        <configuration>
                            <testDir>${k6.testDir}</testDir>
                            <virtualUsers>${k6.vus}</virtualUsers>
                            <duration>${k6.duration}</duration>
                            <appPort>${app.port}</appPort>
                            <managementPort>${management.port}</managementPort>
                        </configuration>
                    </execution>

                    <!-- 4. Stop the application -->
                    <execution>
                        <id>stop-server</id>
                        <goals><goal>stop-server</goal></goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

PlaywrightHelper API

The PlaywrightHelper class in testbench-loadtest-support provides two static methods:

createBrowserContext(Browser browser)

Creates a Playwright BrowserContext. When the k6.harOutputPath system property is set (automatically by the loadtest:record-playwright goal), HAR recording is enabled in FULL mode. Otherwise, a plain context is created.

Source code
Java
BrowserContext context = PlaywrightHelper.createBrowserContext(browser);

getBaseUrl()

Returns the base URL of the application under test. Resolution order:

  1. HOSTNAME environment variable (if set) for the host, otherwise localhost

  2. server.port system property (if set) for the port, otherwise 8080

Source code
Java
String baseUrl = PlaywrightHelper.getBaseUrl(); // e.g., "http://localhost:8080"
page.navigate(baseUrl + "/my-view");

loadtest:record-playwright Goal

Records Playwright tests and converts captured HAR files to k6 scripts.

Parameter Type Default Description

testClasses

List<String>

required

Playwright test class names to record (without package prefix).

appPort

int

8080

Port where the application is running.

testWorkDir

String

required

Working directory of the application module (where mvn commands run for test execution).

harDir

String

target

Directory where HAR files are written.

outputDir

String

target/k6/tests

Directory where generated k6 scripts are placed.

skip

boolean

false

Skip recording.

For parameters related to running the generated k6 scripts (loadtest:run), configuring think times, combined scenarios, and understanding k6 output, see the main Load Testing documentation.

Troubleshooting

Playwright Test Fails During Recording

The test runs inside the application module’s Maven context. Ensure the application module builds successfully with mvn install before running the load test module.

HAR File is Empty or Missing

Verify that your test uses PlaywrightHelper.createBrowserContext(browser) and not browser.newContext() directly. The helper is what enables HAR recording.