Skip to content

Cypress → Playwright Migration

When to Use

Moving an existing Cypress ATK suite to Playwright.

What's Reusable

Asset Reusable?
Preprocess hooks (body classes, data-media-id) Yes — module-side
drushCmd, pantheon, targetSite, tugboat settings Yes — same keys in playwright.atk.config.js
preflightTests.yml, qaUsers.json Yes — same files
Testor snapshots Yes — Testor is runner-agnostic
Test bodies Translation needed
Helpers Mostly the same names; signatures differ

Pattern: Translation Patterns

Cypress Playwright
cy.visit('/path') await page.goto(baseUrl + 'path')
cy.get(sel).click() await page.locator(sel).click()
cy.get(sel).type('foo') await page.locator(sel).fill('foo')
cy.get(sel).should('contain', 'X') await expect(page.locator(sel)).toContainText('X')
cy.execDrush(cmd) atkCommands.execDrush(cmd) (synchronous; a string locally, a Buffer via Pantheon, SSH or Tugboat)
cy.logInViaForm(account) await atkCommands.getUserPage(browser, account) or logInViaForm(page, context, account)
cy.getNid() await atkCommands.getNid(page)
cy.inputCKEditor(text) await atkCommands.inputTextIntoCKEditor(page, text)
{ tags: ['@smoke'] } @smoke in the test title
describe / it test.describe / test

Helper Gaps

  • Playwright only: expectMessage, openSearchForm, checkSearchResult, deleteCurrentNodeViaUi, getUserPage, getDrushAlias, preflightTest, skipIfLocal
  • Cypress only: getByLabel, getIframeBodyWithId, save, debugLog, trace
  • Cypress commands, unexported in Playwright: execViaSsh, execTugboatDrush
  • Different IDs: Cypress user tests are 1020/1021; Playwright's are 1100/1101
  • Cypress only: simple sitemap (1080/1081)

Decision: migrate all at once or incrementally?

Approach When
All at once Small suite; one sprint available
Incrementally Larger suite; migrate per area
Stay on Cypress The suite works and the team knows it

Pattern: side by side during migration

atk_setup puts Playwright tests in tests/ and Cypress tests in cypress/e2e/, so they can coexist. Both write package.json at ATK_HOME. Merge the two dependency lists by hand, or set a different ATK_HOME per runner.

Common Mistakes

  • Migrating a flaky Cypress suite — the flakes migrate too
  • Translating literally — adopt Playwright's web-first assertions
  • Treating execDrush() as a Cypress chain — the Playwright version returns stdout directly: a string locally, a Buffer via Pantheon, SSH or Tugboat

See Also