Jan 22, 2024

Kickstarting test automation with Playwright

Unveiling the essentials of Playwright in this comprehensive introduction.

Welcome to an insightful exploration of Playwright – a powerful tool transforming the landscape of web automation and browser testing. In this blog, we embark on a journey to unravel the intricacies of Playwright, a cutting-edge open-source framework designed to simplify and enhance the process of browser automation. From its inception to its core features, we'll delve into the fundamentals that make Playwright a game-changer in the world of web development. Whether you're a seasoned developer seeking to optimize testing workflows or a curious newcomer eager to grasp the potential of this tool, join us as we navigate through a brief introduction to Playwright, unlocking the doors to a more efficient and robust web automation experience.

What the heck is Playwright 🤔?

Software testing is a critical phase in the software development life cycle, ensuring that applications meet specified requirements and function as intended. Playwright, an open-source automation framework developed by Microsoft, has become a valuable tool in the field of software testing. Here's a brief overview of how Playwright facilitates effective software testing

Playwright’s key features include Multi-Browser Support: Playwright supports multiple browsers, including Chromium, Firefox, and WebKit. This flexibility enables developers to test their applications across different browser engines, ensuring cross-browser compatibility.

Cross-Browser Page Automation: Playwright facilitates the automation of browser interactions across various pages, tabs, and frames. This capability proves invaluable for scenarios involving complex web applications with multiple components.

Device Emulation: Developers can emulate various devices and screen sizes, allowing them to test how their applications respond to different user environments. This feature is crucial for ensuring a seamless user experience across a diverse range of devices.

Parallel Execution: Playwright enables parallel test execution, enhancing efficiency by running tests concurrently. This feature accelerates the testing process and reduces overall execution time, especially in scenarios with large test suites.

Network Interception and Mocking: Playwright empowers developers to intercept network requests, modify responses, and mock network conditions. This proves invaluable for testing how applications handle different network scenarios and for isolating specific functionalities during testing.

Headless and Headful Mode: Playwright allows developers to run tests in both headless and headful modes. Headless mode is ideal for automated testing in server environments, while headful mode provides a visual representation of the browser, aiding in debugging and troubleshooting.

Capture Screenshots and Videos: Playwright makes it easy to capture screenshots and record videos during test execution. This feature is instrumental in visually validating test results and identifying issues in the application's user interface.

Intuitive API: Playwright boasts an intuitive and developer-friendly API, making it accessible to both beginners and experienced developers. The API design prioritizes simplicity and readability, enhancing the overall development and maintenance experience.

In summary, Playwright's rich set of features empowers developers to conduct thorough and efficient browser testing, ensuring the reliability and performance of web applications across diverse environments.

Setting Up Playwright

Before setting up Playwright, make sure you have the following prerequisites installed on your system:

1. Node.js and npm:

Playwright is a Node.js library, so you need to have Node.js installed. You can download it from the official website: Node.js Downloads (opens in a new tab)

npm (Node Package Manager) is usually installed along with Node.js. Ensure that npm is available on your system.

2. Supported Browsers:

Playwright supports multiple browsers (Chromium, Firefox, and WebKit). Depending on your needs, you might want to have one or more of these browsers installed on your machine.

For Chromium: Download and install it from the official website: Chromium (opens in a new tab)

For Firefox: Download and install it from the official website: Mozilla Firefox (opens in a new tab)

For WebKit: Currently, Playwright uses the version of WebKit that comes bundled with it, so no separate installation is required.

3. Operating System:

Playwright is compatible with Windows, macOS, and Linux. Ensure that your operating system is supported.

4. Python (Optional for WebKit on Linux):

If you are using Linux and plan to work with the WebKit browser, you might need to have Python 3.x installed. Playwright relies on Python for some dependencies on Linux systems.

Once you have these prerequisites in place, you can proceed with the installation and setup of Playwright by following the steps outlined in the "Setting Up Playwright" section in the previous response. Always refer to the official Playwright documentation for the most up-to-date information and any additional requirements: Playwright Documentation (opens in a new tab)

