JetBase Logotyp
  • Hem
  • Blogg
  • Migrera Cypress-tester till Playwright med Copilot
Banner

Viktigaste punkterna

En migration från Cypress till Playwright behöver inte bli en högriskomskrivning. På en vårdplattform flyttades 148 E2E-tester gradvis medan Cypress förblev aktiv i CI, vilket bevarade release-täckningen under hela övergången. GitHub Copilot minskade repetitivt konverteringsarbete med 70–80%, men säker migration krävde fortfarande mänsklig granskning, isolerade ramverkskonfigurationer och fil för fil-validering.

• Bygg Playwright-prototypen på 1–2 dagar.
• Kör båda ramverken tills varje svit är stabil.
• Migrera stödjande filer före testfiler.
• Granska importer, fixtures, locatorer och påståenden manuellt.

När vi fick en begäran att migrera Cypress-tester till Playwright, förväntade vi oss en lång och tröttsam omskrivningsprocess.

Överraskande nog lyckades vi, med hjälp av GitHub Copilot, starta migreringen från Cypress till Playwright på bara ett par dagar — och hålla vår CI-pipeline igång hela tiden utan att avbryta några testprocesser.

I den här artikeln kommer jag att dela med mig av hur vi angrep denna migrering, de lärdomar vi drog längs vägen och hur AI-assisterad kodmigrering drastiskt kan minska den manuella belastningen vid ramövergångar.

1

Projektkontext

Projektet var en komplex hälso- och sjukvårdsplattform med mycket som pågick under ytan. Vår testkonfiguration inkluderade:

  • End-to-end (E2E) och integrationstester
  • En anpassad TAF-arkitektur med inställningar, nedmonteringar och skapande av enheter
  • Multi-miljökonfigurationer
  • Dynamiska data och djup navigationslogik

Totalt hade vi 148 E2E-tester som kördes på Cypress — allt fungerade bra, men organisationen ville standardisera QA-verktyg över team, vilket innebar en sak: Playwright-migrering.

2

Varför använda GitHub Copilot för migrering?

När migrationsbegäran kom såg jag en möjlighet att experimentera med GitHub Copilot för testautomatisering. Istället för att manuellt skriva om hundratals testfiler ville jag se hur långt vi kunde driva AI-assistans för att automatisera syntaxkonverteringen från Cypress till Playwright.

Och ärligt talat fungerade det mycket bättre än förväntat.

GitHub Copilot hanterade det mesta av den repetitiva översättningen (väljare, kommandon, asynkron hantering, etc.), vilket lät oss fokusera på justeringar av infrastrukturen och finjustering.

Inom 1–2 dagar hade vi redan en fungerande prototyp av Playwright-testautomatiseringsramverket.

3

Två viktiga förbehåll

Verifiera alltid AI-genererad kod

Även om AI-assisterad kodmigrering påskyndar saker och ting, måste du granska varje rad. Infrastruktursmigreringar kan lätt introducera subtila buggar eller prestandaförsämringar. Tänk på Copilot som din parprogrammerare, inte som en autopilot.

Håll det gamla ramverket igång till slutet

Blockera aldrig releaser eller regressioner under migreringen. Håll dina Cypress-tester igång på CI tills motsvarande sviter är helt stabila i Playwright. När en svit har migrerats och validerats, ta bort den från Cypress och byt CI för att köra den i Playwright.

Denna gradvisa utrullning säkerställer noll driftstopp och kontinuerlig testtäckning under hela processen.

4

Arbetsflöde för att migrera från Cypress till Playwright

När grunden var klar gick vi vidare till den praktiska migreringen.  
Här nedan är arbetsflödet som hjälpte oss att köra båda ramverken parallellt, upprätthålla CI-stabilitet och börja migrera tester stegvis — utan att blockera pågående releaser.

1. Initiera Playwright och skapa mappstrukturen

Det första steget var att initiera Playwright och skapa en ren, isolerad mappstruktur.

Vi ville att båda ramverken skulle leva sida vid sida i samma arkiv, så att vi kunde utföra dem samtidigt under övergången.

