JetBase Logo
  • Hjem
  • Blog
  • Migrering af Cypress-tests til Playwright med Copilot
Banner

Vigtigste pointer

En migration fra Cypress til Playwright behøver ikke at blive en højrisiko-omskrivning. På en sundhedsplatform blev 148 E2E-tests flyttet gradvist, mens Cypress forblev aktiv i CI og bevarede udgivelsesdækning gennem hele overgangen. GitHub Copilot reducerede gentagne konverteringsopgaver med 70–80 %, men sikker migration krævede stadig menneskelig gennemgang, isolerede ramme-konfigurationer og validering fil for fil.

• Byg Playwright-prototypen på 1–2 dage.
• Kør begge rammer, indtil hver suite er stabil.
• Migrer hjælpefiler før testfiler.
• Gennemgå imports, fixtures, lokatorer og påstande manuelt.

Da vi fik en anmodning om at migrere Cypress tests til Playwright, forventede vi en lang, kedelig omskrivningsproces.

Overraskende nok, med hjælp fra GitHub Copilot, lykkedes det os at starte migreringen fra Cypress til Playwright på blot et par dage — og holde vores CI-pipeline kørende hele tiden uden at forstyrre nogen testprocesser.

I denne artikel vil jeg dele, hvordan vi greb denne migration an, de lektioner vi lærte undervejs, og hvordan AI-assisteret kode-migrering drastisk kan reducere den manuelle belastning ved framework-overgange.

1

Projektkontekst

Projektet var en kompleks sundhedsplatform med meget der foregik under motorhjelmen. Vores testopsætning inkluderede:

  • End-to-end (E2E) og integrationstests
  • En tilpasset TAF-arkitektur med opsætninger, nedlægning og enhedsskabelse
  • Multi-miljøkonfigurationer
  • Dynamiske data og dyb navigationslogik

I alt havde vi 148 E2E-tests kørende på Cypress — alt fungerede fint, men organisationen ønskede at standardisere QA-værktøjer på tværs af teams, hvilket betød én ting: Playwright-migrering.

2

Hvorfor Bruge GitHub Copilot til Migrering?

Da migrationsanmodningen kom ind, så jeg en mulighed for at eksperimentere med GitHub Copilot testautomatisering. I stedet for manuelt at omskrive hundredevis af testfiler, ville jeg se, hvor langt vi kunne presse AI-assistance til at automatisere syntaksomdannelsen fra Cypress til Playwright.

Og ærligt talt, det fungerede langt bedre end forventet.

GitHub Copilot håndterede det meste af den gentagne oversættelse (vælgere, kommandoer, asynkron håndtering, osv.), hvilket lod os fokusere på infrastrukturjusteringer og finjustering.

Inden for 1–2 dage havde vi allerede en fungerende prototype af Playwright testautomatiseringsrammen.

3

To Vigtige Afgørelser

Verificer Altid AI-genereret Kode

Selv om AI-assisteret kode-migrering fremskynder tingene, skal du gennemgå hver linje. Infrastrukturmigreringer kan let introducere subtile fejl eller præstationsregressioner. Tænk på Copilot som din par-programmør, ikke en autopilot.

Hold den Gamle Ramme Kørende Indtil Slutningen

Aldrig blokere udgivelser eller regressioner under migreringen. Hold dine Cypress tests kørende på CI indtil de tilsvarende suits er helt stabile i Playwright. Når en suite er migreret og valideret, fjern den fra Cypress og skift CI til at køre den i Playwright.

Denne gradvise udrulning sikrer nul nedetid og kontinuerlig testdækning gennem hele processen.

4

Arbejdsgang til at Migrere fra Cypress til Playwright

Når fundamentet var klart, gik vi videre til den praktiske migrering.  
Nedenfor er arbejdsgangen, der hjalp os med at køre begge rammer parallelt, opretholde CI-stabilitet og begynde at migrere tests inkrementelt — uden at blokere løbende udgivelser.

1. Initier Playwright og Opret Mappestrukturen

Det første skridt var at initieres Playwright og oprette en ren, isoleret mappestruktur.