5. Install Playwright Get started by installing Playwright using npm , yarn or pnpm.

npm init playwright@latest

If you want to install Playwright with support for a specific browser, you can use:

## For Chromium
npm init playwright@latest playwright-chromium
 
## For Firefox
npm init playwright@latest playwright-firefox
 
## For WebKit
npm init playwright@latest playwright-webkit
 

6. Create a Test File: Structuring Your Playwright Tests for Success In the realm of Playwright testing, a crucial step is creating a dedicated test file to organize and execute your automated tests seamlessly. Crafting an efficient test file not only enhances the maintainability of your test suite but also contributes to a smoother testing workflow.

Create a new file (e.g., test.spec.js) where you'll write your Playwright tests. Here's a simple example:

const { test, expect } = require("@playwright/test");
 
test("Basic test example", async ({ page }) => {
  await page.goto("https://novu.co/");
  const title = await page.title();
  expect(title).toBe("Novu - The open-source notification infrastructure");
});

Best Practices for Writing Playwright Test Files:

Writing effective and maintainable Playwright test files involves following best practices to ensure the reliability and scalability of your test suite. Here are some best practices for writing Playwright test files:

Organize Test Cases:

  • Structure your test files logically, grouping them based on functionality or modules.

  • Use a naming convention that clearly identifies the purpose of each test file.

// test/authentication.test.js
 
describe("Authentication Tests", () => {
  // Test cases for login functionality
  it("should allow a user to login successfully", async () => {
    // Test implementation...
  });
 
  it("should display an error message for invalid credentials", async () => {
    // Test implementation...
  });
});

Use Descriptive Test Names:

  • Provide meaningful and descriptive names for your test cases. This makes it easier to understand the purpose of each test and helps in debugging.
it("should allow a user to login successfully", async () => {
  // Test implementation...
});
 
it("should display an error message for invalid credentials", async () => {
  // Test implementation...
});

Modularize Test Code:

  • Break down your tests into modular components or functions. This promotes code reuse and makes it easier to maintain and update your test suite.
// utils/authenticationUtils.js
 
async function loginUser(page, username, password) {
  // Implementation for login functionality...
}
 
module.exports = { loginUser };
// test/authentication.test.js
 
const { loginUser } = require("../utils/authenticationUtils");
 
it("should allow a user to login successfully", async () => {
  await loginUser(page, "validUsername", "validPassword");
  // Assertions...
});
 
it("should display an error message for invalid credentials", async () => {
  await loginUser(page, "invalidUsername", "invalidPassword");
  // Assertions...
});

Setup and Teardown:

  • Leverage the beforeAll, beforeEach, afterEach, and afterAll hooks for setup and teardown tasks.
  • Properly manage the browser context, ensuring a clean state before each test.
beforeAll(async () => {
  // Setup browser and context...
});
 
afterAll(async () => {
  // Teardown browser and context...
});

Parameterize Tests:

  • Parameterize your test cases to run with different sets of data. This helps maximize test coverage without duplicating code.
const credentials = [
  { username: "validUsername", password: "validPassword" },
  { username: "invalidUsername", password: "invalidPassword" },
];
 
it.each(credentials)(
  "should handle login with %s credentials",
  async (cred) => {
    await loginUser(page, cred.username, cred.password);
    // Assertions...
  },
);

Handle Asynchronous Operations:

  • Be mindful of Playwright's asynchronous nature. Utilize async and await to handle promises gracefully.
  • Use the built-in functions like waitFor, waitForSelector, and waitForTimeout for synchronization.
it("should allow a user to login successfully", async () => {
  await loginUser(page, "validUsername", "validPassword");
  await page.waitForSelector("#dashboard");
  // Assertions...
});

Use Page Objects:

  • Implement the Page Object Model (POM) to encapsulate the interaction with pages and components. This promotes code maintainability and reusability.
// pageObjects/LoginPage.js
 
class LoginPage {
  constructor(page) {
    this.page = page;
  }
 
  async login(username, password) {
    // Implementation for login functionality...
  }
 
  // Additional methods...
}
 
module.exports = LoginPage;
// test/authentication.test.js
 
