JetBase Logo
  • Hjem
  • Blogg
  • Migrering av Cypress-tester til Playwright med Copilot
Banner

Hovedpunkter

En migrering fra Cypress til Playwright trenger ikke å bli en høy-risiko omskrivning. På en helseplattform ble 148 E2E-tester flyttet gradvis mens Cypress forble aktiv i CI, noe som bevarte utgivelsesdekningen gjennom overgangen. GitHub Copilot reduserte repetitivt konverteringsarbeid med 70–80%, men trygg migrering krevde fortsatt menneskelig gjennomgang, isolerte rammeverkskonfigurasjoner og fil-for-fil validering.

• Bygg Playwright-prototypen på 1–2 dager.
• Kjør begge rammeverkene til hver pakke er stabil.
• Migrer støttefiler før testfiler.
• Gå gjennom importer, fixtures, lokatorer og påstander manuelt.

Når vi fikk en forespørsel om å migrere Cypress-tester til Playwright, forventet vi en lang, tidkrevende omskrivingsprosess.

Overraskende nok, med hjelp fra GitHub Copilot, klarte vi å starte migreringen fra Cypress til Playwright på bare noen dager — og holde CI-pipelinen kjørende hele tiden uten å forstyrre noen testprosesser.

I denne artikkelen vil jeg dele hvordan vi nærmet oss denne migreringen, hvilke lærdommer vi fikk underveis, og hvordan AI-assistert kode-migrering kan drastisk redusere den manuelle overhodet ved rammeverksoverganger.

1

Prosjektkontekst

Prosjektet var en kompleks helseservieplattform med mye som foregikk under panseret. Vår testoppsett inkluderte:

  • End-to-end (E2E) og integrasjonstester
  • Et tilpasset TAF-arkitektur med oppsett, nedleggelse og enhetsopprettelse
  • Multi-miljø konfigurasjoner
  • Dynamiske data og dyp navigasjonslogikk

Totalt hadde vi 148 E2E-tester som kjørte på Cypress — alle fungerte fint, men organisasjonen ønsket å standardisere QA-verktøy på tvers av teamene, noe som betydde én ting: migrering til Playwright.

2

Hvorfor Use GitHub Copilot for Migrering?

Når forespørselen om migrering kom inn, så jeg en mulighet til å eksperimentere med GitHub Copilot for testautomatisering. I stedet for å omskrive hundrevis av testfiler manuelt, ønsket jeg å se hvor langt vi kunne presse AI-assistansen for å automatisere syntaksomformingen fra Cypress til Playwright.

Og ærlig talt, det fungerte langt bedre enn forventet.

GitHub Copilot håndterte de fleste av de gjentagende oversettelsene (selektorer, kommandoer, asynkron håndtering, osv.), noe som lot oss fokusere på infrastrukturjusteringer og finjustering.

Innen 1–2 dager hadde vi allerede en fungerende prototype av Playwright testautomatiseringsrammeverket.

3

To Viktige Ansvarsfraskrivelser

Verifiser Alltid AI-Generert Kode

Selv om AI-assistert kode-migrering får ting til å gå raskere, må du gjennomgå hver linje. Infrastrukturmigreringer kan lett introdusere subtile feil eller ytelsesregresjoner. Tenk på Copilot som din parprogrammerer, ikke som autopilot.

Hold Det Gamle Rammeverket Kjørende Til Slutt

Aldri blokkere utgivelser eller regresjoner under migrering. Hold Cypress-testene dine kjørende på CI inntil de tilsvarende suiteene er helt stabile i Playwright. Når en suite er migrert og validert, fjern den fra Cypress og bytt CI for å kjøre den i Playwright.

Denne gradvise utrullingen sikrer null nedetid og kontinuerlig testdekning gjennom hele prosessen.

4

Arbeidsflyt for å Migrere fra Cypress til Playwright

Når grunnlaget var klart, gikk vi videre til den praktiske migreringen.  
Nedenfor er arbeidsflyten som hjalp oss å kjøre begge rammeverkene parallelt, opprettholde CI-stabilitet, og starte migreringen av tester inkrementelt — uten å blokkere pågående utgivelser.

