Playwright Assertions: Complete Reference Guide
Learn to use Playwright web-first assertions. Review locator assertions, page assertions, API response checks, and custom expect matches.
playwright-v1-49-matrix
Playwright Assertions: Complete Guide
Assertions validate that application states match your expectations. Playwright uses web-first assertions that automatically retry checks until conditions are met. This guide outlines how to build robust assertions.
Introduction
In legacy automation frameworks, assertions failed if the page did not load fast enough. Developers wrote manual sleep lines to avoid test flakiness. Playwright resolves this by introducing dynamic auto-waiting assertions.
These assertions continuously query the browser DOM. They check if the element has reached the expected state within a defined timeout window.
Web-First Auto-Retrying Assertion Model
Unlike static checks, web-first assertions are built directly into Playwright's locator library. They retry the condition until it passes or the timeout expires:
graph TD
TriggerAssert["Call: expect(locator).toBeVisible()"] --> CheckDOM["Query DOM state"]
CheckDOM --> IsTargetState{"Matches Expected State?"}
IsTargetState -->Yes
TestPasses["Test Continues (Pass)"]
IsTargetState -->No
CheckTimeout{"Timeout Reached?"}
CheckTimeout -->No
WaitShort["Wait (100ms)"]
WaitShort --> CheckDOM
CheckTimeout -->Yes
TestFails["Test Fails (Timeout Error)"]Assertion Lifecycle Sequence
The internal execution of a retrying assertion follows this lifecycle sequence:
sequenceDiagram
participant Runner as Test Runner
participant Expect as Expect Matcher
participant DOM as Browser DOM
Runner->>Expect: expect(locator).toHaveText("Success")
loop Every 100ms
Expect->>DOM: Read text content of locator
DOM-->>Expect: "Loading..." (no match)
Expect->>Expect: Keep retrying
end
Expect->>DOM: Read text content of locator
DOM-->>Expect: "Success" (match)
Expect-->>Runner: Assertion passesLocator Assertions Reference
Use these locator assertions to inspect UI elements.
1. Assert Visibility and Hidden States
Verify that elements are visible to the end user:
import { test, expect } from '@playwright/test';
test('should display success dialog elements', async ({ page }) => {
await page.goto('/checkout');
await page.getByRole('button', { name: 'Submit Order' }).click();
// Verify alert container is visible
const successAlert = page.getByRole('alert');
await expect(successAlert).toBeVisible({ timeout: 10000 });
// Verify login spinner is hidden
const spinner = page.getByTestId('spinner');
await expect(spinner).toBeHidden();
});2. Assert Inputs and Attributes
Inspect form inputs and HTML attributes:
import { test, expect } from '@playwright/test';
test('should validate profile form state', async ({ page }) => {
await page.goto('/settings/profile');
// Assert input has correct filled value
const emailInput = page.getByLabel('Email Address');
await expect(emailInput).toHaveValue('user@playwrightpad.info');
// Assert checkbox is checked
const checkbox = page.getByLabel('Subscribe to alerts');
await expect(checkbox).toBeChecked();
});3. Assert Text Content and CSS Classes
Validate user interface labels and styling classes:
import { test, expect } from '@playwright/test';
test('should verify task listings', async ({ page }) => {
await page.goto('/tasks');
// Assert container text contains specific values
const list = page.getByRole('list');
await expect(list).toContainText('Buy milk');
// Assert classes exist on element
const header = page.getByRole('heading', { name: 'Tasks List' });
await expect(header).toHaveClass(/theme-dark/);
});Page and API Assertions Reference
Verify browser page parameters and API response status codes:
import { test, expect } from '@playwright/test';
test('should verify navigation and api status', async ({ page, request }) => {
await page.goto('/dashboard');
// Verify correct URL address matches
await expect(page).toHaveURL(/.*dashboard/);
// Verify tab title matches pattern
await expect(page).toHaveTitle(/Dashboard | PlaywrightPad/);
// Perform API response check
const response = await request.get('/api/health');
expect(response.ok()).toBe(true);
});Comparison: Standard vs Web-First Assertions
The table below contrasts standard Jest/Node assertions with Playwright web-first assertions.
| Feature Area | Standard Assertion (toBe) | Playwright Web-First (toBeVisible) |
|---|---|---|
| DOM Auto-Waiting | No (evaluates immediately) | Yes (retries query continuously) |
| Timeout Configuration | Default test timeout | Configurable per assertion (e.g. timeout: 5000) |
| Error Messages | Generates raw value mismatch logs | Exposes locator path and wait histories |
| DOM Snapshot Checks | Fast (checks in-memory state) | Safe (runs in actual browser engine) |
| Flakiness Risk | High (susceptible to render latency) | Low (awaits page settling) |
Best Practices for Test Verification
Here are a few key practices:
playwright.config.ts (e.g. expect: { timeout: 5000 }).Common Mistakes to Avoid
expect(await page.isVisible('button')).toBe(false). This does not wait for the button to disappear.| Bad Pattern | Recommended Alternative |
expect(await locator.innerText()).toBe('Save') | await expect(locator).toHaveText('Save') |
await page.waitForTimeout(2000) | Auto-waiting assertions with expect |
| Checking multiple states inside single string match | Break assertions into separate locator checks |
Frequently Asked Questions
What is the default timeout for assertions?
The default expectation timeout is 5 seconds, which can be modified inside the projects configuration file.
What is a soft assertion?
Soft assertions (expect.soft()) compile failure logs without stopping test execution. This allows other steps to run.
How do I write custom assertion error messages?
Pass a custom message string as the second parameter inside the expect wrapper (e.g. expect(locator, 'Button should be active').toBeVisible()).
Does expect support negative assertions?
Yes. Prepend the selector with the not matcher (e.g., await expect(locator).not.toBeVisible()).
Can I verify CSS styles like background colors?
Yes. Use the toHaveCSS matcher to inspect styles (e.g. await expect(button).toHaveCSS('background-color', 'rgb(0, 0, 0)')).
How do I check if an input is editable?
Validate input write permissions using the toBeEditable() matcher.
Does toHaveURL wait for redirection?
Yes. It continuously checks the page URL until it matches the expected URL pattern within the timeout.
How do I assert file upload inputs?
Verify file inputs using locator selectors combined with the toHaveValue() matcher.
Can I run assertions on elements inside iframes?
Yes. Target the iframe locator context first, and then perform expect assertions on internal selectors.
How does expect handle hidden elements?
Matchees check CSS visibility, display, and opacity parameters to determine visibility state.
Summary
Web-first assertions decrease flakiness by verifying states dynamically. Relying on auto-retrying matchers stabilizes pipelines across different network conditions.
Related Articles
About The Author
PlaywrightPad Editorial reports on Chromium engines, E2E test optimizations, and AI integration specifications.
Newsletter
Get weekly browser reports sent directly to your inbox.