Den här uppsättningen gjorde att vi kunde:

  • Migrera gradvis
  • Jämföra resultat och tider mellan Cypress och Playwright
  • Hålla CI-pipelines igång för båda

Exempel på initiering:

Initialization example.webp

Här är den föreslagna mappstrukturen vi använde för 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. Konfigurera separata tsconfig-filer för varje ramverk

En av de tidiga problemen vi stod inför var TypeScript-konflikter — båda ramverken definierar liknande metodnamn (expect, request, osv.), och att dela en enda tsconfig.json ledde till kompilationsfel.

Lösningen var enkel: dela upp TypeScript-konfigurationerna. Denna struktur säkerställer att varje ramverk initierar sina egna typdefinitioner och undviker typkollisioner:

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

Huvud tsconfig.json
Lägg till composite-alternativet för att stödja projektreferenser.

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 denna uppdelning på plats kunde båda ramverken samexistera fredligt i ett arkiv — inga fler kompilator-konflikter och ingen risk för att av misstag initiera delade metoder två gånger.

3.

Skapa en prompt för att automatisera migrering med GitHub Copilot

När Playwright hade initierats och projektet strukturerats var det dags att låta GitHub Copilot hjälpa till med det tunga arbetet.

För att göra detta skapade vi en anpassad prompt som definierar hur Copilot ska bete sig när den skriver om tester från Cypress till Playwright. Prompten talar om för agenten vad den ska göra, hur den ska göra det och vad den ska ignorera — vilket ger konsekventa resultat över alla migreringar.

Hur man lägger till prompten

Inuti ditt GitHub-repo, öppna kugghjulsikonen ⚙️ i Copilot Chat och skapa en ny prompt.  
Filens namn kommer automatiskt att sparas under: ./github/prompts/

Du kan namnge den något i stil med migrate_tests.md.

Exempel på prompt:

---
mode: agent
---
Du är en Playwright Test Generator, en expert på webbläsarautomatisering och end-to-end-testning.
Din specialitet är att skapa robusta, tillförlitliga Playwright-tester som exakt simulerar användarinteraktioner och validerar applikationsbeteende.
Din uppgift är att hjälpa till att migrera befintliga Cypress-tester till Playwright-tester.
Cypress-tester, sidobjekt, komponenter och hjälpfiler ges som indata, och du behöver generera motsvarande Playwright-testkod.
Skriv ut ALL migrerad kod till chatten.
När du genererar Playwright-testkod eller några sidobjekt, se till att:
1. Teststrukturen följer samma struktur som Cypress-testerna.
2. Skapa en global fixture för setup och teardown och återanvänd den i testerna.
3. Alla användarinteraktioner (klick, skrivning, navigering) översätts noggrant till Playwright-syntax i sidobjekt och testfiler.
4. Påståenden i Cypress omvandlas till motsvarande Playwright-påståenden.
5. Ignorera nätverksövervakningen och stubbningen av Cypress-tester.
6. Kommentera ut alla metoder med väntetider (t.ex., cy.wait) i Playwright-koden.
7. Använd inte get-metoder i sidobjekt; använd direkta metoder istället `backbackItem = () => this.page.locator('[id="item_4_title_link"]');`

Varför detta hjälper

Denna typ av strukturerad prompt gör att GitHub Copilot beter sig mer som en specialiserad migrationsassistent, snarare än en allmänt använd kodgenerator.

Med rätt sammanhang och regler kan Copilot automatiskt:

  • Omskriva stora delar av Cypress-tester till Playwright-syntax
  • Behålla konsekvens i mapp- och teststruktur 
  • Minimera manuell konverteringstid med 70–80%

I grund och botten skapar du din egen AI-migreringsverktygslåda — skräddarsydd för din projekts struktur och konventioner.

4. Välj agentläge och kör migreringen steg för steg

När prompten var klar var nästa steg att faktiskt köra migreringen med GitHub Copilot i agentläge. I detta skede lät vi AI-modellen bearbeta varje fil — sidobjekt, komponenter, hjälpare och slutligen tester — en och en.