1. Initialiser Playwright og Opprett Mappen Struktur

Det første steget var å initialisere Playwright og opprette en ren, isolert mappestruktur. Vi ønsket at begge rammeverkene skulle leve side om side i det samme depotet, slik at vi kunne kjøre dem samtidig under overgangen.

Den oppsetningen tillot oss å:

  • Migrere gradvis
  • Sammenligne resultater og tider mellom Cypress og Playwright
  • Holde CI-pipelines kjørende for begge

Eksempel på initialisering:

Initialization example.webp

Her er den foreslåtte mappestrukturen vi brukte for Playwright:

├── cypress/
│   ├── app/
│   ├── downloads/
│   ├── e2e/
│   ├── fixtures/
│   ├── screenshots/
│   ├── support/
│   └── videos/
├── playwright/
│ 	├── app/
│	│   ├── components/
│	│   ├── fixtures/
│	│   └── pageobjects/
│   ├── constants/
│   ├── helpers/
│   ├── reports/
│   ├── test-results/
│   └── tests/
├── .gitignore
├── package.json
├── playwright.config.ts
├── smoke.config.ts
├── tsconfig.json

2. Konfigurer Separate tsconfig Filer for Hvert Rammeverk

Et av de tidlige problemene vi stod overfor var TypeScript-konflikter — begge rammeverkene definerer lignende metodenavn (expect, request, osv.), og deling av en enkelt tsconfig.json førte til kompilasjonsfeil.

Løsningen var enkel: del TypeScript-konfigurasjonene. Denne strukturen sikrer at hvert rammeverk initierer sine egne typebetegnelser og unngår typekonflikter:

├── tsconfig.json
├── tsconfig.cypress.json
├── tsconfig.playwright.json

Hoved tsconfig.json
Legg til composite-alternativet for å støtte prosjektreferanser.

tsconfig.json

{
  "compilerOptions": {
    "composite": true
  }
}

tsconfig.cypress.json

{
  "extends": ".‌/tsconfig.json",
  "compilerOptions": {
    "types": ["cypress", "@testing-library/cypress", "node"],
    "isolatedModules": false
  },
  "include": ["cypress/**/*.ts"]
}

tsconfig.playwright.json

{
  "extends": ".‌/tsconfig.json",
  "compilerOptions": {
    "types": ["node", "@playwright/test"]
  },
  "include": ["playwright/**/*.ts", "playwright.config.ts"]
}

Med denne separasjonen på plass kunne begge rammeverkene sameksistere fredelig i ett repo — ikke flere kompilatorkonflikter, og ingen risiko for å ved et uhell initialisere delte metoder to ganger.

3. Opprett en prompt for å automatisere migrering med GitHub Copilot

Når Playwright var initialisert og prosjektet var strukturert, var det på tide å la GitHub Copilot hjelpe med det tunge løftet.

For å gjøre dette, opprettet vi en tilpasset prompt som definerer hvordan Copilot skal oppføre seg når den omskriver tester fra Cypress til Playwright. Prompten forteller agenten hva den skal gjøre, hvordan den skal gjøre det, og hva som skal ignoreres — noe som gir konsistente resultater på tvers av alle migreringer.

Slik legger du til prompten

Inne i ditt GitHub-repositorium, åpne tannhjulikonet ⚙️ i Copilot Chat og opprett en ny prompt.  
Filene lagres automatisk under: ./github/prompts/

Du kan navngi den noe som migrate_tests.md.

Eksempel på prompt:

