Home / Services / Playwright migration services
Migrate your test suite to Playwright
The end state is one Playwright suite in your repository, green in your pipeline on every commit, whatever it is running on today.
We move an end-to-end suite onto Playwright from any web automation framework — the tests, the fixtures and the CI job. The source does not change the method: inventory, a pilot slice, bulk conversion, then a cutover with both suites green on the same commits. Engineers are billed hourly, from $50 an hour, minimum one full-time engineer for one month.
You get questions back first, starting with whether moving the suite is worth the money to you. If it runs on something with no page of its own on this site, this page is yours.
Who this is for
You settled the framework question already. The open one is the four years of tests sitting in the repository, and which of them survive the move.
- Enough tests that hand-converting them would come out of next quarter's roadmap.
- Test infrastructure with a single owner who would like to stop being it.
- A pass rate low enough that a red build gets re-run before anybody reads it.
We take a migration from any web automation framework, and a repository holding two of them at once is still one job. The three with pages of their own here are the ones we are asked for most often.
Changing framework does not have to mean changing language. Playwright ships four official bindings — TypeScript and JavaScript, Python, Java and .NET — and we deliver in all four, so a Java suite can arrive in Playwright still written in Java and your team can still read it. That choice reaches the pipeline. The sharding and the merged report shown further down belong to Playwright's own test runner, which ships only with the JavaScript and TypeScript binding, so a Java, Python or .NET suite is split and reported through the runner that language already has.
There is a size below which none of this is worth buying, and a suite one of your engineers could convert in-house is under it. A suite nobody trusted in the first place is a deletion rather than a migration, because moving it buys you a bad suite that runs faster. If there are no end-to-end tests at all, the engagement you want is a Playwright suite built from scratch. If the suite is already Playwright and nobody believes its results, that is flaky suite repair.
Which suite are you leaving
Selenium
The work concentrates in the waits and in whatever replaces the Grid, and the language the suite is written in usually arrives with it. Moving a Selenium suite sets out what changes.
Cypress
You are leaving a runner as well as a library, so the config, the support directory and the browser model all have to be re-expressed rather than ported across. Leaving Cypress goes through those.
Protractor
The clock on this one is not ours: the package is deprecated, and npm's registry entry for it carries a notice putting end of life in 2023. Protractor is end of life, and that page is written for a suite nobody still on the team wrote.
Everything else lands here: WebdriverIO, TestCafe, Nightwatch, a folder of Puppeteer scripts, a wrapper somebody built over WebDriver and then left the company. A framework gets a page of its own because enough people search for it, which says nothing about what we accept. The single boundary is the destination: a suite driving a native iOS or Android application has nowhere to land in Playwright, so an Appium suite is not a migration anybody can do, and that is a fact about the framework and not a preference of ours.
What you get
The converted suite
Every test in the old suite arrives in your repository as Playwright, through your own pull requests: converted, fixed, or deliberately dropped. Nothing leaves the suite without a line saying why.
The pipeline that runs it
The CI job itself, split across machines, with the blob report from each shard merged into one report for the run. Whatever gave the old suite its parallelism stays behind with it, so this pipeline is built new.
The migration record
A single file mapping the old suite onto the new one, test by test, deletions included and each with its reason. Your engineers should be able to review the converted suite without us in the room.
How it works
Inventory
Somebody reads every test in the suite, plus the last few weeks of pipeline history, and writes down what is in there: the test count, how many pass today, how many are quarantined, how many pipelines run any of it, and where the test data comes from. You give us repository access, one recent pipeline run or the plain statement that there is not one, and the list of what is already quarantined.
A pilot slice
One user journey, converted the whole way through and running in your CI before anything else starts. Disagreeing about the method costs less on twenty lines of running code than on a plan. Everything converted afterwards follows the conventions it sets. You give us the journey that matters most, and an environment we can point at.
Bulk conversion
The rest, in tranches. Each tranche is reviewed, merged and running in CI before the next one starts, so an engagement that stops halfway leaves converted tests in your repository instead of a branch nobody can land. One long-lived branch is how a migration ends with two half-suites and nobody trusting either. You give us review time from someone who knows the product, on every tranche.
Cutover
Both suites run against the same commits until the Playwright one has passed on them, and then the old job comes out of the pipeline. You give us the call that it is done, and the name of whoever owns the pipeline afterwards.
There are no weeks in that list on purpose. The schedule is set by the test count, how many of those tests pass today, whether the suite is structured code or steps written inline, the number of pipelines that run any of it, and how much test data is set up by clicking through the product. The inventory measures those on your repository, and the tranche plan comes out of what it finds.
The code — where every migration lands
Conversion is engineers reading tests one at a time, and what each test becomes depends on the framework you are leaving. Every migration converges on a config file and a pipeline, so those are the two samples below.
The config is the whole runner, in one file a reader can hold in their head:
// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
fullyParallel: true,
workers: process.env.CI ? 4 : undefined,
retries: process.env.CI ? 2 : 0,
reporter: process.env.CI ? 'blob' : 'html',
use: {
baseURL: 'https://staging.example.com',
trace: 'on-first-retry',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
testIgnore: '**/quarantine/**',
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
testIgnore: '**/quarantine/**',
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
testIgnore: '**/quarantine/**',
},
{
name: 'quarantine',
use: { ...devices['Desktop Chrome'] },
testMatch: '**/quarantine/**',
},
],
});
Both samples on this page are written against Playwright 1.62.
The concurrency your old infrastructure needed a machine for is now two keys:
fullyParallel and workers. The quarantine project is
the migration-shaped part of the file. Converted tests that nobody trusts yet run under their
own name and cannot redden the main job, which is what stops somebody deleting them in week
three to get the build green. The webkit project runs Playwright's WebKit build, which is not
Safari on an iPhone — that limit is below.
The pipeline is four commands, and they are the same four in GitHub Actions, GitLab CI or Jenkins:
# In each of four CI jobs, with SHARD set to 1, 2, 3 or 4.
npm ci
npx playwright install --with-deps
npx playwright test --shard=$SHARD/4
# In one job afterwards, with the four blob reports collected into one directory.
npx playwright merge-reports --reporter html ./all-blob-reports
Each job writes a blob report instead of an HTML one, and the last step merges the four into
a single report for the run. Sharding
balances differently depending on the config above:
with fullyParallel set, the run is split at the level of individual tests, and
without it at the level of files — which is why a suite of six long spec files spreads badly
across four jobs until that key is on. Teams who would rather not install browsers on every
run can start from the container image Playwright publishes for the release, which for 1.62 is
mcr.microsoft.com/playwright:v1.62.0-noble in
the CI documentation's own samples.
Where this stops
An old suite usually contains something Playwright cannot do. We name those tests during the inventory, and we do not quote for them.
- Native mobile apps. Whatever part of the suite drives a native iOS or Android build does not move. Playwright drives browsers. It emulates a mobile browser — a viewport, a user agent, touch input — which covers your responsive web at phone size, and none of that is the app, the store build or the device. Those tests stay where they are, and we do not sell a replacement for them.
- Load and performance at scale. If part of the old infrastructure was being used to put the application under load, Playwright does not take that over. It measures one real browser doing one thing well; it is not k6, JMeter or Gatling, and no engagement sold here includes load testing.
- Safari on a real iOS device. Playwright's WebKit build is not Safari on
an iPhone: the browser documentation says
Playwright does not work with the branded version of Safari, because it relies on patches.
If you reach real Safari today through a device cloud, that coverage does not
come across. The
webkitproject in the config above is a second engine running unflagged in CI on every commit, and it is not that version of Safari on that hardware. If you need both, keep the device-cloud suite for that one browser and move everything else. - Internet Explorer. Not supported by the framework. Those tests do not move, and there is no version of this engagement in which they do. Old suites still carry them.
Security and penetration testing are not offered here either, in any framework.
What it costs
The price is engineer time, and the only way to know it is to count the suite. Engineers are billed hourly, from $50 an hour, depending on where the engineer sits. The minimum engagement is one full-time engineer for one month.
On a migration it moves with how much of the suite is worth keeping, and with how much of its test data was set up by clicking through the product. A suite that signs in through the front end three hundred times is carrying three hundred conversions that are not really tests, and they cost the same as the ones that are.
Read first
- How Playwright drives a browser. The technical spine underneath everything on this page.
- Parallel runs and sharding. The long version of the config and the pipeline above.
- Playwright's advantages and limitations. Where the limits above come from, argued at length.
- Playwright vs WebdriverIO. For the part of your team still arguing the framework decision.
Questions
How long does a Playwright migration take?
That depends on what the inventory finds, and we will not put a number on a web page ahead of it. The estimate comes out of the test count, how many of those tests pass today, whether the suite is structured code or steps written inline, the number of pipelines that run any of it, and how much test data is set up by clicking through the product. Two suites with the same number of tests can be a long way apart on those inputs alone.
Which frameworks do you migrate from?
Any web automation framework that drives a browser. Selenium, Cypress and Protractor have pages of their own here because they are what we are asked for most often; WebdriverIO, TestCafe, Nightwatch, a folder of Puppeteer scripts and a framework somebody wrote in-house are the same job. The boundary is the destination and not the source: Playwright drives browsers, so a suite driving a native iOS or Android application has nowhere to land in it, and an Appium suite is not a migration we can take.
Do we have to stop shipping while the migration runs?
No. The converted tests arrive in tranches, each merged and running in CI before the next one starts, and the suite you have today keeps running against the same commits until the Playwright suite has passed on them too. You are never left relying on the half-built suite. The old job is switched off at the end of that overlap.
What happens to the tests you cannot migrate?
They are named during the inventory, before anyone quotes for the work. Anything driving a native mobile app, anything that only ever ran in Internet Explorer, and anything that was really a load test wearing a browser: those stay where they are, we do not convert them, and we do not sell you a replacement. What we will not do is drop them quietly and let you find out from a coverage gap six months later.
Do we need the audit before you start?
No. Most clients arrive knowing the job, and we scope that and start. The audit is for the team that wants to know what it has before it picks a direction, so it is a route in and never a gate. It is optional, it is billed by the hour, and how long it takes depends on the project. The minimum of one full-time engineer for one month does not apply to it.
How big is the suite, and what is it written in?
Those two answers and a link to a recent pipeline run are enough to come back to you with a first tranche and a plan for the rest. We do not need an audit to start. Staffing the suite after the last tranche merges is a different conversation.