JetBase-logo
Banner

Belangrijkste punten

Een migratie van Cypress naar Playwright hoeft geen hoog-risico herschrijving te worden. Op een gezondheidsplatform werden 148 E2E-tests geleidelijk verplaatst terwijl Cypress actief bleef in CI, waardoor de release-dekking gedurende de overgang behouden bleef. GitHub Copilot verminderde repetitieve conversiewerkzaamheden met 70–80%, maar een veilige migratie vereiste nog steeds menselijke beoordeling, geïsoleerde frameworkconfiguraties en bestandsgewijze validatie.

• Bouw het Playwright-prototype in 1–2 dagen.
• Voer beide frameworks uit totdat elke suite stabiel is.
• Migreer ondersteunende bestanden voordat testbestanden.
• Controleer imports, fixtures, locaties en assertions handmatig.

Toen we een verzoek kregen om Cypress-tests naar Playwright te migreren, verwachtten we een lang, vervelend herschrijvingsproces.

Verassend genoeg lukte het ons met de hulp van GitHub Copilot om de migratie van Cypress naar Playwright in slechts een paar dagen te starten — en om onze CI-pijplijn de hele tijd draaiende te houden zonder de testprocessen te onderbreken.

In dit artikel deel ik hoe we deze migratie hebben aangepakt, de lessen die we onderweg hebben geleerd en hoe AI-ondersteunde code-migratie de handmatige belasting van framework-overgangen drastisch kan verminderen.

1

Projectcontext

Het project was een complex gezondheidszorgplatform met veel dat zich onder de motorkap afspeelt. Onze testopstelling omvatte:

  • Eind-tot-eind (E2E) en integratietests
  • Een aangepaste TAF-architectuur met opstellingen, afbrekingen en entiteitscreatie
  • Multi-omgeving configuraties
  • Dynamische gegevens en diepe navigatielogica

In totaal hadden we 148 E2E-tests die op Cypress draaiden — allemaal werkten ze prima, maar de organisatie wilde de QA-tooling standaardiseren over teams heen, wat één ding betekende: migratie naar Playwright.

2

Waarom GitHub Copilot gebruiken voor migratie?

Toen het verzoek voor migratie binnenkwam, zag ik een kans om te experimenteren met testautomatisering van GitHub Copilot. In plaats van handmatig honderden testbestanden te herschrijven, wilde ik zien hoe ver we AI-ondersteuning konden benutten om syntaxisconversie van Cypress naar Playwright te automatiseren.

En eerlijk gezegd, het werkte veel beter dan verwacht.

GitHub Copilot handelde het meeste van de repetitieve vertaling (selectoren, commando's, async-handling, etc.), waardoor we ons konden concentreren op infrastructuuraanpassingen en het verfijnen.

Binnen 1–2 dagen hadden we al een werkend prototype van het Playwright-testautomatiseringsframework.

3

Twee Belangrijke Disclaimer

Controleer Altijd AI-gegenereerde Code

Ook al versnelt AI-ondersteunde code-migratie dingen, je moet elke regel controleren. Infrastructuurmigraties kunnen gemakkelijk subtiele bugs of prestatie-regressies introduceren. Beschouw Copilot als je parenprogrammeur, niet als een autopiloot.

Houd het Oude Framework Draaien Tot het Einde

Blokkeer nooit releases of regressies tijdens de migratie. Houd je Cypress-tests draaiende op CI totdat de bijbehorende suites volledig stabiel zijn in Playwright. Zodra een suite is gemigreerd en gevalideerd, verwijder deze dan uit Cypress en wijzig CI om deze in Playwright te laten draaien.

Deze geleidelijke uitrol zorgt voor geen downtime en voortdurende testdekking gedurende het proces.

4

Workflow om te Migreren van Cypress naar Playwright

Toen de basis duidelijk was, gingen we over op de hands-on migratie.  
Hieronder staat de workflow die ons hielp beide frameworks parallel te draaien, de CI-stabiliteit te handhaven en tests geleidelijk te migreren — zonder lopende releases te blokkeren.

1. Initialiseer Playwright en Maak de Mapstructuur aan

De eerste stap was om Playwright te initialiseren en een schone, geïsoleerde mapstructuur te creëren.We wilden dat beide frameworks naast elkaar in dezelfde repository konden leven, zodat we ze gelijktijdig tijdens de overgang konden uitvoeren.

Die opstelling stelde ons in staat om:

  • G geleidelijk te migreren
  • Resultaten en tijden tussen Cypress en Playwright te vergelijken
  • CI-pijplijnen voor beide draaiende te houden

Initiëlexample:

Initialization example.webp

Hier is de voorgestelde mappenstructuur die we voor Playwright hebben gebruikt:

├── 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. Configureer aparte tsconfig bestanden voor elk framework

Een van de vroege problemen waarmee we geconfronteerd werden, waren TypeScript-conflicten — beide frameworks definiëren vergelijkbare methodenamen (expect, request, enz.), en het delen van een enkele tsconfig.json leidde tot compilatiefouten.

De oplossing was eenvoudig: splits de TypeScript-configuraties. Deze structuur zorgt ervoor dat elk framework zijn eigen type-definities initialiseert en type-collisions voorkomt:

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

Hoofd tsconfig.json
Voeg de composite optie toe ter ondersteuning van projectreferenties.

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"]
}

