Assertions
Use Playwright's built-in web-first assertions to check visibility, text, URLs, counts, attributes, and CSS properties.
Web-First Assertions
Playwright's expect() function provides web-first assertions that automatically retry until the expected condition is met or a timeout elapses. This is fundamentally different from a plain assert statement, which evaluates the condition only once at the moment of execution. Web-first assertions eliminate entire categories of flakiness caused by timing issues.
playwright.config.ts via expect: { timeout: 10000 }, or per-assertion by passing { timeout: 15000 } as an option.Common Assertion Methods
The most frequently used assertions are toBeVisible(), toBeHidden(), toHaveText(), toContainText(), toHaveValue(), toBeChecked(), toHaveURL(), toHaveTitle(), toHaveCount(), and toHaveAttribute(). All of them support negation with .not, giving you a complete vocabulary for both positive and negative assertions.
Soft Assertions
By default, a failed assertion immediately stops the test. Soft assertions accumulate all failures and only report them at the end, allowing you to see all problems in one run. Use expect.soft() (JavaScript) inside a single test to verify multiple independent properties without short-circuiting on the first failure. This is particularly useful for visual checks of a complex page.
| Assertion | Checks |
|---|---|
| toBeVisible() | Element is in the DOM and visible |
| toHaveText(str) | Element's text matches exactly or by regex |
| toContainText(str) | Element's text includes substring |
| toHaveURL(str) | Current page URL matches |
| toHaveCount(n) | Locator matches exactly n elements |
| toHaveAttribute(k,v) | Element has attribute with value |
| toHaveCSS(prop,val) | Computed CSS property equals value |
import { test, expect } from '@playwright/test';
test('assertion showcase', async ({ page }) => {
await page.goto('/dashboard');
// Visibility
await expect(page.getByRole('heading')).toBeVisible();
await expect(page.getByTestId('spinner')).toBeHidden();
// Text content
await expect(page.getByRole('heading')).toHaveText('Dashboard');
await expect(page.getByTestId('summary')).toContainText('42 items');
// URL and title
await expect(page).toHaveURL('/dashboard');
await expect(page).toHaveTitle(/Dashboard/);
// Count of matching elements
await expect(page.getByRole('listitem')).toHaveCount(5);
// Attribute
await expect(page.getByRole('link', { name: 'Profile' }))
.toHaveAttribute('href', '/profile');
// CSS property
await expect(page.getByTestId('status-badge'))
.toHaveCSS('background-color', 'rgb(34, 197, 94)');
// Soft assertions — collect all failures
await expect.soft(page.getByTestId('revenue')).toContainText('$');
await expect.soft(page.getByTestId('users')).toContainText('users');
// Negation
await expect(page.getByText('Error')).not.toBeVisible();
});
import com.microsoft.playwright.*;
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
import java.util.regex.Pattern;
class AssertionsTest {
void assertionShowcase(Page page) {
page.navigate("http://localhost:3000/dashboard");
// Visibility
assertThat(page.getByRole(AriaRole.HEADING)).isVisible();
assertThat(page.getByTestId("spinner")).isHidden();
// Text content
assertThat(page.getByRole(AriaRole.HEADING))
.hasText("Dashboard");
assertThat(page.getByTestId("summary"))
.containsText("42 items");
// URL and title
assertThat(page).hasURL("/dashboard");
assertThat(page).hasTitle(Pattern.compile("Dashboard"));
// Count
assertThat(page.getByRole(AriaRole.LISTITEM)).hasCount(5);
// Attribute
assertThat(page.getByRole(AriaRole.LINK,
new Page.GetByRoleOptions().setName("Profile")))
.hasAttribute("href", "/profile");
// Negation
assertThat(page.getByText("Error")).not().isVisible();
}
}
from playwright.sync_api import Page, expect
import re
def test_assertion_showcase(page: Page):
page.goto("/dashboard")
# Visibility
expect(page.get_by_role("heading")).to_be_visible()
expect(page.get_by_test_id("spinner")).to_be_hidden()
# Text
expect(page.get_by_role("heading")).to_have_text("Dashboard")
expect(page.get_by_test_id("summary")).to_contain_text("42 items")
# URL and title
expect(page).to_have_url("/dashboard")
expect(page).to_have_title(re.compile("Dashboard"))
# Count
expect(page.get_by_role("listitem")).to_have_count(5)
# Attribute
expect(page.get_by_role("link", name="Profile")) .to_have_attribute("href", "/profile")
# CSS property
expect(page.get_by_test_id("status-badge")) .to_have_css("background-color", "rgb(34, 197, 94)")
# Custom timeout
expect(page.get_by_text("Ready")).to_be_visible(timeout=15000)
# Negation
expect(page.get_by_text("Error")).not_to_be_visible()
Written by PV
© 2026 All Rights Reserved