Deep dive into Playwright
Introduction
Playwright is a powerful, open-source automation library for web applications, developed by Microsoft and launched in January 2020. It enables developers to write scripts that automate web browsers for a wide range of tasks, including testing, web scraping, and browser-based automation workflows.
Key Features
- Cross-Browser: Playwright supports Chromium, Firefox, and WebKit, ensuring consistent testing across all major browsers
- Cross-Platform: Works across Windows, macOS, and Linux, allowing seamless testing on any platform.
- Headless & Headed Modes: Run tests in headless (for speed) or headed (for visual debugging), offering flexibility for different use cases.
- Parallel Testing Execution: Supports running tests in parallel across multiple browsers and contexts, speeding up the overall test process.
- Browser Contexts: Isolated browser profiles (contexts) allow efficient testing of multiple scenarios within the same browser instance.
- Auto-Waiting: Built-in retries for interactions like clicks and navigation, reducing flaky tests.
- Network Interception: Allows mocking of network requests, intercepting responses, and simulating network conditions for more complex testing.
- Emulation: Can emulate mobile devices, screen sizes, and geolocation, enabling testing of responsive and location-based behavior.
- Test Isolation: Each test can be isolated within its own context or page, preventing cross-test interference.
- Modern Web Support: Handles features like WebSockets, Web Workers, and Service Workers for testing of modern apps.
- Visual Comparisons: Playwright supports capturing screenshots and comparing them against baseline images for visual regression testing.
- Tracing and Debugging: Playwright provides tools for tracing test execution, recording video, and generating logs, which help in debugging and identifying issues quickly.
Playwright’s architecture
It’s built around the following core components:
- Browser: This represents the entire browser (like Chromium, Firefox, or WebKit) running during the test. It’s the top-level entity that controls all the lower-level components.
- Browser Context: Contexts are like separate user profiles within the same browser. Each context runs as a separate session, with its own cookies, cache, and storage.
- Page: Like individual tabs or windows in the browser. Each page operates independently and can perform its own set of actions, such as navigating to URLs, clicking elements, or filling out forms.
Real example
Let see how to write an real example test on a simple Tic Tac Toe game
import { test, expect, chromium } from "@playwright/test";
test("Tic Tac Toe game play", async () => {
const player1Name = "Razvan";
const player2Name = "Cosmin";
// Launch the browser
const browser = await chromium.launch();
const page = await browser.newPage();
// Navigate to the game page
await page.goto("https://razvantimis.github.io/tic-tac-toe/");
// Start the game by entering player names
await page.fill("#name1", player1Name); // Fill Player 1's name
await page.fill("#name2", player2Name); // Fill Player 2's name
await page.getByRole("button", { name: "Confirm" }).click(); // Confirm names
// Wait for the names dialog to disappear
await page.waitForSelector(".names-dialog", { state: "hidden" });
// Function to simulate a player move
const makeMove = async (position: number, expectedText: string) => {
const cell = page.getByTestId(`game-cell-${position}`);
await cell.click(); // Player clicks the cell
await expect(cell).toHaveText(expectedText); // Verify move
};
// Player 1 makes their moves (X)
await makeMove(0, "X");
// Player 2 makes their move (O)
await makeMove(1, "O");
// Player 1 makes another move (X)
await makeMove(3, "X");
// Player 2 makes another move (O)
await makeMove(4, "O");
// Player 1 makes the last move to win (X)
await makeMove(6, "X");
// Check for the winning condition
await expect(page.locator(".result-dialog")).toBeVisible(); // Verify that the result dialog is visible
await expect(
page.getByRole("heading", { name: `${player1Name} Wins!` })
).toBeVisible(); // Verify win message
// Close the browser
await browser.close();
});
Selecting Elements
By following below order—focusing on accessibility first and then stability—you can create more robust and maintainable tests in Playwright.
page.getByRole(role, options)
: Targets elements by their ARIA role, enhancing accessibility in tests.
await page.getByRole("button", { name: "Confirm" }).click();
page.getByTestId(testId)
: Using a data-testid attribute for selecting elements in tests provides stability and clarity
await page.getByTestId(`game-cell-${position}`).click();
page.locator(selector)
: Selects elements using CSS selectors.
await expect(page.locator('.gamecell[data-position="0"]')).toHaveText("X");
Conclusion
Playwright is a game-changer in browser automation, offering a fast, flexible framework for complex web testing scenarios. With multi-browser support, parallel execution, and modern APIs, it’s an ideal choice for developers and QA engineers looking to create reliable and maintainable test suites.