Skip to main content
This guide walks you through creating and running your first Playwright test. By the end, you’ll understand the basics of writing tests and interacting with web pages.

Prerequisites

Make sure you have installed Playwright before proceeding.

Create your first test

1

Create a test file

Create a new file called example.spec.ts in your tests/ directory:
import { test, expect } from '@playwright/test';

test('has title', async ({ page }) => {
  await page.goto('https://playwright.dev/');

  // Expect a title "to contain" a substring.
  await expect(page).toHaveTitle(/Playwright/);
});
This test navigates to the Playwright homepage and verifies the page title contains “Playwright”.
2

Run the test

Execute your test using the Playwright Test runner:
npx playwright test
By default, tests run in headless mode across all configured browsers.
3

View results

After the test completes, view the HTML report:
npx playwright show-report
The report shows test results, execution time, and any failures.

Running tests in different modes

Default mode - browsers run without a UI:
npx playwright test

Real-world examples

Here are practical examples from the Playwright repository demonstrating common testing patterns.

Example 1: Taking screenshots

Navigate to a page and capture a screenshot:
import { test } from '@playwright/test';

test('Page Screenshot', async ({ page }) => {
  await page.goto('https://playwright.dev/');
  await page.screenshot({ path: `example.png` });
});

Example 2: Interacting with forms

Fill out a form and submit it:
import { test, expect } from '@playwright/test';

test('should add single todo', async ({ page }) => {
  await page.goto('https://demo.playwright.dev/todomvc');

  // Type into the input field
  await page.getByRole('textbox', { name: 'What needs to be done?' })
    .fill('Buy groceries');

  // Verify the text appears
  await expect(page.getByRole('textbox', { name: 'What needs to be done?' }))
    .toHaveValue('Buy groceries');

  // Submit by pressing Enter
  await page.keyboard.press('Enter');

  // Verify the todo appears in the list
  await expect(page.getByText('Buy groceries')).toBeVisible();
  await expect(page.getByText('1 item left')).toBeVisible();
});

Example 3: Mobile emulation

Test mobile viewports with device emulation:
import { test, devices } from '@playwright/test';

test.use({
  ...devices['iPhone 13 Pro'],
  locale: 'en-US',
  geolocation: { longitude: 12.492507, latitude: 41.889938 },
  permissions: ['geolocation'],
})

test('Mobile and geolocation', async ({ page }) => {
  await page.goto('https://maps.google.com');
  await page.getByText('Your location').click();
  await page.waitForRequest(/.*preview\/pwa/);
  await page.screenshot({ path: 'colosseum-iphone.png' });
});

Example 4: Evaluating JavaScript

Execute code in the browser context:
import { test } from '@playwright/test';

test('Evaluate in browser context', async ({ page }) => {
  await page.goto('https://www.example.com/');
  const dimensions = await page.evaluate(() => {
    return {
      width: document.documentElement.clientWidth,
      height: document.documentElement.clientHeight,
      deviceScaleFactor: window.devicePixelRatio
    }
  });
  console.log(dimensions);
});

Example 5: Network interception

Intercept and log network requests:
import { test } from '@playwright/test';

test('Intercept network requests', async ({ page }) => {
  // Log and continue all network requests
  await page.route('**', route => {
    console.log(route.request().url());
    route.continue();
  });
  await page.goto('http://todomvc.com');
});

Running specific tests

npx playwright test example.spec.ts

Understanding test anatomy

Every Playwright test follows this structure:
import { test, expect } from '@playwright/test';

test('test description', async ({ page }) => {
  // 1. Setup - navigate to page
  await page.goto('https://example.com');

  // 2. Action - interact with elements
  await page.getByRole('button', { name: 'Submit' }).click();

  // 3. Assertion - verify expected behavior
  await expect(page.getByText('Success')).toBeVisible();
});
Auto-waiting: Playwright automatically waits for elements to be actionable before performing actions. This eliminates the need for manual timeouts and makes tests more reliable.

Common CLI commands

Run all tests

npx playwright test

Run with UI

npx playwright test --ui

Generate code

npx playwright codegen

Show report

npx playwright show-report

Debugging tests

1

Add a breakpoint

Use await page.pause() to pause execution:
test('debug example', async ({ page }) => {
  await page.goto('https://example.com');
  await page.pause(); // Execution pauses here
  await page.getByRole('button').click();
});
2

Run in debug mode

npx playwright test --debug
This opens the Playwright Inspector with:
  • Ability to step through test actions
  • Pick locator tool
  • Console for running commands
  • Source code view
The Playwright Inspector allows you to step through your test, explore locators, and execute commands in real-time.

Next steps

Writing tests

Learn best practices for writing tests

Configuration

Configure test runner options

Locators

Master element selection strategies

Assertions

Understand web-first assertions

Tips for getting started

Run npx playwright codegen example.com to record browser interactions and generate test code automatically. This is a great way to learn Playwright’s API.
When writing tests, use --headed mode to see what’s happening. Switch to headless mode for CI/CD.
Install the Playwright Test extension for VS Code to run tests directly from the editor with debugging support.
Common pitfall: Don’t forget await before Playwright actions. All Playwright methods are asynchronous and return Promises.

Build docs developers (and LLMs) love