Met deze scheiding konden beide frameworks vreedzaam in één repo coëxisteren — geen compilerconflicten meer en geen risico op per ongeluk het twee keer initialiseren van gedeelde methoden.

3.

Maak een prompt om migratie te automatiseren met GitHub Copilot

Nadat Playwright was geïnitialiseerd en het project was gestructureerd, was het tijd om GitHub Copilot te laten helpen met het zware werk.

Om dit te doen, hebben we een aangepaste prompt gemaakt die definieert hoe Copilot zich moet gedragen bij het herschrijven van tests van Cypress naar Playwright. De prompt vertelt de agent wat te doen, hoe het te doen en wat te negeren — wat zorgt voor consistente resultaten bij alle migraties.

Hoe de prompt toe te voegen

Open binnen je GitHub-repository het tandwielpictogram ⚙️ in Copilot Chat en maak een nieuwe prompt aan.  
Het bestand wordt automatisch opgeslagen onder: ./github/prompts/

Je kunt het iets noemen als migrate_tests.md.

Voorbeeld van de prompt:

---
mode: agent
---
Je bent een Playwright Test Generator, een expert in browserautomatisering en end-to-end testen.
Jouw specialiteit is het creëren van robuuste, betrouwbare Playwright-tests die gebruikersinteracties nauwkeurig simuleren en het gedrag van de applicatie valideren.
Jouw taak is om bestaande Cypress-tests naar Playwright-tests te migreren.
De Cypress-tests, paginaobjecten, componenten en hulpprogramma-bestanden worden als invoer geleverd, en jij moet gelijkwaardige Playwright-testcode genereren.
Geef ALLE gemigreerde code in de chat.
Bij het genereren van de Playwright-testcode of paginaobjecten, zorg ervoor dat:
1. De teststructuur dezelfde structuur volgt als de Cypress-tests.
2. Maak een globale fixture voor setup en teardown en herbruik deze in de tests.
3. Alle gebruikersinteracties (klikken, typen, navigeren) nauwkeurig worden vertaald naar Playwright-syntaxis in paginaobjecten en testbestanden.
4. Asserties in Cypress worden omgezet naar gelijkwaardige Playwright-asserties.
5. Negeer de netwerkmethoden en stobbingsonderdelen van de Cypress-tests.
6. Commenteer alle methoden met wachttijden (bijv. cy.wait) in de Playwright-code uit.
7. Gebruik geen get-methoden in paginaobjecten; gebruik in plaats daarvan directe methoden `backbackItem = () => this.page.locator('[id="item_4_title_link"]');`

Waarom dit helpt

Deze gestructureerde prompt stelt GitHub Copilot in staat om meer te functioneren als een gespecialiseerde migratie-assistent, niet als een algemene codegenerator.

Met de juiste context en regels kan Copilot automatisch:

  • Grote delen van Cypress-tests herschrijven naar Playwright-syntaxis
  • De consistentie van map- en teststructuur behouden 
  • De handmatige conversietijd met 70–80% verminderen

Uiteindelijk maak je je eigen AI-migratietoolchain — afgestemd op de structuur en conventies van je project.

4. Selecteer de agentmodus en voer de migratie stap voor stap uit

Toen de prompt klaar was, was de volgende stap om de migratie daadwerkelijk uit te voeren met GitHub Copilot in agentmodus. In deze fase lieten we het AI-model elk bestand verwerken — paginaobjecten, componenten, hulpprogramma's en uiteindelijk de tests — één voor één.

Voor deze taak hebben we het GPT-4.1-model gebruikt, dat de meest consistente en contextbewuste code-transformaties levert.