Vi ønskede, at begge rammer skulle leve side om side i det samme repository, så vi kunne køre dem samtidigt under overgangen.

Den opsætning gjorde det muligt for os at:

  • Migrere gradvist
  • Sammenligne resultater og tidsforbrug mellem Cypress og Playwright
  • Holde CI-pipelines kørende for begge

Eksempel på initialisering:

Initialization example.webp

Her er den foreslåede mappestruktur, vi brugte til 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. Konfigurere separate tsconfig filer for hver ramme

Et af de tidlige problemer, vi stod overfor, var TypeScript-konflikter — begge rammer definerer lignende metode navne (expect, request, osv.), og deling af en enkelt tsconfig.json førte til kompilationsfejl.

Løsningen var enkel: Opdel TypeScript-konfigurationerne. Denne struktur sikrer, at hver ramme initialiserer sine egne type-definitioner og undgår type kollisioner:

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

Hoved tsconfig.json
Tilføj composite muligheden for at understøtte projektreferencer.

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 adskillelse på plads kunne begge rammer sameksistere fredeligt i ét repo — ikke flere kompilatorkonflikter, og ingen risiko for utilsigtet at initialisere delte metoder to gange.

3.

Opret en prompt til at automatisere migration med GitHub Copilot

Når Playwright var blevet initialiseret, og projektet var struktureret, var det tid til at lade GitHub Copilot hjælpe med det tunge arbejde.

For at gøre dette oprettede vi en brugerdefineret prompt, der definerer, hvordan Copilot skal opføre sig, når der omskrives tests fra Cypress til Playwright. Prompten fortæller agenten, hvad der skal gøres, hvordan det skal gøres, og hvad der skal ignoreres - hvilket giver ensartede resultater i alle migrationer.

Sådan tilføjer du prompten

Inde i dit GitHub-repositorium skal du åbne gearikonet ⚙️ i Copilot Chat og oprette en ny prompt.  
Filen gemmes automatisk under: ./github/prompts/

Du kan navngive den noget som migrate_tests.md.

Eksempel på prompt:

---
mode: agent
---
Du er en Playwright Test Generator, en ekspert i browserautomatisering og end-to-end testning.
Din specialitet er at skabe robuste, pålidelige Playwright-tests, der præcist simulerer brugerinteraktioner og validerer applikationens adfærd.
Din opgave er at hjælpe med at migrere eksisterende Cypress-tests til Playwright-tests.
Cypress-tests, sideobjekter, komponenter og hjælpefiler gives som input, og du skal generere ækvivalent Playwright testkode.
Output ALLE migrerede koder til chatten.
Når du genererer Playwright testkoden eller nogen sideobjekter, skal du sikre dig, at:
1. Teststrukturen følger den samme struktur som Cypress-tests.
2. Opret en global fixture til opsætning og nedtagning og genbrug den i tests.
3. Alle brugerinteraktioner (klik, typning, navigation) oversættes præcist til Playwright-syntaks i sideobjekter og testfiler.
4. Påstande i Cypress konverteres til ækvivalente Playwright-påstande.
5. Ignorer netværksaflytning og stub-delen af Cypress-tests.
6. Kommenter alle metoder med ventetid (f.eks. cy.wait) i Playwright-koden.
7. Brug ikke get-metoder i sideobjekter; brug direkte metoder i stedet `backbackItem = () => this.page.locator('[id="item_4_title_link"]');`

Hvorfor dette hjælper

Denne type struktureret prompt giver GitHub Copilot mulighed for at opføre sig mere som en specialiseret migrationsassistent, ikke som en generel kodegenerator.

Med den rette kontekst og regler kan Copilot automatisk:

  • Omskrive store dele af Cypress-tests til Playwright-syntaks
  • Opretholde konsistens i mappens og teststrukturen 
  • Reducere manuel konverteringstid med 70–80%

Essentielt set skaber du dit eget AI-migrationsværktøj - skræddersyet til dit projekts struktur og konventioner.

4. Vælg agenttilstand og kør migration trin for trin

Når prompten var klar, var næste skridt egentlig at køre migrationen med GitHub Copilot i agenttilstand. I denne fase lod vi AI-modellen behandle hver fil - sideobjekter, komponenter, hjælpere og til sidst tests - én ad gangen.

