Playwright E2E Tests: Actions, Assertions, Hooks
Learn Playwright E2E testing. Write first test, actions, async assertions, test isolation, leverage hooks for reliable web automation!
This guide provides a practical overview of writing tests with Playwright, focusing on core concepts, actions, assertions, and test organization.
Introduction
Playwright tests are designed for simplicity and reliability. They perform actions on web pages and assert expected states. Playwright automatically handles waiting for elements to become actionable and for assertions to eventually pass, eliminating the need for manual waits and reducing test flakiness.
Getting Started: Your First Test
Playwright tests are typically written in TypeScript or JavaScript. A basic test involves navigating to a URL and performing assertions.
// tests/example.spec.ts
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/);
});
test('get started link', async ({ page }) => {
await page.goto('https://playwright.dev/');
// Click the "Get started" link using its role and name.
await page.getByRole('link', { name: 'Get started' }).click();
// Expects the page to have a heading with the name "Installation".
await expect(page.getByRole('heading', { name: 'Installation' })).toBeVisible();
});
Note: When using JavaScript in VS Code, add // @ts-check at the start of each test file to enable automatic type checking.
Performing Actions
Most tests begin with navigation and then interact with page elements.
Navigation
Use page.goto() to navigate to a URL. Playwright waits for the page to reach the load state before proceeding.
await page.goto('https://playwright.dev/');
Interactions
Interacting with elements starts by locating them using Playwright's Locators API. Locators provide a robust way to find elements on the page. Playwright automatically waits for elements to become actionable (e.g., visible, enabled) before performing an action, so you don't need to add explicit waits.
// Create a locator for the "Get started" link.
const getStartedLink = page.getByRole('link', { name: 'Get started' });
// Click the located element.
await getStartedLink.click();
Often, this can be condensed into a single line:
await page.getByRole('link', { name: 'Get started' }).click();
Basic Actions
Here are some common Playwright actions:
| Action | Description |
|---|---|
locator.check() |
Check a checkbox |
locator.click() |
Click an element |
locator.uncheck() |
Uncheck a checkbox |
locator.hover() |
Hover mouse over an element |
locator.fill() |
Fill a form field with text |
locator.focus() |
Focus an element |
locator.press() |
Press a single key |
locator.setInputFiles() |
Pick files for upload |
locator.selectOption() |
Select an option in a dropdown |
Using Assertions
Playwright includes test assertions via the expect function. Call expect(value) and use a matcher to define your expectation.
Playwright offers async matchers that wait for a condition to be met, making tests non-flaky.
// This assertion waits until the page title contains "Playwright".
await expect(page).toHaveTitle(/Playwright/);
Popular Async Assertions
| Assertion | Description |
|---|---|
expect(locator).toBeChecked() |
Checkbox is checked |
expect(locator).toBeEnabled() |
Control is enabled |
expect(locator).toBeVisible() |
Element is visible |
expect(locator).toContainText() |
Element contains specific text |
expect(locator).toHaveAttribute() |
Element has a specific attribute |
expect(locator).toHaveCount() |
List of elements has a given length |
expect(locator).toHaveText() |
Element matches text (exact or regex) |
expect(locator).toHaveValue() |
Input element has a specific value |
expect(page).toHaveTitle() |
Page has a specific title (exact or regex) |
expect(page).toHaveURL() |
Page has a specific URL (exact or regex) |
Playwright also includes generic matchers like toEqual, toContain, and toBeTruthy for immediate synchronous checks. These do not require await.
// Synchronous assertion.
expect(success).toBeTruthy();
Test Isolation
Playwright Test ensures strong isolation between tests. Each test receives a fresh environment, thanks to the page fixture which belongs to an isolated BrowserContext. A BrowserContext is equivalent to a brand new browser profile, preventing test interference.
// tests/example.spec.ts
import { test } from '@playwright/test';
test('example test', async ({ page }) => {
// "page" here is isolated for this specific test.
});
test('another test', async ({ page }) => {
// "page" in this second test is completely isolated from the first test.
});
Using Test Hooks
Playwright provides various test hooks to organize and manage test execution.
-
test.describe(name, callback): Groups related tests. -
test.beforeEach(callback): Runs before each test in the currentdescribeblock. -
test.afterEach(callback): Runs after each test in the currentdescribeblock. -
test.beforeAll(callback): Runs once before all tests in the currentdescribeblock. -
test.afterAll(callback): Runs once after all tests in the currentdescribeblock.
// tests/example.spec.ts
import { test, expect } from '@playwright/test';
test.describe('navigation', () => {
// Navigate to the starting URL before each test in this group.
test.beforeEach(async ({ page }) => {
await page.goto('https://playwright.dev/');
});
test('main navigation', async ({ page }) => {
// This test starts at 'https://playwright.dev/' due to beforeEach.
await expect(page).toHaveURL('https://playwright.dev/');
});
test('navigate to docs', async ({ page }) => {
// This test also starts at 'https://playwright.dev/'.
await page.getByRole('link', { name: 'Docs' }).click();
await expect(page).toHaveURL(/.*docs/);
});
});
Top comments (0)