Exploring Playwright: A Comprehensive Guide to Web Testing and Automation

Introducing Playwright: A Brief Overview
Playwright, developed by Microsoft, is an open-source Node.js library that provides a high-level API for automating browsers. It offers cross-browser support for Chromium, Firefox, and WebKit, making it versatile for testing and automation across various web environments. Unlike some other automation tools, Playwright operates on multiple platforms, including Windows, macOS, and Linux.
The hallmark feature of Playwright is its capability to run headless browser instances, which enables testing without the need for a visible browser window. This not only speeds up the testing process but also ensures the accuracy of results by eliminating any potential interference from the user interface. In this article, we will delve into Playwright's capabilities, its advantages, and provide code snippets to demonstrate its practical usage for web testing and automation.
In this blog, we will cover basics of Playwright, Its features and how to perform Google Search and Github authentication from different browsers.
Key Advantages of Playwright
Multi-Browser Support: Playwright supports multiple browsers out of the box, enabling developers to perform cross-browser testing efficiently. This is crucial for ensuring consistent behavior across different browser engines.
Headless and Headful Modes: Playwright's headless mode allows for running tests without displaying the graphical user interface of the browser, while the headful mode provides a visible browser window for debugging and validation.
Concurrency: Playwright utilizes a unique architecture that allows for parallel execution of tests, significantly reducing the overall testing time. This is particularly useful for large test suites.
Automation and Record & Replay: Playwright offers powerful automation capabilities for interacting with web pages programmatically. Additionally, its "Record & Replay" functionality assists in generating code snippets by recording user interactions.
Web Testing and UI Interactions: Playwright excels in simulating user interactions, such as clicking, typing, scrolling, and more. This makes it an ideal choice for testing complex user interfaces.
Network Interception: Playwright enables developers to intercept and modify network requests, which is invaluable for testing scenarios that involve network requests.
Responsive Design Testing: With Playwright, developers can easily test how web applications respond to different screen sizes and orientations, aiding in creating responsive designs.
Getting Started
To begin using Playwright, you'll first need to install it using npm (Node Package Manager):
npm install playwright
Once installed, you can use the Playwright API to control browsers, perform actions, and make assertions. Here's a basic example of launching a browser and navigating to a website:
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://www.example.com');
// Perform actions and assertions here
await browser.close();
})();
Page Interactions
Playwright simplifies user interactions with a webpage using expressive methods. Each BrowserContext can have multiple pages. A Page refers to a single tab or a popup window within a browser context. It should be used to navigate to URLs and interact with the page content.
For instance, to fill out a form and submit it, you can use:
await page.fill('input[name=username]', 'myUsername');
await page.fill('input[name=password]', 'myPassword');
await page.click('button[type=submit]');
You can also use below code for authentication. Below code is more verbose.
const page = await browser.newPage();
await page.goto('/signup');
await page.getByLabel('username').fill('myUsername');
await page.getByLabel('password').fill('myPassword');
await page.getByText('submit').click();
You can also simulate keyboard inputs, mouse actions, and more, providing a comprehensive solution for testing complex user interactions.
Taking Screenshots and Recording Videos
Visual testing is crucial to ensure that a web application's UI remains consistent. Playwright makes this easy with functions to take screenshots and record videos of your tests:
await page.screenshot({ path: 'screenshot.png' });
await page.video.startRecording({ path: 'video.mp4' });
// Perform actions
await page.video.stopRecording();
Comparing Screenshots
You can compare the screenshot of pages using the below code.
const screenshot1 = await page.screenshot();
const screenshot2 = await page.goto('https://www.example.com/updated-page').then(() => page.screenshot());
const isSame = screenshot1.equals(screenshot2);
console.log(`Screenshots are the same: ${isSame}`);
Handling Navigation and URLs
Navigating through a website and managing URLs is fundamental to web automation. Playwright allows you to navigate, go back and forward, and even intercept and modify requests:
await page.goto('https://www.example.com');
await page.goBack();
await page.goForward();
// Intercept network requests
page.route('**/*', route => {
route.continue();
});
Assertions and Testing
Playwright integrates seamlessly with popular testing frameworks like Jest and Mocha. You can make assertions to verify the correctness of your web application using these frameworks:
const { test, expect } = require('@playwright/test');
test('Check title of the page', async ({ page }) => {
await page.goto('https://www.example.com');
const title = await page.title();
expect(title).toBe('Example Domain');
});
Parallel Execution
Modern web applications require tests to be executed across different environments quickly. Playwright supports parallel test execution, which can significantly reduce test suite execution times:
npx playwright test --workers 4
Using Test Fixtures for Shared Context
Playwright Test is based on the concept of test fixtures. Test fixtures are used to establish environment for each test, giving the test everything it needs and nothing else. Test fixtures are isolated between tests. With fixtures, you can group tests based on their meaning, instead of their common setup.
const { test, expect } = require('@playwright/test');
test.describe('Login', () => {
let page;
test.beforeEach(async ({ browser }) => {
const context = await browser.newContext();
page = await context.newPage();
});
test('Successful login', async () => {
await page.goto('https://www.example.com/login');
// Perform login and assertions
});
test('Failed login', async () => {
await page.goto('https://www.example.com/login');
// Perform failed login and assertions
});
});
Example: Google Search
In this example, we'll perform a Google search using Playwright in both Chrome and Firefox browsers.
const { chromium, firefox } = require('playwright');
(async () => {
const query = 'Playwright browser automation';
// Perform Google search in Chrome
const chromeBrowser = await chromium.launch();
const chromePage = await chromeBrowser.newPage();
await chromePage.goto('https://www.google.com');
await chromePage.getByLabel('Search').fill(query);
await chromePage.press('Enter');
await chromePage.waitForSelector('h3');
const chromeTitle = await chromePage.title();
console.log(`Chrome search title: ${chromeTitle}`);
await chromePage.screenshot({ path: 'chrome_google_search.png' });
await chromeBrowser.close();
// Perform Google search in Firefox
const firefoxBrowser = await firefox.launch();
const firefoxPage = await firefoxBrowser.newPage();
await firefoxPage.goto('https://www.google.com');
await firefoxPage.getByLabel('Search').fill(query);
await firefoxPage.press('Enter');
await firefoxPage.waitForSelector('h3');
const firefoxTitle = await firefoxPage.title();
console.log(`Firefox search title: ${firefoxTitle}`);
await firefoxPage.screenshot({ path: 'firefox_google_search.png' });
await firefoxBrowser.close();
})();
Example: Github Login
In this example, we'll log into a Github account using Playwright in both Chrome and Firefox browsers.
const { chromium, firefox } = require('playwright');
(async () => {
const account = {
username: 'your_username',
password: 'your_password',
};
// Log into GitHub in Chrome
const chromeBrowser = await chromium.launch();
const chromePage = await chromeBrowser.newPage();
await chromePage.goto('https://github.com/login');
await chromePage.getByLabel('Username or email address').fill(account.username);
await chromePage.getByLabel('Password').fill(account.password);
await chromePage.click('input[type=submit]');
await chromePage.waitForNavigation();
await chromePage.screenshot({ path: 'chrome_github_login.png' });
await chromeBrowser.close();
// Log into GitHub in Firefox
const firefoxBrowser = await firefox.launch();
const firefoxPage = await firefoxBrowser.newPage();
await firefoxPage.goto('https://github.com/login');
await firefoxPage.getByLabel('Username or email address').fill(account.username);
await firefoxPage.getByLabel('Password').fill(account.password);
await firefoxPage.click('input[type=submit]');
await firefoxPage.waitForNavigation();
await firefoxPage.screenshot({ path: 'firefox_github_login.png' });
await firefoxBrowser.close();
})();
Conclusion
Playwright has rapidly gained traction in the realm of web testing and automation, thanks to its powerful capabilities and cross-browser support.In this article we covered the importance of playwright, page interactions, taking screenshots and recordings, comparing those screenshots, handling navigations and urls, asserting and testing, also we learned how parallel execution works with playwright, last but not the least we have added using test fixtures for shared context. With Playwright, the world of web testing is at your fingertips. Happy Coding!
Source code available in Github.