The Complete Playwright Cheatsheet

Dec 21, 2023 ยท 7 min read

Overview

Playwright is a Node.js library for cross-browser end-to-end testing. It enables reliable testing across Chromium, Firefox and WebKit.

// Install Playwright
npm i -D @playwright/test

Key Features

  • Cross-browser testing: Chromium, Firefox, WebKit
  • Network layer (mocking/stubbing requests and responses)
  • CPU throttling, Device emulation
  • Screenshots, Videos, Trace Viewer
  • Core Concepts

    Browser Types

    Playwright supports 3 browser types - chromium, firefox and webkit. Browser instances can be created as:

    const { chromium } = require('playwright');
    
    const browser = await chromium.launch();
    

    Browser Contexts

    Browser contexts isolates browser state like cookies, storage etc. New context guarantees clean state.

    const context = await browser.newContext();
    

    Pages

    Pages represent tabs and hold the actual page state. New pages open fresh empty tabs.

    const page = await context.newPage();
    

    Basic Examples

    Navigate to page

    await page.goto('<https://www.example.com>');
    

    Get page title

    await page.title();
    

    Click element

    await page.click('button');
    

    Type text

    await page.fill('input', 'text');
    

    Assertions

    // Assertion helpers
    expect(page.url()).toBe('<https://example.com>');
    await expect(page.locator('h1')).toHaveText('Title');
    

    Screenshot

    await page.screenshot({ path: 'screenshot.png' });
    

    Advanced Interactions

    Clicking Elements

    Options like click count, button type etc.:

    await page.click('#submit', { clickCount: 2 });
    await page.click('#checkbox', { button: 'right' });
    

    Typing Text

    Handle delays while typing, useful for UI/UX testing:

    await page.type('#address', 'Hello World', { delay: 100 });
    

    Element States

    Force element states before interacting:

    await page.focus('#email');
    await page.check('#checkbox');
    

    Selector Strategies

    Playwright offers different selector engines to query elements:

    CSS Selector

    await page.click('button');
    

    Text Selector

    Selects elements based on inner text

    await page.click('text=Login');
    

    XPath Selector

    Full XPath support

    await page.click('//button[text()="Login"]');
    

    ID Selector

    Select element by ID attribute

    await page.click('#login-button');
    

    Data Test ID

    Custom test id attributes for unique selection

    await page.click('[data-testid="submit-form"]');
    

    By Role

    Semantic selector by element role

    await page.click('.role-button');
    

    Advanced Element Selectors

    Pass selector functions to customize selection:

    await page.locator(({ hasText }) => hasText('Save')).click();
    

    DOM Path:

    await page.getByTestId('email-id', { path: 'form div' });
    

    Select visible elements:

    await page.getByText('Save', { exact: true, visible: true });
    

    Advanced Usage

    Configure Browser Settings

    Settings like viewport size, user agent etc. can be configured for browsers using browserType.launch()

    await chromium.launch({
      headless: false,
      slowMo: 50,
      viewport: {width: 1280, height: 720}
    });
    

    Intercept Network Requests

    Network requests can be mocked and stubbed for testing using route handlers.

    await context.route('**/*.{png,jpg}', route => {
      route.abort();
    });
    

    This aborts all image requests.

    Emulate Devices

    Playwright allows emulation of devices like iPhone, iPad etc.

    const context = await browser.newContext({
      ...devices['iPhone X']
    });
    

    Local Storage

    Handle browser storage (localStorage, sessionStorage)

    await context.storageState({path: 'state.json'}); // save storage state
    await context.storageState({path: 'state.json'}); // restore state
    

    Multi-Browser Testing

    Run same tests across Chromium, Firefox and WebKit using test runner.

    npm test // runs tests over all 3 browsers
    

    Docker Images

    Playwright provides official docker images with browsers installed. This removes need for browser drivers on CI.

    docker pull mcr.microsoft.com/playwright:v1.24.0-focal
    

    Tracing Viewer

    Playwright captures browser traces during test execution which helps debug tests.

    npx playwright show-trace trace.zip
    

    Additional Assertions

    Element State

    Assert element states like disabled, visible etc.

    await expect(page.locator('button')).toBeDisabled();
    

    Visual Comparison

    Compare screenshots to baseline images

    await expect(page.screenshot()).toMatchSnapshot('landing.png');
    

    Wait Helpers

    Wait For Selector

    Wait until selector is available before performing action

    await page.waitForSelector('div.loaded');
    

    Wait For Navigation

    Wait for navigation to finish before asserting page state

    await page.waitForNavigation();
    

    Authentication

    Persist Credentials

    Use context storage state to persist login sessions

    await context.storageState({path: 'state.json'});
    

    Reporting

    Playwright Cloud

    Upload test results and artifacts to Playwright Cloud

    npm test --project=myCloudProject
    

    Dynamic Mock Response

    Return different mock data based on request:

    await context.route('**/*.json', route => {
      if (route.request().url().includes('data')) {
        route.fulfill({
          status: 200,
          body: JSON.stringify({data: 'mock'})
        });
      } else {
        route.abort();
      }
    });
    

    GraphQL Mocking

    Stub GraphQL API response with dummy data:

    await context.route('<https://api.graph.cool/simple/v1/movies>', route => {
        route.fulfill({
            status: 200,
            contentType: 'application/json',
            body: JSON.stringify({data: {movies: ['Movie 1']}})
        });
    });
    

    Devices and Emulation

    Emulating various mobile devices:

    // iPhone XR
    await context.emulate(devices['iPhone XR']);
    
    // Google Pixel 5
    await context.emulate(devices['Pixel 5']);
    

    Device specific viewports:

    await context.emulateViewport(1920, 1080); // Full HD
    await context.emulateViewport(360, 640); // iPhone 5/SE
    

    Assertions & Validation

    Element count assertion:

    await expect(page.locator('.items')).toHaveCount(5);
    

    Validate JS expression:

    await page.waitForFunction(() => window.innerWidth < 1000);
    

    Assert response times:

    await expect(page).toRespondIn(50); // ms
    

    Browser Context Sharing

    You can share data between browser contexts using the browserContext.storageState() method. This can be useful for scenarios where you want to reuse cookies or authentication tokens between different contexts.

    // Saving browser context storage state
    const storageState = await context.storageState({ path: 'auth.json' });
    
    // Create a new browser context and restore storage state
    const newContext = await browser.newContext();
    await newContext.addCookies(storageState.cookies);
    await newContext.clearCookies(); // If needed, clear cookies before adding
    await newContext.addCookies(storageState.cookies);
    

    Element Hover and Scroll

    You can hover over an element using the hover() method, and you can scroll to an element using the scrollIntoView() method.

    // Hover over an element
    await page.hover('#element-to-hover');
    
    // Scroll to an element
    await page.$eval('#element-to-scroll-to', (element) => {
      element.scrollIntoView();
    });
    

    File Upload and Download

    To interact with file upload buttons, you can use the input.uploadFile() method. To handle file downloads, you can use the browserContext.waitForEvent('download') method.

    // Upload a file
    await page.setInputFiles('#file-input', 'path/to/file.txt');
    
    // Handle file downloads
    const [download] = await Promise.all([
      context.waitForEvent('download'),
      page.click('#download-button'),
    ]);
    await download.saveAs('path/to/save/file.txt');
    

    Working with Frames and iframes

    You can interact with frames and iframes using the frame() method.

    // Switch to a frame by name or ID
    const frame = page.frame('frameName');
    await frame.click('#element-in-frame');
    
    // Switch back to the main frame
    await page.waitForLoadState('domcontentloaded');
    

    Headless Mode

    You can run Playwright tests in headless mode by configuring the headless option when launching the browser.

    await chromium.launch({ headless: true });
    

    Page Events

    You can listen for and handle various page events using the page.on() method.

    page.on('dialog', async (dialog) => {
      console.log('Dialog message:', dialog.message());
      await dialog.accept();
    });
    
    page.on('console', (message) => {
      console.log('Console message:', message.text());
    });
    

    Error Handling

    Use try-catch blocks to handle errors that may occur during test execution.

    try {
      // Perform actions that may throw errors
    } catch (error) {
      console.error('An error occurred:', error.message);
    }
    

    Page Navigation Strategies

    You can navigate back and forward in the browser's history using the goBack() and goForward() methods.

    await page.goBack(); // Navigate back
    await page.goForward(); // Navigate forward
    

    Parallel Testing

    To run tests in parallel, you can leverage Playwright's built-in test runner.

    npx playwright test --workers 4
    

    Custom Test Configuration

    Set up custom test configurations for different environments using Playwright's configuration files.

    // playwright.config.js
    module.exports = {
      projects: [
        {
          name: 'dev',
          use: { ... },
        },
        {
          name: 'prod',
          use: { ... },
        },
      ],
    };
    

    Page Objects

    Implement the page object pattern to separate page interactions from test code.

    // Example page object
    class LoginPage {
      constructor(page) {
        this.page = page;
      }
    
      async login(username, password) {
        // Implement login logic
      }
    }
    

    Test Structure

    Follow a clear test structure that includes setup, execution, and teardown phases. Use before and after hooks to handle common setup and cleanup tasks.

    // Example using Jest hooks
    beforeEach(async () => {
      // Perform common setup steps here
      await page.goto('<https://example.com>');
    });
    
    afterEach(async () => {
      // Perform common cleanup tasks here
    });
    
    test('Test case description', async () => {
      // Test execution code
    });
    

    Timing Issues

    Ensure that your tests handle asynchronous operations correctly. Use await to wait for elements to become available, and consider using waitForSelector or waitForFunction when necessary.

    // Wait for an element to become visible
    await page.waitForSelector('.my-element', { state: 'visible' });
    

    Unhandled Errors

    Always include error handling in your tests to catch and handle exceptions gracefully. Use try-catch blocks to capture errors and provide informative error messages.

    try {
      // Test actions that may throw errors
    } catch (error) {
      console.error('An error occurred:', error.message);
    }
    

    Measuring Page Load Time

    You can measure the time it takes for a page to load using the page.goto method along with the performance.timing API.

    const startTime = Date.now();
    await page.goto('<https://example.com>');
    const loadTime = Date.now() - startTime;
    console.log(`Page loaded in ${loadTime}ms`);
    

    Network Throttling

    Playwright allows you to simulate different network conditions, such as slow 3G or offline mode, to test how your application behaves under varying network speeds.

    // Simulate slow 3G network
    await context.route('**/*', (route) => {
      route.throttle('Regular3G');
      route.continue();
    });
    

    Analyzing Performance Metrics

    You can gather various performance metrics using the page.metrics() method to assess the performance of your web application.

    await page.goto('<https://example.com>');
    const metrics = await page.metrics();
    console.log('Performance metrics:', metrics);
    

    Browse by tags:

    Browse by language:

    The easiest way to do Web Scraping

    Get HTML from any page with a simple API call. We handle proxy rotation, browser identities, automatic retries, CAPTCHAs, JavaScript rendering, etc automatically for you


    Try ProxiesAPI for free

    curl "http://api.proxiesapi.com/?key=API_KEY&url=https://example.com"

    <!doctype html>
    <html>
    <head>
        <title>Example Domain</title>
        <meta charset="utf-8" />
        <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
    ...

    X

    Don't leave just yet!

    Enter your email below to claim your free API key: