Migration is the incremental process of moving an existing Selenium suite to Playwright — mapping concepts (WebElement→Locator, explicit waits→auto-waiting, switchTo→frameLocator), reusing page-object structure, and porting high-value or flaky tests first rather than rewriting everything at once.
A big-bang rewrite is risky; the pragmatic path is incremental. Start by standing up Playwright alongside Selenium in the same repo, port the flakiest and highest-value journeys first (where auto-waiting pays off most), and let the two suites coexist until Playwright reaches parity. Concept mapping: WebElement becomes a lazy Locator; WebDriverWait/ExpectedConditions largely disappear thanks to auto-waiting and web-first assertions; findElement(By.xpath/css) becomes semantic getByRole/getByLabel (a chance to upgrade brittle selectors); switchTo().frame() becomes frameLocator; Actions/JS-executor tricks become native APIs (hover, dragTo, setInputFiles). Page objects usually port with light edits because the structure is the same. Team enablement matters: codegen and UI Mode shorten the learning curve. Track flaky-rate and runtime before/after to justify the effort with data.
A team with a 400-test Selenium suite that flakes ~8% starts by porting the 30 flakiest end-to-end journeys to Playwright in the same repo. Those 30 drop to near-zero flake and run 3x faster; the data convinces stakeholders, and the remaining tests migrate over the next few sprints while both suites run in CI during the transition.
// Selenium (Java) — explicit wait + XPath + frame switching
// WebElement btn = new WebDriverWait(driver, Duration.ofSeconds(10))
// .until(ExpectedConditions.elementToBeClickable(By.xpath("//button[text()='Pay']")));
// driver.switchTo().frame("card");
// driver.findElement(By.id("num")).sendKeys("4242...");
// driver.switchTo().defaultContent();
// btn.click();
// Playwright — auto-wait + semantic locator + frameLocator, no switching
await page.frameLocator('iframe[name="card"]')
.getByLabel('Card number').fill('4242424242424242');
await page.getByRole('button', { name: 'Pay' }).click();
await expect(page.getByText('Payment successful')).toBeVisible();Scenario: Leadership asks you to migrate a large, flaky Selenium suite to Playwright but is nervous about risk, cost, and losing coverage during the transition. Lay out a migration plan you'd defend in that meeting.