Hoe te beginnen met migratie

1. Open Copilot Chat in VS Code

2. Gebruik / om het promptbestand te selecteren dat je eerder hebt gemaakt

3. Gebruik # om een specifiek bestand te selecteren (bijvoorbeeld een Cypress-test of paginacomponent) dat je wilt migreren

Copilot zal nu je migratieprompt toepassen en een Playwright-compatibele versie van het bestand rechtstreeks in de chat genereren.

How to Start Migration.webpVoorbeeld van migratie van de inventoryPage Pagina Component

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

Het Gedrag van de Agent Afstemmen

Maak je geen zorgen als de eerste output niet perfect is. Uit onze ervaring krijgt de AI-agent meestal 60–70% van de code goed bij de eerste poging. De sleutel is om de gesprekscontext actief te houden — blijf dezelfde chatthread verfijnen door te vragen om fixes of aanpassingen. Naarmate je dit doet, begint Copilot je projectpatronen te leren en produceert het nauwkeurigere, herbruikbare code.

In wezen geldt: hoe meer iteraties je in dezelfde chat doet, des te beter de migratiekwaliteit wordt.

Migratievolgorde: Bestanden Eerst, Dan Tests

Om afhankelijkheden consistent te houden en ontbrekende referenties te vermijden, volg deze volgorde:

1. Genereer eerst niet-testbestanden:

  • Pagina-objecten
  • Componenten
  • Hulpprogrammabestanden
  • Constanten

2. Zodra alle ondersteunende bestanden zijn gegenereerd en geverifieerd, voeg je de #app map toe aan de chatcontext en migreer je de testbestanden zelf.

Verificatiestap

Wanneer een Playwright-test wordt gegenereerd:

1. Bekijk de code — bevestig dat pagina-locators, teststappen en assertions correct zijn.

2. Voer de test uit met je Playwright CLI om ervoor te zorgen dat deze correct wordt uitgevoerd.

3. Corrigeer kleine syntaxis of fixture-onjuistheden als Copilot een Cypress-opdracht verkeerd heeft begrepen.

Door na elk bestand te verifiëren, houd je de migratie stabiel en incrementeel, zodat je latere grootschalige debugging kunt vermijden.