För den här uppgiften använde vi GPT-4.1-modellen, som levererar de mest konsekventa och kontextmedvetna kodtransformeringarna.

Hur man börjar migrera

1. Öppna Copilot Chat i VS Code

2. Använd / för att välja den promptfil du skapade tidigare

3. Använd # för att välja en specifik fil (till exempel ett Cypress-test eller en sidaobjekt) som du vill migrera

Copilot kommer nu att tillämpa din migrationsprompt och generera en Playwright-kompatibel version av filen direkt i chatten.

How to Start Migration.webpExempel på migration av inventoryPage sidobjekt

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().

Justera agentens beteende

Oroa dig inte om den första utdata inte är perfekt. Utifrån vår erfarenhet får AI-agenten vanligtvis 60–70 % av koden rätt vid första försöket. Nyckeln är att hålla samtalskontexten aktiv — fortsätt att förfina samma chattråd genom att be om korrigeringar eller justeringar. När du gör detta börjar Copilot att lära sig dina projektmönster och producerar mer exakt, återanvändbar kod.

I huvudsak, ju fler iterationer du gör i samma chatt, desto bättre blir migreringskvaliteten.

Migreringsordning: Filer först, sedan tester

För att hålla beroenden konsekventa och undvika saknade referenser, följ denna ordning:

1. Generera icke-testfiler först:

  • Sidobjekt
  • Komponenter
  • Hjälpfiler
  • Konstanter

2. När alla stödjande filer är genererade och verifierade, lägg till #app-mappen i chattkontexten, och migrera sedan testfilerna själva.

Verifieringssteg

När ett Playwright-test genereras:

1. Granska koden — bekräfta att sidlokatorer, teststeg och påståenden är korrekta.

2. Kör testet med din Playwright CLI för att säkerställa att det körs korrekt.

3. Åtgärda mindre syntax- eller fixture-mismatcher om Copilot misstog ett Cypress-kommando.

Genom att verifiera efter varje fil håller du migreringen stabil och stegvis, vilket undviker storskalig felsökning senare.

Exempel på migrerat inventoryPage-test som framgångsrikt passerar:

```html 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("Användaren ska lägga till en vara i kundvagnen", 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("Användaren ska ta bort en vara från kundvagnen", 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/); // Borde inte ha någon nummertext }); test("Användaren ska lägga till flera varor i kundvagnen", 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. Slutlig mappstruktur efter migreringen

När migreringen var färdig nådde vår repository ett stabilt, dubbelt ramverksläge — helt fungerande både Cypress och Playwright sida vid sida. Denna struktur gjorde det möjligt för oss att:

  • Gradvis avveckla Cypress testsviter så snart de ersattes
  • Hålla CI/CD-pipelines operativa för båda ramverken
  • Upprätthålla en ren och modulär arkitektur

Nedan är den slutliga strukturen efter fullbordad migreringsarbetsflöde.

Slutlig mappstruktur

``````plaintext github/ │ ├── prompts/ │ └── workflows/ ├── cypress/ │ ├── app/ │ ├── downloads/ │ ├── e2e/ │ ├── fixtures/ │ ├── screenshots/ │ ├── support/ │ └── videos/ ├── playwright/ │ ├── app/ │ ├── constants/ │ ├── helpers/ │ ├── reports/ │ ├── test-results/ │ └── tests/

Noteringar om strukturen

  • .github/prompts/ — innehåller dina Copilot-migrationskommandon. Att hålla dem versionerade gör att du kan uppdatera eller återanvända dem för framtida ramverksmigrationer eller refaktoreringar.
  • .github/workflows/ — innehåller dina CI/CD-definitioner. Du kan köra både Playwright- och Cypress-jobb parallellt tills den gamla ramverket är helt avvecklat.
  • playwright/ mapp — fungerar nu som den primära automatiseringskällan framöver. Den speglar strukturen för den tidigare Cypress-implementationen för att underlätta onboarding och säkerställa konsekvens.
  • tsconfig.playwright.json och tsconfig.cypress.json — förblir separerade för full typisolering, vilket förhindrar konflikter under byggen.

Denna struktur stödde inte bara en smidig övergång utan positionerade också projektet för framtida skalbarhet, CI-flexibilitet och modulärt testägande över teamen.

 
Planerar du en migration från Cypress till Playwright?

Flytta din testsvit utan att störa releaser eller förlora täckning. Våra QA-ingenjörer kan hjälpa dig att planera migreringen, anpassa din automatiseringsarkitektur och hålla båda ramverken stabila under övergången.

5

Praktiska råd & Lärdomar

Efter att ha migrerat nästan 150 tester med Copilot och Playwright, här är några viktiga lärdomar och riktiga tips som gjorde processen smidigare (och räddade oss från en del huvudvärk).

Allmän AI-relaterad rådgivning

  • AI ljuger — ofta övertygande.  

Verifiera alltid varje rad kod som AI:n genererar. Lita aldrig blint på den, särskilt under infrastrukturmigreringar.

  • Håll dig till konsekventa namngivningskonventioner.

Behåll identiska variabel- och metodnamn över ramverken — det hjälper AI-agenten att migrera kod mer noggrant och gör det enklare för dig att hitta och importera dem senare.

Allmän AI-relaterad rådgivning.webp

  • Återskapa importer manuellt.

Copilot tenderar att förstöra importvägar. Det är ofta snabbare att ta bort dem och återimportera manuellt, eller ställa in globala importer som: import x from "playwright/foo/bar";

  • Återanvänd samma chatt för alla migrationer. ```

