From Puppeteer to Playwright: Is This Migration Worthwhile?
Hey there, folks! Are you struggling with the decision of switching from Puppeteer to Playwright? How easy or difficult is this transition? And is it really worth it? What unexpected changes will there be at the coding level? What new and interesting features does Playwright hide? Don't worry. This article will talk about these interesting things.
A Big Reveal of the Current Situation of Puppeteer and Playwright
At first glance, these two tools have many similarities. But in the past two years, their development speeds have been like two sports cars with different horsepower, gradually pulling apart. Playwright is developing so vigorously that it has outshined Puppeteer. This strong momentum has led many people to switch to Playwright. This article will explain in detail how to migrate and what cool new features this change can bring us. Although the article is a bit long, the content is super simple and easy to learn!
Why Migrate?
We've previously conducted comparative tests of Cypress, Selenium, Playwright, and Puppeteer (for details, click on the article link). To summarize briefly, the reasons are as follows:
- Playwright is updated very frequently and has many more new features than Puppeteer!
- In real - world end - to - end (E2E) tests, Playwright has excellent performance and executes test cases at an extremely fast speed (check the article link for details)!
- Playwright is more stable, like a reliable partner.
- On communities such as GitHub, Twitter, and Slack, Playwright is quite popular, while the Puppeteer community seems a bit deserted.
A Comparison of Change Lists
Let's first take a look at a comparison table. Spend a few minutes glancing at it, and then we'll study it in depth later.
Puppeteer | Playwright |
---|---|
puppeteer.launch(...) | playwright.chromium.launch(...) |
browser.createIncognitoBrowserContext(...) | browser.newContext(...) |
page.setViewport(...) | page.setViewportSize(...) |
page.waitForSelector(selector) page.click(selector); |
page.click(selector) |
page.waitForXPath(XPathSelector) | page.waitForSelector(XPathSelector) |
page.$x(xpath_selector) | page.$(xpath_selector) |
page.waitForNetworkIdle(...) | page.waitForLoadState({ state: 'networkidle' }) |
page.waitForFileChooser(...) | Removed, handled differently. |
page.waitFor(timeout) | page.waitForTimeout(timeout) |
page.type(selector, text) | page.fill(selector, text) |
page.cookies([...urls]) | browserContext.cookies([urls]) |
page.deleteCookie(...cookies) | browserContext.clearCookies() |
page.setCookie(...cookies) | browserContext.addCookies(cookies) |
page.on('request',...) | Handled through page.route |
elementHandle.uploadFile(...) | elementHandle.setInputFiles(...) |
Tricky file download. | Better support for downloads. |
A Big Reveal of Change Details
Package Import
In Puppeteer, the beginning of a script might look like this:
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
//...
In Playwright, it's like this:
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
//...
Playwright is very considerate and comes with cross - browser support. You can freely choose the browser to run, like const { webkit } = require('playwright');
. In Puppeteer, this needs to be achieved through the configuration of the launch interface, for example:
const browser = await puppeteer.launch({ product: 'firefox' })
Browser Context
In Puppeteer, the browser context is used like this:
const browser = await puppeteer.launch();
const context = await browser.createIncognitoBrowserContext();
const page = await context.newPage();
In Playwright, the context is even more important and the usage is a bit different:
const browser = await chromium.launch();
const context = await browser.newContext();
const page = await context.newPage();
Just like in Puppeteer, if it's for basic use or a single - page flow, the default context can be used:
const browser = await chromium.launch();
const page = await browser.newPage();
Wait
Playwright has a powerful auto - waiting mechanism, which means you may not need to wait manually all the time. However, waiting is one of the most troublesome parts in UI automation, and you still need to know how to make the script wait obediently for one or more conditions to be met. In this regard, Playwright has brought these changes:
-
page.waitForNavigation
andpage.waitForSelector
are still there, but with the auto - waiting mechanism, they are not always necessary in many cases. -
page.waitForEvent
is added. - Puppeteer's
page.waitForXPath
is integrated intopage.waitForSelector
, and it can automatically recognize XPath expressions. -
page.waitForFileChooser
is removed. For the new usage, see Upload files, E2E Account Settings. -
page.waitForNetworkIdle
is integrated intopage.waitForLoadState
. -
page.waitForUrl
is added, which can wait for a URL to be loaded by the main frame of the page. -
page.waitFor(timeout)
becomespage.waitForTimeout(timeout)
. Note thatpage.waitForTimeout
should not be used in a formal product. This hard waiting is only suitable for testing.
Setting the Viewport
Puppeteer's page.setViewport
becomes page.setViewportSize
in Playwright.
Typing
Puppeteer's page.type
can still be used. If you want to control fine - grained keyboard events, it's still a good helper. Besides, Playwright has added page.fill
, which is very convenient for filling and clearing forms.
Cookies
When using Puppeteer, cookies are handled at the page level; in Playwright, you can manipulate them at the BrowserContext level.
Before:
page.cookies([...urls])
page.deleteCookie(...cookies)
page.setCookie(...cookies)
Now:
browserContext.cookies([urls])
browserContext.clearCookies()
browserContext.addCookies(cookies)
Note that there are some small differences between these methods, so be careful when passing cookies.
XPath Selectors
Playwright can automatically recognize XPath selectors starting with //
or ..
, while in Puppeteer, there is a separate interface.
Device Emulation
Playwright's device emulation can be done at the browser context level, like this:
const pixel2 = devices['Pixel 2'];
const context = await browser.newContext({
...pixel2,
});
And it can also control permissions, location, and other device parameters. Cool, right?
File Download
Downloading files in headless mode is quite troublesome in Puppeteer, but it's much simpler in Playwright:
const [download] = await Promise.all([
page.waitForEvent('download'),
page.click('#orders > ul > li:nth-child(1) > a')
])
const path = await download.path();
This is a complete example.
File Upload
Puppeteer's elementHandle.uploadFile
becomes elementHandle.setInputFiles
. See the file upload example for details.
Request Interception
In Puppeteer, request interception is done like this:
await page.setRequestInterception(true)
page.on('request', (request) => {
if (request.resourceType() === 'image') request.abort()
else request.continue()
})
In Playwright, you can intercept URLs of a specified pattern through page.route
:
await page.route('**/*', (route) => {
return route.request().resourceType() === 'image'
? route.abort()
: route.continue()
})
See here for a complete example.
New Features Worth Noting
When switching from Puppeteer to Playwright, you need to have a good understanding of Playwright's new features, which might bring new surprises to your testing or monitoring setup!
New Selector Engine
Playwright provides a super flexible way to reference UI elements. Besides css and XPath, there are also these:
- Playwright - specific selectors, such as
:nth - match(:text("Buy"), 3)
. - Text selectors, such as
text=Add to Car
. - Chain selectors, such as
css=preview >> text=In stock
. And you can even create your own custom selector engine. For more information and usage of selectors, see Working with selectors.
Save and Reuse State
Playwright can easily save the authentication state (cookies and localStorage) of a given session, which can be directly used when the script runs next time, saving authentication time. So considerate, right?
Locator API
Playwright's Locator API encapsulates the logic of retrieving a given element, so that you can easily get the latest DOM element in the script at different time points.
Inspector
Playwright's Inspector is a GUI tool that is very useful when debugging scripts. It allows you to execute instructions step by step in the script, making it easy to find the cause of failure.
Test
Playwright has a Test mechanism that is very useful in E2E tests, such as out - of - the - box parallelization, hooks, etc.
Trace Viewer
Playwright's Trace Viewer allows you to explore the traces recorded by Playwright tests or the BrowserContext tracking API. Through tracking, you can clearly see the execution of the script.
Test Generator
You can use Playwright's Test Generator to record interactions in the browser, and the output is a complete script that can be checked and executed.
Precautions During the Migration Process
During the process of migrating from Puppeteer to Playwright, in addition to understanding the various changes and new features mentioned above, there are also some details that we need to pay special attention to.
Version Compatibility Issues
When installing and using Playwright, make sure that its version is compatible with other dependent libraries used in your project. Different versions of Playwright may have slight differences in the way of using the API and functional features. So carefully refer to the official documentation and choose the version suitable for your project. At the same time, also pay attention to the compatibility between Playwright and the browser version you are using. Some new features may require a specific version of the browser to run properly.
Configuration Adjustment
After the migration, you may need to make corresponding adjustments to some configurations. For example, in Puppeteer, you may be used to certain specific startup parameters and configuration options, while in Playwright, the way of configuring and the parameter names may be different. You need to re - set the configuration for launching the browser according to the Playwright documentation, including whether to enable headless mode, set up a proxy, adjust browser performance parameters, etc.
Error Handling
Playwright's error - handling mechanism is also different from that of Puppeteer. During the migration process, ensure that your code can correctly catch and handle various exceptions thrown by Playwright. Playwright's error messages usually contain detailed error reasons and stack traces, which helps you quickly locate and solve problems. You can use try - catch statements to catch exceptions and handle them according to different error types, such as retrying operations, logging error messages, etc.
Team Collaboration
If your project is a team - collaborative development project, then when migrating to Playwright, make sure that all team members are aware of these changes. You can organize team training to share the new features and usage methods of Playwright, so that everyone can get familiar with the new tool as soon as possible. At the same time, update the project's code specifications and documentation to ensure that team members follow a unified standard when using Playwright.
Optimization Suggestions After Migration
After completing the migration, the work is not over. To fully utilize the advantages of Playwright, you can also optimize your code.
Utilize the Parallelization Function
Playwright's Test mechanism provides out - of - the - box parallelization, which can greatly shorten the execution time of test cases. You can reasonably configure the number of test cases to be executed in parallel according to the actual situation of the project, fully utilize the performance of multi - core CPUs, and improve testing efficiency.
Optimize the Waiting Strategy
Although Playwright's auto - waiting mechanism is already very powerful, in some complex scenarios, you may still need to further optimize the waiting strategy. For example, according to the loading characteristics of page elements, reasonably set the waiting timeout to avoid low testing efficiency due to excessive waiting time. At the same time, try to avoid using hard waiting times, but use more intelligent waiting conditions, such as waiting for an element to be visible or clickable.
Code Refactoring
During the migration process, you may find that some code originally written in Puppeteer can be implemented more concisely and efficiently in Playwright. At this time, you can appropriately refactor the code, remove redundant code, and improve the readability and maintainability of the code. At the same time, make use of the new features provided by Playwright to optimize test cases, making them more robust and reliable.
Summary
Although migrating from Puppeteer to Playwright requires us to spend some time and energy to learn and adapt to new changes, in the long run, it is well worth it. Playwright has obvious advantages in terms of performance, stability, and new features, which can bring higher efficiency and a better experience to our testing and automation tasks. As long as we master the key points of migration, pay attention to various details during the migration process, and optimize the code after migration, we can successfully complete this migration and make our project reach a new level with the help of Playwright!
Leapcell: The Next - Gen Serverless Platform for Web Hosting, Async Tasks, and Redis
Finally, I would like to recommend a platform Leapcell that is most suitable for deploying Playwright.
1. Multi - Language Support
- Develop with JavaScript, Python, Go, or Rust.
2. Deploy unlimited projects for free
- Pay only for usage — no requests, no charges.
3. Unbeatable Cost Efficiency
- Pay - as - you - go with no idle charges.
- Example: $25 supports 6.94M requests at a 60ms average response time.
4. Streamlined Developer Experience
- Intuitive UI for effortless setup.
- Fully automated CI/CD pipelines and GitOps integration.
- Real - time metrics and logging for actionable insights.
5. Effortless Scalability and High Performance
- Auto - scaling to handle high concurrency with ease.
- Zero operational overhead — just focus on building.
Explore more in the documentation!
Leapcell Twitter: https://x.com/LeapcellHQ
Top comments (0)