const LoginPage = require("../pageObjects/LoginPage");
const loginPage = new LoginPage(page);
 
it("should allow a user to login successfully", async () => {
  await loginPage.login("validUsername", "validPassword");
  // Assertions...
});

Let's see some code in action 👀

Example 1: Open a browser and navigate to a website

// Importing the 'chromium' object from the 'playwright' library.
const { chromium } = require("playwright");
 
// Asynchronous function to launch a Chromium browser, navigate to a website, and then close the browser.
(async () => {
  // Launching a new Chromium browser instance.
  const browser = await chromium.launch();
 
  // Creating a new page within the browser.
  const page = await browser.newPage();
 
  // Navigating to the 'https://example.com' website.
  await page.goto("https://example.com");
 
  // Closing the Chromium browser.
  await browser.close();
})();

Example 2: Fill out a form and take a screenshot

const { chromium } = require("playwright");
 
(async () => {
  const browser = await chromium.launch();
  const page = await browser.newPage();
 
  await page.goto("https://example.com");
 
  // Fill out a form
  await page.fill('input[name="username"]', "your_username");
  await page.fill('input[name="password"]', "your_password");
 
  // Take a screenshot
  await page.screenshot({ path: "example.png" });
 
  await browser.close();
})();

Example 3: Clicking a button and handling navigation

const { chromium } = require("playwright");
 
(async () => {
  const browser = await chromium.launch();
  const page = await browser.newPage();
 
  await page.goto("https://example.com");
 
  // Click a button
  await page.click("button#submit-button");
 
  // Wait for navigation
  await page.waitForNavigation();
 
  // Verify the new page URL
  console.log(`Current URL: ${page.url()}`);
 
  await browser.close();
})();

Example 4: Evaluate page content

const { chromium } = require("playwright");
 
(async () => {
  const browser = await chromium.launch();
  const page = await browser.newPage();
 
  await page.goto("https://example.com");
 
  // Evaluate page content
  const title = await page.title();
  console.log(`Page title: ${title}`);
 
  const paragraphText = await page.$eval("p", (p) => p.textContent);
  console.log(`Paragraph text: ${paragraphText}`);
 
  await browser.close();
})();

Ugh! Enough of theoretical code 😵

Let's see some real action 🤩

Let's test text elements on the Novu Page. (Novu is opensource infrastructure for developers 🚨)

// Importing necessary functions and modules from Playwright test library
import test, { page, expect } from "@playwright/test";
import { describe } from "node:test";
 
// Defining a test suite with a description
describe("Nohu test ", () => {
  // Test case for "Get started button"
  test("Get started button", async ({ page }) => {
    // Navigating to the specified URL
    await page.goto("https://novu.co/");
 
    // Pausing the test execution for debugging purposes
    await page.pause();
 
    // Using expect to assert that a link with role "Get Started" exists and has the text "Get Started"
    await expect(
      page.getByRole("link", { name: "Get Started" }).nth(1),
    ).toHaveText("Get Started");
 
    // Checking if an element with text "Get Started" exists and clicking on it if it does
    if (await page.$("text=Get Started")) {
      await page.locator("text=Get Started").nth(1).click();
    }
  });
 
  // Test case for "Book a demo button"
  test("Book a demo button", async ({ page }) => {
    // Navigating to the specified URL
    await page.goto("https://novu.co/");
 
    // Pausing the test execution for debugging purposes
    await page.pause();
 
    // Checking if an element with text "star us" exists and clicking on it if it does
    if (await page.$("text=star us")) {
      await page.locator("text=star us").nth(1).click();
    }
 
    // Intentionally failing the test by asserting that a heading has the text "ABCD"
    // This line is marked to intentionally fail the test for demonstration purposes
    await expect(
      page.getByRole("heading", { name: "Used by innovative companies" }),
    ).toHaveText("ABCD");
  });
});
intro meme

Absolutely not! Mometic is your time-saving ally, ready to effortlessly tidy up this chaos for you. If you're interested in using AI to automate your E2E tests with no code, book a demo (opens in a new tab) with us!