Playwright Locators, Actions, and Assertions
Introduction
Stable tests depend on stable locators. Playwright encourages locators that mirror how a person perceives the page, such as roles, labels, and visible text, and it automatically waits for elements to be ready before acting. This lesson covers locators, common actions, and assertions.
Prerequisites
- A Playwright project (see the setup lesson)
- Basic HTML knowledge
Step-by-Step Guide
Step 1: Prefer user-facing locators
getByRole is usually the best first choice because it matches how assistive technology sees the page. Use getByLabel for form fields, getByPlaceholder, getByText, and getByTestId when no accessible option exists.
page.getByRole('button', { name: 'Sign in' });
page.getByLabel('Email');
page.getByPlaceholder('What needs to be done?');
page.getByText('Welcome back');
page.getByTestId('todo-item');Step 2: Narrow down with chaining and filters
When several elements match, scope the locator to a container or filter by text so each test targets exactly one element.
const row = page.getByRole('listitem').filter({ hasText: 'Buy milk' });
await row.getByRole('checkbox').check();Step 3: Perform actions
Actions such as click and fill automatically wait until the element is visible, stable, and enabled, so you rarely need manual waits.
await page.goto('https://demo.playwright.dev/todomvc');
const input = page.getByPlaceholder('What needs to be done?');
await input.fill('Buy milk');
await input.press('Enter');
await page.getByRole('link', { name: 'Completed' }).click();Step 4: Use web-first assertions
Assertions on locators and pages retry until they pass or time out. Prefer them over reading a value and comparing it yourself.
await expect(page.getByTestId('todo-title')).toHaveText(['Buy milk']);
await expect(page.getByTestId('todo-item')).toHaveCount(1);
await expect(page).toHaveURL(/completed/);
await expect(page.getByRole('heading')).toBeVisible();Step 5: Avoid fixed waits
Calling page.waitForTimeout slows tests and still flakes. Wait for a meaningful condition instead, such as an assertion or a response.
// Avoid
await page.waitForTimeout(3000);
// Prefer
await expect(page.getByText('Saved')).toBeVisible();FAQs
- Why are CSS and XPath selectors discouraged?
- They are tied to page structure and styling, so small markup changes break tests. Role, label, and text locators survive refactors and also encourage accessible markup.
- What is auto-waiting?
- Before an action, Playwright checks that the element is attached, visible, stable, and enabled, and retries until it is or the timeout expires. This removes most hand-written waits.
Summary
Choose role and label locators first, rely on auto-waiting actions, and assert with web-first matchers. Together these remove most of the flakiness people associate with UI tests.
Comments
Log in or create a free account to join the discussion.