---
mode: agent
---
Du er en Playwright Test Generator, en ekspert på nettleserautomatisering og ende-til-ende-testing.
Din spesialitet er å lage robuste, pålitelige Playwright-tester som nøyaktig simulerer brukerinteraksjoner og validerer applikasjonsatferd.
Din oppgave er å hjelpe med å migrere eksisterende Cypress-tester til Playwright-tester.
Cypress-testene, sideobjektene, komponentene og hjelpefilene er gitt som input, og du må generere tilsvarende Playwright-testkode.
Output ALL migrert kode til chatten.
Når du genererer Playwright-testkode eller noen sideobjekter, må du sikre at:
1. Teststrukturen følger den samme strukturen som Cypress-testene.
2. Opprett en global fixture for oppsett og nedsetting og gjenbruk den i testene.
3. Alle brukerinteraksjoner (klikk, skriving, navigasjon) oversettes nøyaktig til Playwright-syntaks i sideobjekter og testfiler.
4. Påstander i Cypress konverteres til tilsvarende Playwright-påstander.
5. Ignorer nettverksinnsyning og stubbing-deler av Cypress-testene.
6. Kommenter ut alle metodene med venting (f.eks. cy.wait) i Playwright-koden.
7. Ikke bruk get-metoder i sideobjekter; bruk direkte metoder i stedet `backbackItem = () => this.page.locator('[id="item_4_title_link"]');`

Hvorfor dette hjelper

Denne typen strukturerte prompt gjør at GitHub Copilot kan oppføre seg mer som en spesialisert migreringsassistent, ikke en generell kodegenerator.

Med riktig kontekst og regler kan Copilot automatisk:

  • Omskrive store biter av Cypress-tester til Playwright-syntaks
  • Opprettholde konsistens i mappe- og teststruktur 
  • Redusere manuell konverteringstid med 70–80%

I hovedsak lager du ditt eget AI-migreringsverktøy — skreddersydd for prosjektets struktur og konvensjoner.

4. Velg agentmodus og kjør migreringen trinn for trinn

Når prompten var klar, var neste steg å faktisk kjøre migreringen med GitHub Copilot i agentmodus. I denne fasen lar vi AI-modellen prosessere hver fil — sideobjekter, komponenter, hjelpere, og til slutt testene — én etter én.

For this task, we used the GPT-4.1-modellen, som leverer de mest konsistente og kontekstsensitive kodeforvandlinger.

Slik starter du migrasjonen

1. Åpne Copilot Chat i VS Code

2. Bruk / for å velge prosjektfilen du opprettet tidligere

3. Bruk # for å velge en spesifikk fil (for eksempel en Cypress-test eller sideobjekt) som du ønsker å migrere

Copilot vil nå bruke migreringsprompten din og generere en Playwright-kompatibel versjon av filen direkte i chatten.

How to Start Migration.webpEksempel på migrering av inventoryPage Sideobjekt

import { ItemComponent } from "..‌/components/item.component";
import Common from ".‌/common";
class InventoryPage extends Common {
  item = new ItemComponent();
  backbackItem = () => cy.get("#item_4_title_link");
  backbackAddItemButton = () => cy.getByTestId("add-to-cart-sauce-labs-backpack");
  bikeLightsAddItemButton = () => cy.getByTestId("add-to-cart-sauce-labs-bike-light");
  backbackRemoveItemButton = () => cy.getByTestId("remove-sauce-labs-backpack");
  shoppingCartLogo = () => cy.get("#shopping_cart_container");
  clickBackbackAddItemButton = () => this.backbackAddItemButton().click();
  clickBikeLightsAddItemButton = () => this.bikeLightsAddItemButton().click();
  clickBackbackRemoveItemButton = () => this.backbackRemoveItemButton().click();
  assertCartLogoItems = (itemsNum: number) => this.shoppingCartLogo().should("have.text", itemsNum);
}
export default new InventoryPage();

 

import { Page, Locator, expect } from "@playwright/test";
import Common from ".‌/common";
class InventoryPage extends Common {
  constructor(page: Page) {
    super(page);
    this.item = new ItemComponent(page);
  }
  
  // Locators
  backbackItem(): Locator {
    return this.page.locator("#item_4_title_link");
  }
  backbackAddItemButton(): Locator {
    return this.page.getByTestId("add-to-cart-sauce-labs-backpack");
  }
  bikeLightsAddItemButton(): Locator {
    return this.page.getByTestId("add-to-cart-sauce-labs-bike-light");
  }
  backbackRemoveItemButton(): Locator {
    return this.page.getByTestId("remove-sauce-labs-backpack");
  }
  shoppingCartLogo(): Locator {
    return this.page.locator("#shopping_cart_container");
  }
  // Actions
  async clickBackbackAddItemButton(): Promise<void> {
    await this.backbackAddItemButton().click();
  }
  async clickBikeLightsAddItemButton(): Promise<void> {
    await this.bikeLightsAddItemButton().click();
  }
  async clickBackbackRemoveItemButton(): Promise<void> {
    await this.backbackRemoveItemButton().click();
  }
  async assertCartLogoItems(itemsNum: number): Promise<void> {
    await expect(this.shoppingCartLogo()).toHaveText(String(itemsNum));
  }
}
export default InventoryPage;

