Why Playwright Beats Selenium for Modern Web Automation
This article compares Playwright and Selenium, highlighting Playwright's superior language support, driver‑less operation, faster startup, reliable auto‑waiting, stable code generation, asynchronous capabilities, and headless mode, then provides step‑by‑step environment setup, practical usage tips, and code examples for Java‑based UI testing.
Background
The UI automation market is dominated by Selenium due to its ease of use and community support, but it suffers from driver maintenance, unstable IDE recordings, and limited stability.
Playwright vs Selenium Comparison
Supported Languages : Playwright supports JavaScript, TypeScript, Python, C#, Go, Java; Selenium supports Java, Python, Ruby, C#, C++, JavaScript.
Browser Interaction & Performance : Playwright interacts via developer tools, requires no drivers, and launches browsers quickly; Selenium relies on WebDriver, leading to slower starts.
Browser Support : Playwright covers Chromium, WebKit, Firefox (excluding IE11); Selenium runs on most browsers except some domestic variants.
Reliability : Playwright offers automatic waiting and WebSocket communication; Selenium needs explicit waits and uses one‑way HTTP.
Code Generation : Playwright records stable code using CSS, XPath, or text selectors; Selenium IDE generates unstable coordinate‑based code.
Async Support : Playwright supports asynchronous operations; Selenium does not.
Headless Mode : Both support headless execution for CI environments.
Mobile Emulation : Both can emulate mobile browsers but cannot test on real devices.
Playwright Environment Setup
Prerequisites: JDK 8, Git, Maven, TestNG, JUnit.
<dependency>
<groupId>com.microsoft.playwright</groupId>
<artifactId>playwright</artifactId>
<version>1.17.0</version>
</dependency>
<dependency>
<groupId>com.microsoft.playwright</groupId>
<artifactId>assertions</artifactId>
<version>1.17.2</version>
</dependency>Install browsers:
# Install supported browsers
mvn exec:java -e -Dexec.mainClass=com.microsoft.playwright.CLI -Dexec.args="install"
# Show help for special browsers
mvn exec:java -e -Dexec.mainClass=com.microsoft.playwright.CLI -Dexec.args="install --help"
# Install WebKit
mvn exec:java -e -Dexec.mainClass=com.microsoft.playwright.CLI -Dexec.args="install webkit"Record scripts:
# Record with storage state
mvn exec:java -e -Dexec.mainClass=com.microsoft.playwright.CLI -Dexec.args="codegen --load-storage=auth.json https://www.guandata.com"
# Emulate iPhone 11
mvn exec:java -e -Dexec.mainClass=com.microsoft.playwright.CLI -Dexec.args='open --device="iPhone 11" https://www.guandata.com'Practical Operations
Playwright supports headless mode by default (setHeadless(true)).
Element locating can use CSS, XPath, or text selectors, simplifying interactions.
No need to download separate WebDrivers for each browser.
Recording scripts is straightforward and stable.
Example of launching a browser and performing actions:
public class Example {
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(new Browser.NewContextOptions().setStorageStatePath(Paths.get("auth.json")));
Page page = context.newPage();
page.navigate("http://192.168.199.6:8087/auth/index");
// login steps omitted for brevity
}
}
}Switching browsers and headless settings:
// Launch Firefox
Browser browser = playwright.firefox().launch();
// Launch Chromium in headless mode
Browser browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(true));Encapsulating common setup in a base class reduces duplication:
public class UiAbstract {
public static Page page;
public static BrowserContext context;
@BeforeSuite
public void setUp() {
Playwright playwright = Playwright.create();
Browser browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(Env.HEADLESS));
Browser.NewContextOptions opts = new Browser.NewContextOptions();
opts.setViewportSize(1280, 720);
opts.setBaseURL(Env.TESTSERVER);
context = browser.newContext(opts);
}
}Screenshot Comparison Assertions
To reduce manual text assertions, a pixel‑level image diff is implemented. The workflow captures screenshots, uploads them to a Samba server, compares them with baseline images, highlights differences, and generates a report.
Core diff code:
public class ImageDiff {
public static double getDifferencePercent(String actual, String baseline, String diffOut, int threshold, double tolerance) throws IOException {
InputStream actualInput = new FileInputStream(actual);
InputStream baseInput = new FileInputStream(baseline);
BufferedImage img1 = ImageIO.read(actualInput);
BufferedImage img2 = ImageIO.read(baseInput);
int width = img1.getWidth();
int height = img1.getHeight();
long diffCount = 0;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int i = pixelYIQDiff(img1.getRGB(x, y), img2.getRGB(x, y));
if (i > threshold) {
diffCount++;
img1.setRGB(x, y, 0xffff0000);
} else {
img1.setRGB(x, y, greyPixel(img1.getRGB(x, y)));
}
}
}
double diffPct = 100.0 * diffCount / (width * height);
if (diffPct > tolerance) {
ImageIO.write(img1, "png", new File(diffOut));
}
return diffPct;
}
// pixelYIQDiff, rgb2y/i/q, greyPixel implementations omitted for brevity
}Code Demo
A full test case demonstrates permission checks across subscription plans, using Playwright for navigation, element interaction, screenshot capture, and image‑diff assertions.
/**
* @description: Test subscription permission effects
* @date: 2021-12-29 18:33
*/
public class SubscriptionReadTest extends UiAbstract {
String description = "订阅-查看";
@BeforeTest
public void beforeTest() { page = context.newPage(); }
@Test(dataProvider = "datapro")
public void subscriptionReadTest(String role, String loginId) {
page.navigate("/auth/index");
// login steps omitted
page.click(":nth-match(i, 2)");
// capture and assert screenshots for various subscription views
ScreenshotUtil.screenshotBySelector(page, "div._1HjXw1zf", description + "-" + role + "卡片订阅");
// other steps omitted for brevity
ScreenshotUtil.ScreenshotAssert(description + "-" + role + "卡片订阅");
}
@DataProvider
public Object[][] datapro() {
return new Object[][]{{"普通用户", "[email protected]"}, {"只读用户", "[email protected]"}};
}
@AfterTest
public void after() { page.close(); }
}For more details, refer to the official Playwright Java documentation and GitHub repository.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
