Home > Blog > Playwright: Java vs TypeScript
Author: Tomotaka ASAGI
Published: Jan 11, 2026
I Tried Playwright in Java First—Here's Why TypeScript Changed Everything
Introduction
When I first decided to try Playwright, I quickly put together a simple project in Java. My initial impression was: "I see, this could replace Selenium, no WebDriver needed, and it might be easier to write automated tests."
Having spent over 10 years with Selenium and Java, it felt natural to just swap out the test engine without changing the language.
I had already implemented VRT-like functionality using OpenCV ten years ago. My ecosystem was complete—JUnit for test execution, Gradle for builds, Allure for reports. "I just need to replace the test engine," I thought.
The result? I concluded that "Playwright isn't that different from Selenium."
...But this was a big misconception.
For actual client projects, I've been building with TypeScript. As I started using more Playwright-specific features, I realized: they're completely different.
The Difference Between Playwright and Playwright Test
At first, I didn't understand this at all. I assumed that even when using Playwright with TypeScript, I would need a separate test runner like Jest—similar to how Java requires JUnit.
Playwright ≠ Playwright Test
Name | Description | Supported Languages |
Playwright | Browser automation library | TypeScript, JavaScript, Java, Python, C# |
Playwright Test | Test framework | TypeScript, JavaScript only |
Java's Playwright is a "browser automation library." It's positioned as a replacement for Selenium.
The TypeScript version, however, comes with "Playwright Test"—a full test framework. This is what makes Playwright truly valuable and creates the decisive difference from Selenium.
Selenium + Java Stack vs Playwright Test
The following is a stack I've frequently used and have built for many clients over the years.
Feature | Selenium + Java Stack | Components |
Browser automation | Selenium WebDriver | selenium-java |
Test execution | JUnit / TestNG | junit-jupiter, etc. |
Build | Gradle / Maven | build.gradle / pom.xml |
Reports | Allure, etc. | allure-junit5, etc. |
Parallel execution | Gradle / JUnit config | Configuration files |
Layout verification | OpenCV implementation, etc. | opencv-java, etc. |
Note: Back then, I didn't use the term "VRT." In Japanese, we called it "layout breakage detection" (画面崩れ検知), but the concept is essentially the same as Visual Regression Testing.
With Playwright Test:
Feature | Playwright Test | Required Work |
Browser automation | Playwright | Built-in |
Test execution | Playwright Test | Built-in |
Build | Not needed | - |
Reports | HTML Reporter | One line config |
Parallel execution | --workers option | Just an option flag |
VRT | toHaveScreenshot() | One line |
With the Selenium + Java stack, you combine various tools to build your environment. Playwright Test, on the other hand, has these features integrated from the start.
Additionally, Java environments require decisions like "which JDK to use" and version management. Playwright Test (TypeScript) setup is complete with just npm init playwright@latest.
What Java Version Cannot Do
The following features are not available in Java Playwright:
Feature | TypeScript | Java | Description |
Playwright Test | ✅ | ❌ | The test framework itself |
toHaveScreenshot() | ✅ | ❌ | Visual Regression Testing |
toMatchSnapshot() | ✅ | ❌ | Snapshot testing |
Fixtures | ✅ | ❌ | Test setup & sharing |
Sharding | ✅ | ❌ | Distributed test execution |
HTML Reporter | ✅ | ❌ | Standard reporting |
UI Mode | ✅ | ❌ | Interactive test execution |
Component Testing | ✅ | ❌ | Component unit testing |
Test Generator integration | ✅ Full | △ | Code generation only |
VRT Example
TypeScript (Playwright Test):
await expect(page).toHaveScreenshot('homepage.png');
This alone completes VRT. It automatically fails on differences and generates diff images. Baseline image management is handled out of the box.
Java version:
To achieve VRT, separate implementation is required.
// Take a screenshot
byte[] screenshot = page.screenshot();
// Save to file
Files.write(Paths.get("screenshot.png"), screenshot);
// Comparison logic requires separate implementation
// - Load baseline image
// - Pixel comparison (OpenCV, etc.)
// - Generate diff image
// - Set thresholds
// - Error handling
When I was using Selenium, I would incorporate layout verification when there was a specific request for it. However, as I mentioned in Part 1, there were no new Selenium projects in 2025.
As more projects use Playwright for test automation, awareness of toHaveScreenshot() has grown, and requests for VRT-enabled tests have increased. Being available as a standard feature has expanded its adoption.
Tips for Java Developers Moving to TypeScript
1. async/await
Java didn't have async/await (until Java 21's Virtual Threads). In TypeScript, it's essential.
// TypeScript - asynchronous processing
const title = await page.title(); // await required
await page.click('button'); // await required
// Java - appears synchronous
String title = page.title(); // no await
page.click("button"); // no await
Java's Playwright wraps things synchronously internally, so Java developers don't think about async. In TypeScript, be careful not to forget await.
2. Test Structure
JUnit (Java):
public class LoginTest {
@BeforeEach
void setUp() { ... }
@Test
void testLogin() { ... }
@AfterEach
void tearDown() { ... }
}
Playwright Test (TypeScript):
import { test, expect } from '@playwright/test';
test.beforeEach(async ({ page }) => { ... });
test('login test', async ({ page }) => { ... });
test.afterEach(async ({ page }) => { ... });
JUnit is class-based, while Playwright Test is function-based.
3. Type System
Both Java and TypeScript are statically typed, but TypeScript has Union types and optional properties.
// TypeScript - Union types
type Status = 'pending' | 'approved' | 'rejected';
// TypeScript - Optional properties
interface User {
name: string;
email?: string; // optional
}
When to Choose Java
When choosing a language, the following two points are particularly important criteria.
1. Integration with Existing Java Test Assets
If you already have a large-scale Java test suite and want to incorporate Playwright into it, rewriting everything in TypeScript isn't realistic. A phased migration approach that leverages existing assets is effective.
2. Team Skillset
In my "Test Automation Circles" framework, team skillset is highlighted as an important factor in the Base layer.
Forcing TypeScript on engineers who only have Java experience can create a significant burden. This can become a factor in test automation efforts not being sustained.
This becomes a trade-off between using a familiar language and the features available.
If you want to fully leverage Playwright's features, TypeScript is the better choice. However, it's important to make the optimal choice for your project after considering the criteria above.
Conclusion
There are clear differences in available features between using Playwright with Java versus TypeScript.
- Playwright (Java) = Browser automation library ≒ Selenium replacement
- Playwright Test (TypeScript) = Test automation platform
The Java version functions as a "library for browser automation," similar to Selenium. The TypeScript version's Playwright Test, on the other hand, is a test framework with VRT, reporting, parallel execution, and other features integrated as standard.
When adopting Playwright for a new project, I recommend understanding these differences before choosing your language.
Next time, I'll compare BDD frameworks for using Playwright with TypeScript: Cucumber.js vs Playwright-bdd.
This article is Part 2 of the Playwright series.
- Part 1: From Selenium to Playwright
- Part 2: TypeScript vs Java - Feature Differences by Language (this article)
- Part 3: BDD Framework Comparison - Cucumber.js vs Playwright-bdd