Justering av agentens atferd

Ikke bekymre deg hvis det første resultatet ikke er perfekt. Vår erfaring er at AI-agenten vanligvis får 60–70 % av koden riktig på første forsøk. Nøkkelen er å holde samtalekonteksten aktiv — fortsett å forbedre resultatet i den samme chattråden ved å be om rettelser eller justeringer. Etter hvert begynner Copilot å lære mønstrene i prosjektet ditt og produserer mer nøyaktig og gjenbrukbar kode.

Kort sagt: jo flere iterasjoner du gjør i den samme chatten, desto bedre blir kvaliteten på migreringen.

Migreringsrekkefølge: filer først, deretter tester

For å holde avhengighetene konsistente og unngå manglende referanser, følg denne rekkefølgen:

1. Generer filene som ikke er tester, først:

  • Sideobjekter
  • Komponenter
  • Hjelpefiler
  • Konstanter

2. Når alle støttefilene er generert og verifisert, legger du til #app-mappen i chatkonteksten og migrerer deretter selve testfilene.

Verifiseringstrinn

Når en Playwright-test er generert:

1. Gå gjennom koden — bekreft at sidelokatorer, testtrinn og påstander er riktige.

2. Kjør testen med Playwright CLI for å sikre at den kjører som den skal.

3. Rett opp mindre avvik i syntaks eller fixtures hvis Copilot har misforstått en Cypress-kommando.

Ved å verifisere etter hver fil holder du migreringen stabil og trinnvis, og du unngår omfattende feilsøking senere.

Eksempel på en migrert inventoryPage-test som består:

import inventoryPage from "cypress/app/pageobjects/inventoryPage";
import loginPage from "cypress/app/pageobjects/loginPage";
import { itemsNames } from "../..‌/fixtures/data.json";
describe("InventoryPage tests", () => {
  beforeEach(() => {
    loginPage.loginWithValidData();
  });
  it("The user should add item to the card", () => {
    inventoryPage.item.itemByName("Bike Light").should("have.text", itemsNames.bikeLight);
    inventoryPage.item.addToCartByName("Bike Light");
    inventoryPage.assertCartLogoItems(1);
  });
  it("The user should remove item from the card", () => {
    inventoryPage.backbackItem().should("have.text", itemsNames.backpackItemName);
    inventoryPage.clickBackbackAddItemButton();
    inventoryPage.assertCartLogoItems(1);
    inventoryPage.clickBackbackRemoveItemButton();
    inventoryPage.shoppingCartLogo().should("not.have.text");
  });
  it("The user should add multiple items to the card", () => {
    inventoryPage.backbackItem().should("have.text", itemsNames.backpackItemName);
    inventoryPage.clickBackbackAddItemButton();
    inventoryPage.assertCartLogoItems(1);
    inventoryPage.clickBikeLightsAddItemButton();
    inventoryPage.assertCartLogoItems(2);
  });
});

 

