Quarkus Playwright

Playwright is an open-source automation library designed for browser testing and web scraping. This extension supports two primary use cases:

  1. Testing: Perform end-to-end tests for your Quarkus web application.

  2. Runtime: Leverage Playwright for screen scraping or other browser tasks in your runtime application, including support for GraalVM native compilation.

Test Usage

The primary use case for Playwright is integration with @QuarkusTest for end-to-end testing of your application. You can easily create effective cross-browser end-to-end tests for your Quarkus web application using Playwright with frameworks such as Qute, Quinoa, Renarde, Web-Bundler, and MyFaces. Playwright Test was specifically designed to meet the requirements of end-to-end testing. It supports all modern rendering engines, including Chromium, WebKit, and Firefox. You can run tests on Windows, Linux, and macOS—either locally or in CI—both in headless and headed modes, with native mobile emulation for Google Chrome on Android and Mobile Safari.

Just add the dependency as <scope>test</scope> to your pom.xml:

<dependency>
    <groupId>io.quarkiverse.playwright</groupId>
    <artifactId>quarkus-playwright</artifactId>
    <version>2.1.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-junit5</artifactId>
    <scope>test</scope>
</dependency>

Write your tests:

@QuarkusTest
@WithPlaywright
public class WithDefaultPlaywrightTest {

    @InjectPlaywright
    BrowserContext context;

    @TestHTTPResource("/")

    URL index;

    @Test
    public void testIndex() {
        final Page page = context.newPage();
        Response response = page.navigate(index.toString());
        Assertions.assertEquals("OK", response.statusText());

        page.waitForLoadState();

        String title = page.title();
        Assertions.assertEquals("My Awesome App", title);

        // Make sure the web app is loaded and hits the backend
        final ElementHandle quinoaEl = page.waitForSelector(".toast-body.received");
        String greeting = quinoaEl.innerText();
        Assertions.assertEquals("Hello from RESTEasy Reactive", greeting);
    }
}

Use the annotation @WithPlaywright() to change the browser (Chromium, Firefox, Webkit), headless, enable debug, logs, and other options.

Debug your tests with the Playwright inspector @WithPlaywright(debug=true).

Custom Test Selectors

Selectors can be used to install custom selector engines. An example of registering selector engine that queries elements based on a tag name:

@QuarkusTest
@WithPlaywright(selectors = {
        @PlaywrightSelector(name = "tag", script = "{\n" +
                "  // Returns the first element matching given selector in the root's subtree.\n" +
                "  query(root, selector) {\n" +
                "    return root.querySelector(selector);\n" +
                "  },\n" +
                "  // Returns all elements matching given selector in the root's subtree.\n" +
                "  queryAll(root, selector) {\n" +
                "    return Array.from(root.querySelectorAll(selector));\n" +
                "  }\n" +
                "}")
})
public class WithSelectorsPlaywrightTest {

    @InjectPlaywright
    BrowserContext context;

    @Test
    public void testIndex() {
        final Page page = context.newPage();
        // add a button to the page
        page.setContent("<div><button>Click me</button></div>");
        // Use the selector prefixed with its name.
        Locator button = page.locator("tag=button");
        // Combine it with built-in locators.
        page.locator("tag=div").getByText("Click me").click();
        // Can use it in any methods supporting selectors.
        int buttonCount = (int) page.locator("tag=button").count();
        Assertions.assertEquals(1, buttonCount);
    }

}

Runtime Usage

Leverage Playwright for screen scraping or other browser tasks in your runtime application, including support for GraalVM native compilation.

Just add the runtime dependency to pom.xml:

<dependency>
    <groupId>io.quarkiverse.playwright</groupId>
    <artifactId>quarkus-playwright</artifactId>
    <version>2.1.1</version>
</dependency>

In runtime mode, Playwright is used directly through its Java SDK without CDI injection. Follow the standard Microsoft Playwright documentation for usage patterns. Below is an example REST service that demonstrates screen scraping:

@Path("/playwright")
@ApplicationScoped
public class PlaywrightResource {

    private static final Logger log = Logger.getLogger(PlaywrightResource.class);

    /**
     * Navigates to Google homepage and retrieves the page title using Playwright.
     *
     * <p>This endpoint demonstrates basic Playwright functionality by:
     * <ul>
     *   <li>Launching a headless Chromium browser</li>
     *   <li>Creating a new page and navigating to google.com</li>
     *   <li>Retrieving and returning the page title</li>
     * </ul>
     * </p>
     *
     * @return The title of the Google homepage
     */
    @GET
    public String google() {
        String pageTitle;
        final BrowserType.LaunchOptions launchOptions = new BrowserType.LaunchOptions()
                .setHeadless(true)
                .setChromiumSandbox(false)
                .setChannel("")
                .setArgs(List.of("--disable-gpu"));
        final Map<String, String> env = new HashMap<>(System.getenv());
        env.put("DEBUG", "pw:api");
        try (Playwright playwright = Playwright.create(new Playwright.CreateOptions().setEnv(env))) {
            try (Browser browser = playwright.chromium().launch(launchOptions)) {
                Page page = browser.newPage();
                page.navigate("https://www.google.com/");
                pageTitle = page.title();
                log.infof("Page title: %s", pageTitle);
            }
        }
        return pageTitle;
    }
}

Native

If you plan on running in a Docker image we highly recommend you use a pre-built image from Microsoft mcr.microsoft.com/playwright:v1.48.1 which is based on Ubuntu and already has all libraries and tools necessary for PlayWright.

FROM mcr.microsoft.com/playwright:v1.48.1-noble
WORKDIR /work/
RUN chown 1001:root /work \
    && chmod g+rwX /work \
    && chown 1001:root /work
COPY --chown=1001:root target/*.properties target/*.so /work/
COPY --chown=1001:root target/*-runner /work/application
# Make application executable for all users
RUN chmod ugo+x /work/application
EXPOSE 8080
USER 1001
CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]

Additional Configuration

There is additional configuration options available on the @BrowserContextConfig and @WithPlaywright annotations:

io.quarkiverse.playwright.BrowserContextConfig
Unresolved include directive in modules/ROOT/pages/index.adoc - include::https://github.com/quarkiverse/quarkus-playwright/blob/main/runtime/src/main/java/io/quarkiverse/playwright/BrowserContextConfig.java[]
io.quarkiverse.playwright.WithPlaywright
Unresolved include directive in modules/ROOT/pages/index.adoc - include::https://github.com/quarkiverse/quarkus-playwright/blob/main/runtime/src/main/java/io/quarkiverse/playwright/WithPlaywright.java[]