Til denne opgave brugte vi GPT-4.1 modellen, som leverer de mest konsistente og kontekstbevidste kodeændringer.

Hvordan man starter migration

1. Åbn Copilot Chat i VS Code

2. Brug / til at vælge den promptfil, du tidligere oprettede

3. Brug # til at vælge en specifik fil (for eksempel en Cypress test eller sideobjekt), som du ønsker at migrere

Copilot vil nu anvende din migrationsprompt og generere en Playwright-kompatibel version af filen direkte i chatten.

Hvordan man starter migration.webpEksempel på migration af inventoryPage sideobjektet

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);
  }
  
  // Lokatorer
  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");
  }
  // Handlinger
  async clickBackbackAddItemButton(): Promise<void> {
    await this.backbackAddItemButton().click();
  }
  async clickBikeLightsAddItemButton(): Promise<void> {
    await this.bikeLightsAddItemButton().```html

Justering af agentens adfærd

Vær ikke bekymret, hvis den første output ikke er perfekt. Fra vores erfaring får AI-agenten normalt 60-70 % af koden rigtigt ved første forsøg. Nøglen er at holde samtalekonteksten aktiv — fortsæt med at forfine den samme chattråd ved at anmode om rettelser eller justeringer. Når du gør dette, begynder Copilot at lære dine projektmønstre og producerer mere præcis, genanvendelig kode.

Essensielt, jo flere iterationer du laver i den samme chat, desto bedre bliver migrationskvaliteten.

Migrationsorden: Filer først, derefter tests

For at holde afhængighederne konsistente og undgå at miste referencer, følg denne orden:

1. Generer ikke-testfiler først:

  • Sideobjekter
  • Komponenter
  • Hjælpefiler
  • Konstanter

2. Når alle støttefiler er genereret og verificeret, tilføj #app mappen til chatkonteksten, og migrer derefter selve testfilerne.

Verifikations trin

Når en Playwright-test er genereret:

1. Gennemgå koden — bekræft at sidelokatorer, testtrin og påstande er korrekte.

2. Kør testen ved hjælp af din Playwright CLI for at sikre, at den udføres korrekt.

3. Fix mindre syntaks- eller fixture-mismatches, hvis Copilot misunderstod en Cypress-kommando.

Ved at verificere efter hver fil holder du migrationen stabil og inkrementel og undgår storskala fejlretning senere.

Eksempel på en migreret inventoryPage test, der klarer sig succesfuldt:

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("Brugeren skal tilføje en vare til kurven", 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("Brugeren skal fjerne en vare fra kurven", 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("Brugeren skal tilføje flere varer til kurven", 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 repositørstruktur efter migration

Når migrationen var afsluttet, nåede vores repository en stabil, dual-framework tilstand — fuldt kørende både Cypress og Playwright side om side. Denne struktur gjorde det muligt for os at:

  • Gradvist udfase Cypress test suite, efterhånden som de blev erstattet
  • Holde CI/CD pipelines operationelle for begge rammer
  • Opretholde en ren og modulær arkitektur

Nedenfor er den endelige struktur efter afslutningen af migrationsarbejdsgangen.

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/

Noter om strukturen

  • .github/prompts/ — indeholder dine Copilot migrationsprompter. At holde disse versionerede giver dig mulighed for at opdatere eller genbruge dem til fremtidige rammeværksmigreringer eller refaktoreringer.
  • .github/workflows/ — har dine CI/CD definitioner. Du kan køre både Playwright og Cypress jobs parallelt indtil fuld afvikling af det gamle rammeværk.
  • playwright/ mappen — fungerer nu som den primære automatiseringskilde fremadrettet. Den spejler strukturen af den tidligere Cypress implementering for at lette onboarding og sikre konsistens.
  • tsconfig.playwright.json og tsconfig.cypress.json — forbliver separate for fuld typeisolering, hvilket forhindrer konflikter under builds.

Denne struktur understøttede ikke kun en glat overgang, men positionerede også projektet til fremtidig skalerbarhed, CI fleksibilitet, og modulær testejerskab på tværs af teams.

 
Planlægger du en migrering fra Cypress til Playwright?

Flyt din test suite uden at forstyrre udgivelser eller miste dækning. Vores QA ingeniører kan hjælpe dig med at planlægge migreringen, tilpasse din automatiseringsarkitektur, og holde begge rammeværk stabile under overgangen.

5

Praktiske råd & lærte lektioner

Efter at have migreret næsten 150 tests med Copilot og Playwright, her er et par nøglelektioner og virkelige tips, der gjorde processen lettere (og reddede os fra nogle hovedpiner).

Generelle AI-relaterede råd

  • AI lyver — ofte overbevisende.  

Verificer altid hver linje af kode, som AI genererer. Stol aldrig blindt på det, især under infrastrukturmigreringer.

  • Hold dig til konsistente navngivningskonventioner.

Hold identiske variabel- og metode navne på tværs af rammerne — det hjælper AI Agenten med at migrere kode mere præcist og gør det lettere for dig at finde og importere dem senere.

Generelle AI-relaterede råd.webp

  • Rebyg imports manuelt.

Copilot plejer at rodes med importstier. Det er ofte hurtigere at slette dem og re-importere manuelt, eller at opsætte globale imports som: import x from "playwright/foo/bar";

  • Genbrug den samme chat til alle migreringer.

Hold dig til en enkelt Copilot chattråd — det opbygger kontekst og “husker” dine projektkonventioner, hvilket fører til bedre resultater.

  • Opdel migrationsopgaver.  

Generer 1–2 filer ad gangen. Mindre opgaver giver mere præcise resultater og gør manuel validering lettere.

Playwright-specifikke råd

  • Opret aldrig flere forekomster af det samme Page Object uden behov.

At gøre det kan forårsage inkonsistent tilstand eller brudte vælgere, når du navigerer mellem sider. Løsningen? Implementer en Page Manager, der holder alle sideobjekter tilgængelige gennem en enkelt forekomst.

Her er en minimal eksempelopsætning:

// 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” præfikser fra lokatorer, som AI Agenten genererer — brug i stedet direkte lokatormetoder.
  • Glem ikke at konfigurere dotenv til miljøvariabler og legitimationsoplysninger.
  • Tilpas din Playwright-konfiguration til at outputte alle rapporter under Playwright-mappen, så din projektrod forbliver ren:
reporter: [["html", { open: "never", outputFolder: ".‌/playwright/reports/" }]],
  outputDir: ".‌/playwright/test-results",
6

Slutord

Jeg inkluderede ikke ESLint opsætning her, da det varierer fra projekt til projekt.  
Den eneste universelle anbefaling, jeg kan give, er at installere Playwright ESLint-pluginet for bedre regelsynkronisering: eslint-plugin-playwright.

Hvis du vil udforske et komplet fungerende eksempel på denne migration — inklusive promptfiler, tsconfigs og CI opsætning — kan du tjekke det fulde repository her: Repo eksempel.

 
Klar til at modernisere din testautomatisering?

Uanset om du migrerer fra Cypress, genopbygger en ustabil testsuite eller forbedrer din QA-automatisering, kan JetBase hjælpe dig med at foretage overgangen med mindre manuelt arbejde og lavere leveringsrisiko.

Kommentarer

Log ind for at skrive en kommentar
Fortsæt med GoogleFortsæt med Google
Moderne

Vores Caser

Innovation handler ikke kun om ideer - det handler om udførelse, om at omsætte vision til virkelighed og skabe løsninger, der virkelig skaber en forskel. Se, hvad vi har bygget, og hvordan det fungerer:

  • Sundhedspleje
  • Medier & Underholdning
  • e-handel
  • Amazon Web Services
  • Optimering af skyomkostninger
  • Serverløs applikation
  • Detailhandel
  • Sundhedspleje - Banner
    • 100%HIPAA-kompatibel
    • 99,99% oppetidMaksimal Pålidelighed
  • Sundhedspleje - Banner
    • 10.000+Patientstøtte
    • Engagement 30%+Adaptiv UX

Seneste Artikler