import { test, expect } from "..‌/fixtures/test.fixture";
import { itemsNames } from "../..‌/constants/data.json";
// InventoryPage tests migrated from Cypress to Playwright
test.describe("InventoryPage tests", () => {
  test.beforeEach(async ({ pageManager }) => {
    await pageManager.loginPage.loginWithValidData();
  });
  test("The user should add item to the cart", async ({ pageManager }) => {
    await expect(
    pageManager.inventoryPage.item.itemByName(itemsNames.bikeLight)).toHaveText(itemsNames.bikeLight);
    await pageManager.inventoryPage.item.addToCartByName(itemsNames.bikeLight);
    await pageManager.inventoryPage.assertCartLogoItems(1);
  });
  test("The user should remove item from the cart", async ({ pageManager }) => {
    await expect(
      pageManager.inventoryPage.backbackItem()).toHaveText(itemsNames.backpackItemName);
    await pageManager.inventoryPage.clickBackbackAddItemButton();
    await pageManager.inventoryPage.assertCartLogoItems(1);
    await pageManager.inventoryPage.clickBackbackRemoveItemButton();
    await expect(pageManager.inventoryPage.shoppingCartLogo()).not.toHaveText(/\d/); // Should not have any number text
  });
  test("The user should add multiple items to the cart", async ({ pageManager }) => {
    await expect(pageManager.inventoryPage.backbackItem()).toHaveText(itemsNames.backpackItemName);
    await pageManager.inventoryPage.clickBackbackAddItemButton();
    await pageManager.inventoryPage.assertCartLogoItems(1);
    await pageManager.inventoryPage.clickBikeLightsAddItemButton();
    await pageManager.inventoryPage.assertCartLogoItems(2);
  });
});

5. Endelig repositorystruktur etter migreringen

Da migreringen var fullført, hadde repositoryet vårt nådd en stabil tilstand med to rammeverk — Cypress og Playwright kjørte fullt ut side om side. Denne strukturen gjorde det mulig for oss å:

  • Gradvis fase ut Cypress-testsuiter etter hvert som de ble erstattet
  • Holde CI/CD-pipelinene i drift for begge rammeverkene
  • Opprettholde en ren og modulær arkitektur

Nedenfor er den endelige strukturen etter at migreringsarbeidsflyten var fullført.

Endelig mappestruktur

├── .env
├── .gitignore
├── readme.md
├── package.json
├── playwright.config.ts
├── smoke.config.ts
├── tsconfig.cypress.json
├── tsconfig.playwright.json
├── tsconfig.json
├── .github/
│   ├── prompts/
│   └── workflows/
├── cypress/
│   ├── app/
│   ├── downloads/
│   ├── e2e/
│   ├── fixtures/
│   ├── screenshots/
│   ├── support/
│   └── videos/
├── playwright/
│   ├── app/
│   ├── constants/
│   ├── helpers/
│   ├── reports/
│   ├── test-results/
│   └── tests/

Merknader om strukturen

  • .github/prompts/ — inneholder Copilot-promptene for migreringen. Når de er versjonert, kan du oppdatere eller gjenbruke dem ved fremtidige rammeverksmigreringer eller refaktoreringer.
  • .github/workflows/ — inneholder CI/CD-definisjonene dine. Du kan kjøre Playwright- og Cypress-jobber parallelt til det gamle rammeverket er helt faset ut.
  • playwright/-mappen — fungerer nå som den primære kilden for automatisering. Den speiler strukturen i den tidligere Cypress-implementeringen for å gjøre det enklere å komme i gang og sikre konsistens.
  • tsconfig.playwright.json og tsconfig.cypress.json — holdes adskilt for full typeisolasjon og forhindrer konflikter under bygg.

Denne strukturen ga ikke bare en smidig overgang, men gjorde også prosjektet klart for fremtidig skalerbarhet, CI-fleksibilitet og modulært testeierskap på tvers av team.

 
Planlegger du en migrering fra Cypress til Playwright?

Flytt testsuiten din uten å forstyrre utgivelser eller miste dekning. QA-ingeniørene våre kan hjelpe deg med å planlegge migreringen, tilpasse automatiseringsarkitekturen og holde begge rammeverkene stabile under overgangen.

5

Praktiske råd & erfaringer

Etter å ha migrert nesten 150 tester med Copilot og Playwright, er her noen viktige erfaringer og praktiske tips som gjorde prosessen smidigere (og sparte oss for en del hodebry).

Generelle råd om AI

  • AI lyver — ofte overbevisende.  

Kontroller alltid hver kodelinje AI-en genererer. Stol aldri blindt på den, spesielt ikke under infrastrukturmigreringer.

  • Hold deg til konsistente navnekonvensjoner.