Voorbeeld van een gemigreerde inventoryPage test die met succes slaagt:

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("De gebruiker moet een item aan de kaart toevoegen", () => {
    inventoryPage.item.itemByName("Fiets Licht").should("have.text", itemsNames.bikeLight);
    inventoryPage.item.addToCartByName("Fiets Licht");
    inventoryPage.assertCartLogoItems(1);
  });
  it("De gebruiker moet een item van de kaart verwijderen", () => {
    inventoryPage.backbackItem().should("have.text", itemsNames.backpackItemName);
    inventoryPage.clickBackbackAddItemButton();
    inventoryPage.assertCartLogoItems(1);
    inventoryPage.clickBackbackRemoveItemButton();
    inventoryPage.shoppingCartLogo().should("not.have.text");
  });
  it("De gebruiker moet meerdere items aan de kaart toevoegen", () => {
    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. Final Repository Structure After Migration

Zodra de migratie voltooid was, bereikte onze repository een stabiele, duale-framework status — volledig draaiend met zowel Cypress als Playwright naast elkaar. Deze structuur stelde ons in staat om:

  • G geleidelijk Cypress-testreeksen af te schalen naarmate ze werden vervangen
  • CI/CD-pijplijnen operationeel te houden voor beide frameworks
  • Een schone en modulaire architectuur te onderhouden

Hieronder staat de uiteindelijke structuur na het voltooien van de migratieworkflow.

Uiteindelijke Mappenstructuur

├── .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/

Notities over de Structuur

  • .github/prompts/ — bevat je Copilot migratie prompts. Door deze versiebeheer toe te passen, kun je ze bijwerken of hergebruiken voor toekomstige framework migraties of refactors.
  • .github/workflows/ — houdt je CI/CD definities vast. Je kunt zowel Playwright als Cypress jobs parallel uitvoeren tot de volledige afschaffing van het oude framework.
  • playwright/ map — fungeert nu als de primaire automatiseringsbron voortaan. Het weerspiegelt de structuur van de vorige Cypress implementatie om de onboarding te vergemakkelijken en consistentie te waarborgen.
  • tsconfig.playwright.json en tsconfig.cypress.json — blijven gescheiden voor volledige type-isolatie, om conflicten tijdens builds te voorkomen.

Deze structuur heeft niet alleen een soepele overgang ondersteund, maar ook het project gepositioneerd voor toekomstige schaalbaarheid, CI-flexibiliteit en modulaire test-eigendom over teams heen.

 
Plan je een migratie van Cypress naar Playwright?

Verplaats je test suite zonder releases te verstoren of dekking te verliezen. Onze QA-ingenieurs kunnen je helpen de migratie te plannen, je automatiseringsarchitectuur aan te passen en beide frameworks stabiel te houden tijdens de overgang.

5

Praktisch Advies & Lessen Geleerd

Na de migratie van bijna 150 tests met Copilot en Playwright, hier zijn een paar belangrijke lessen en praktische tips die het proces soepeler hebben gemaakt (en ons hebben bespaard van een paar hoofdpijn).

Algemene AI-Gerelateerde Adviezen

  • AI liegt — vaak overtuigend.  

Verifieer altijd elke regel code die de AI genereert. Vertrouw het nooit blindelings, vooral niet tijdens infrastructuur migraties.

  • Houd je aan consistente naamgevingsconventies.

Houd identieke variabele en methodenamen over de frameworks heen — dit helpt de AI Agent om de code nauwkeuriger te migreren en maakt het eenvoudiger voor jou om ze later te vinden en te importeren.

Algemene AI-Gerelateerde Adviezen.webp

  • Herbouw imports handmatig.

Copilot heeft de neiging om importpaden in de war te sturen. Het is vaak sneller om ze te verwijderen en handmatig opnieuw te importeren, of om globale imports in te stellen zoals: import x from "playwright/foo/bar";

  • Herbruik dezelfde chat voor alle migraties.

Blijf bij één enkele Copilot-chatthread — het bouwt context op en "herinnert" zich jouw projectconventies, wat leidt tot betere resultaten.

  • Decomposeer migratietaken.  

Genereer 1–2 bestanden tegelijk. Kleinere taken leveren nauwkeurigere uitkomsten op en maken handmatige validatie gemakkelijker.

Specifieke Adviezen voor Playwright

  • Maak nooit meerdere instanties van hetzelfde Page Object zonder noodzaak.

Dit kan inconsistente staat of gebroken selectoren veroorzaken bij het navigeren tussen pagina's. De oplossing? Implementeer een Page Manager die alle pagina-objecten toegankelijk houdt via één enkele instantie.

Hier is een minimalistisch voorbeeldopstelling:

// 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("De gebruiker zou in moeten loggen met geldige gegevens", async ({ pageManager }) => {
    await pageManager.loginPage.clickLoginButton();
  });

Andere Technische Tips

  • Verwijder alle "get" prefixen van locators die de AI Agent genereert — gebruik in plaats daarvan directe locatormethoden.
  • Vergeet niet om dotenv te configureren voor omgevingsvariabelen en inloggegevens.
  • Pas je Playwright-configuratie aan om alle rapporten onder de Playwright-map uit te voeren, zodat je projectroot schoon blijft:
reporter: [["html", { open: "never", outputFolder: ".‌/playwright/reports/" }]],
  outputDir: ".‌/playwright/test-results",
6

Eindwoord

Ik heb de setup van ESLint hier niet opgenomen omdat dit per project verschilt.  
De enige algemene aanbeveling die ik kan doen, is om de Playwright ESLint-plugin te installeren voor betere regelhandhaving: eslint-plugin-playwright.

Als je een compleet werkend voorbeeld van deze migratie wilt verkennen — inclusief promptbestanden, tsconfigs en CI-opstelling — kun je de volledige repository hier bekijken: Repo voorbeeld.

 
Klaar om uw testautomatisering te moderniseren?

Of u nu migreert van Cypress, een onbetrouwbare test-suite opnieuw opbouwt of uw QA-automatisering verbetert, JetBase kan u helpen de overgang te maken met minder handmatig werk en een lager leveringsrisico.

Opmerkingen

Log in om een opmerking achter te laten
Doorgaan met GoogleDoorgaan met Google
Modern

Onze cases

Innovatie gaat niet alleen over ideeën - het gaat over uitvoering, het omzetten van visie in realiteit en het creëren van oplossingen die echt impact maken. Bekijk wat we hebben gebouwd en hoe het werkt:

  • Gezondheidszorg
  • Media & Entertainment
  • eCommerce
  • Amazon Web Services
  • Cloud Kostenoptimalisatie
  • Serverless Applicatie
  • Detailhandel

Laatste artikelen