Håll dig till en enda Copilot-chattråd — den bygger kontext och "kommer ihåg" dina projektkonventioner, vilket leder till bättre resultat.

  • De komplicerade migrationsuppgifterna.  

Generera 1–2 filer åt gången. Mindre uppgifter ger mer exakta resultat och gör manuell validering enklare.

Playwright-specifika råd

  • Skapa aldrig flera instanser av samma Page Object utan behov.

Att göra det kan orsaka inkonsekvent tillstånd eller brutna väljare när man navigerar mellan sidor. Lösningen? Implementera en Page Manager som håller alla sidobjekt tillgängliga genom en enda instans.

Här är ett minimalt exempel på uppsättning:

// 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("Användaren ska logga in med giltiga uppgifter", async ({ pageManager }) => {
    await pageManager.loginPage.clickLoginButton();
  });

Andra tekniska tips

  • Ta bort alla "get"-prefix från locatorer som AI-agenten genererar — använd direkta locator-metoder istället.
  • Glöm inte att konfigurera dotenv för miljövariabler och autentiseringsuppgifter.
  • Anpassa din Playwright-konfiguration för att outputa alla rapporter under Playwright-mappen, så att din projektrot förblir ren:
reporter: [["html", { open: "never", outputFolder: ".‌/playwright/reports/" }]],
  outputDir: ".‌/playwright/test-results",
6

Efterord

Jag inkluderade inte ESLint-uppsättningen här eftersom den varierar från projekt till projekt.  
Det enda universella rådet jag kan ge är att installera Playwright ESLint-plugin för bättre regler: eslint-plugin-playwright.

Om du vill utforska ett komplett fungerande exempel på denna migration — inklusive promptfiler, tsconfigs och CI-uppsättning — kan du kolla in det fullständiga arkivet här: Repo exempel.

 
Redo för att modernisera din testautomatisering?

Oavsett om du migrerar från Cypress, återbygger en instabil testsvit eller förbättrar din QA-automatisering, kan JetBase hjälpa dig att göra övergången med mindre manuellt arbete och lägre leveransrisk.

Kommentarer

Logga in för att lämna en kommentar
Fortsätt med GoogleFortsätt med Google
Modern

Våra Fall

Innovation handlar inte bara om idéer - det handlar om utförande, att förvandla vision till verklighet och skapa lösningar som verkligen gör intryck. Se vad vi har byggt och hur det fungerar:

  • Vård
  • Media och Underhållning
  • e-handel
  • Amazon Web Services
  • Molnkostnadsoptimering
  • Serverlös applikation
  • Detaljhandel

Senaste Artiklarna