Bruk identiske variabel- og metodenavn i begge rammeverkene — det hjelper AI-agenten med å migrere koden mer nøyaktig og gjør det lettere for deg å finne og importere dem senere.

Generelle råd om AI.webp

  • Bygg importene på nytt manuelt.

Copilot har en tendens til å rote til importstiene. Ofte går det raskere å slette dem og importere på nytt manuelt, eller å sette opp globale importer som: import x from "playwright/foo/bar";

  • Gjenbruk den samme chatten for alle migreringer.

Hold deg til én Copilot-chattråd — den bygger opp kontekst og «husker» konvensjonene i prosjektet ditt, noe som gir bedre resultater.

  • Del opp migreringsoppgavene.  

Generer 1–2 filer om gangen. Mindre oppgaver gir mer nøyaktige resultater og gjør manuell validering enklere.

Playwright-spesifikke råd

  • Opprett aldri flere instanser av det samme Page Object uten behov.

Det kan føre til inkonsistent tilstand eller ødelagte selektorer når du navigerer mellom sider. Løsningen? Implementer en Page Manager som gjør alle sideobjekter tilgjengelige via én enkelt instans.

Her er et minimalt eksempeloppsett:

// login.page.ts
class LoginPage extends Common {
  async clickLoginButton(): Promise<void> {
    await this.loginButton().click();
  }
}
export default LoginPage;
//-----------------------------------------------------------
//PageManager.ts
export class PageManager {
  readonly loginPage: LoginPage;
  constructor(page: Page) {
    this.loginPage = new LoginPage(page);
  }
}
//-----------------------------------------------------------
//test.fixture.ts
export const test = base.extend<{
  pageManager: PageManager;
}>({
  pageManager: async ({ page }, use) => {
    const manager = new PageManager(page);
    await use(manager);
  },
});
export { expect };
//-----------------------------------------------------------
//userLogin.spec.ts
  test("The user should login with valid data", async ({ pageManager }) => {
    await pageManager.loginPage.clickLoginButton();
  });

Andre tekniske tips

  • Fjern alle «get»-prefikser fra lokatorene AI-agenten genererer — bruk direkte lokatormetoder i stedet.
  • Ikke glem å konfigurere dotenv for miljøvariabler og påloggingsinformasjon.
  • Tilpass Playwright-konfigurasjonen slik at alle rapporter havner i Playwright-mappen og prosjektroten holdes ryddig:
reporter: [["html", { open: "never", outputFolder: ".‌/playwright/reports/" }]],
  outputDir: ".‌/playwright/test-results",
6

Etterord

Jeg tok ikke med ESLint-oppsettet her, siden det varierer fra prosjekt til prosjekt.  
Den eneste universelle anbefalingen jeg kan gi, er å installere Playwright-pluginen for ESLint for bedre regelhåndheving: eslint-plugin-playwright.

Hvis du vil utforske et komplett, fungerende eksempel på denne migreringen — inkludert promptfiler, tsconfig-filer og CI-oppsett — kan du se hele repositoryet her: Repo-eksempel.

 
Klar til å modernisere testautomatiseringen din?

Enten du migrerer fra Cypress, bygger opp igjen en ustabil testsuite eller forbedrer QA-automatiseringen, kan JetBase hjelpe deg med overgangen med mindre manuelt arbeid og lavere leveringsrisiko.

Kommentarer

Logg inn for at legge igjen en kommentar
Fortsett med GoogleFortsett med Google
Moderne

Våre kundecaser

Innovasjon handler ikke bare om ideer - det handler om utførelse, å gjøre visjonen til virkelighet og skape løsninger som virkelig gjør en forskjell. Se hva vi har bygget og hvordan det fungerer:

  • Helse
  • Medier og Underholdning
  • e-handel
  • Amazon Web Services
  • Kostnadsoptimalisering i skyen
  • Serverløs applikasjon
  • Detaljhandel
  • Helsevesen - Banner
    • 100%HIPAA-samsvarende
    • 99,99% oppetidMaksimal pålitelighet
  • Helsevesen - Banner
    • 10 000+Pasienter som støtter
    • Engasjement 30%+Adaptiv UX

Siste Artikler