As web applications evolve and grow in complexity, it becomes more and more important to ensure that their core functionalities work as intended across different browsers and platforms, providing a consistent experience for all end users. One of the approaches that Geckotech uses to validate that the code written is production-ready is end-to-end (E2E) testing.
Let's take one of our most recent use cases, for example: a registration onboarding flow. Like most onboarding flows, this one has multiple steps, forms, validations, an integration with a payment service provider, redirections and confirmations. The flow also adapts depending on the data being entered by the user. By the end of it, we also need to confirm in the back-office dashboard whether the user has been successfully onboarded.
It's a complex flow with a clear set of steps, a beginning and an end, making E2E testing perfect for validating it.
Great! But which of the many E2E frameworks available should we choose? Each one has its own features and particularities, pros and cons. We decided to explore our options. Let me walk you through our thought process.
After the initial round of research, where we considered multiple frameworks, the most important takeaway was that you need to define your own requirements for your particular project. No project is the same, so it is important to understand which features are not necessarily important, which are good-to-haves and which are essential. With this in mind, we managed to narrow it down to 2 candidates: Cypress and Playwright.
In general, both Cypress and Playwright match our requirements:
While both frameworks are solid choices, Playwright stands out for this project for the following three reasons:
As a bonus, it's always nice to check some "stats". Although these shouldn't be taken as sole motivation to pick a framework, they're good indicators:
How frequently the project is maintained: Playwrights issue resolution averages 3 days, while Cypress' averages 15 days;
The number of GitHub stars each project has (at this moment): Playwright has 51.4k â and Cypress has 43.4k â – even though Cypress is a few years older than Playwright;
Does Playwright live up to expectations? So far, the answer is yes. Setting up Playwright was easy, and its syntax feels familiar, especially with the Promise-based async/await approach. Debugging has been stress-free thanks to the built-in reporters, and the assertion API design resembles popular JS testing frameworks like Jest, making it intuitive to start writing tests:
test('has title', async ({page}) => {
await page.goto('https://playwright.dev/');
// Expect a title "to contain" a substring.
await expect(page).toHaveTitle(/Playwright/);
});
Although working with multiple browser contexts required some adjustment, we quickly developed helper functions to navigate through the possibilities. For instance, the `runOnNewPageContext` function opens a new browser context and executes an `actions` function that can perform whichever actions and assertions are needed:
export async function runOnNewPageContext(pageUrl, actions) {
const browser = await chromium.launch();
const context = await browser.newContext();
const newPage = await context.newPage();
await newPage.goto(pageUrl);
await actions(newPage);
await context.close();
await browser.close();
}
While we continue to experiment and learn more about Playwright, it has proven to be a solid choice in our case.