1. What Is an Assertion?
An assertion verifies that the application is in the state expected by the test. It answers questions such as:
- Is the Dashboard visible?
- Does the page contain the expected message?
- Is the Login button enabled?
- Is the checkbox checked?
- Does the URL contain the expected path?
- Does the input contain the expected value?
- Are the expected number of products displayed?
2. Different Types of Playwright Assertions
Visibility
Verify that an element is visible or hidden.
CoreText
Verify exact or partial visible text.
CoreValue
Verify the current value of form controls.
FormsAttribute
Verify attributes such as href, title or data-state.
DOMEnabled / Disabled
Verify whether controls can be interacted with.
StateChecked
Verify checkbox and radio button state.
FormsURL
Verify the current page URL.
NavigationTitle
Verify the browser page title.
NavigationCount
Verify the number of matching elements.
CollectionsScreenshot
Compare screenshots for visual validation.
VisualSoft Assertions
Continue the test after an assertion failure.
AdvancedNegation
Verify that an expected condition is not true.
Advanced3. Import Playwright Assertions
In Python's synchronous Playwright API, web-first assertions are
provided through the expect() API.
from playwright.sync_api import expect
With the asynchronous API:
from playwright.async_api import expect
4. Visibility Assertions
Verify Element Is Visible
expect(
page.get_by_role(
"heading",
name="Dashboard"
)
).to_be_visible()
Verify Element Is Hidden
expect(
page.get_by_test_id("loading-spinner")
).to_be_hidden()
5. Text Assertions
Exact Text
expect(
page.get_by_role(
"heading"
)
).to_have_text("Dashboard")
Partial Text
expect(
page.get_by_test_id("status-message")
).to_contain_text("successful")
to_have_text() when the expected text should match
the element's text content, and to_contain_text() when
only an important portion needs to be verified.
6. Text Assertion with Regular Expression
Regular expressions are useful when part of the text is dynamic.
import re
expect(
page.get_by_test_id("order-message")
).to_have_text(
re.compile(r"Order #\d+ confirmed")
)
7. Input Value Assertions
Verify what is currently stored in an input field.
email = page.get_by_label("Email")
email.fill("user@example.com")
expect(email).to_have_value(
"user@example.com"
)
8. Attribute Assertions
Attributes are useful when validating links, states and application metadata.
link = page.get_by_role(
"link",
name="Documentation"
)
expect(link).to_have_attribute(
"href",
"/documentation"
)
Check Dynamic State Attribute
tab = page.get_by_role(
"tab",
name="Orders"
)
expect(tab).to_have_attribute(
"aria-selected",
"true"
)
9. CSS Class Assertions
Class assertions can be useful when the class represents a meaningful application state.
expect(
page.get_by_test_id("status")
).to_have_class(
"status-success"
)
10. Enabled and Disabled Assertions
Enabled
submit = page.get_by_role(
"button",
name="Submit"
)
expect(submit).to_be_enabled()
Disabled
expect(submit).to_be_disabled()
11. Checkbox and Radio Assertions
Checked
terms = page.get_by_label(
"Accept Terms"
)
terms.check()
expect(terms).to_be_checked()
Not Checked
expect(terms).not_to_be_checked()
12. Editable and Read-Only State
Editable
expect(
page.get_by_label("Username")
).to_be_editable()
Read Only
expect(
page.get_by_label("Order ID")
).to_be_read_only()
13. URL Assertions
Verify navigation after an action.
page.get_by_role(
"link",
name="Orders"
).click()
expect(page).to_have_url(
re.compile(r".*/orders")
)
Exact URL
expect(page).to_have_url(
"https://example.com/orders"
)
14. Page Title Assertion
expect(page).to_have_title(
"Customer Orders"
)
Regular Expression
expect(page).to_have_title(
re.compile("Orders")
)
15. Count Assertions
Count assertions are useful for tables, product lists, search results and dashboards.
products = page.get_by_test_id(
"product-card"
)
expect(products).to_have_count(10)
16. Empty and Non-Empty State
Empty State
expect(
page.get_by_test_id("cart-item")
).to_have_count(0)
Non-Empty State
expect(
page.get_by_test_id("cart-item")
).not_to_have_count(0)
17. Negative Assertions
Use not_ when the requirement is that a condition
should not be true.
expect(
page.get_by_text("Error")
).not_to_be_visible()
Not Checked
expect(
page.get_by_label("Subscribe")
).not_to_be_checked()
18. How Web-First Assertions Auto-Retry
Consider a dashboard that loads data asynchronously.
expect(
page.get_by_text("Orders Loaded")
).to_be_visible()
The assertion waits for the expected condition rather than assuming that the UI is already updated at the exact moment the assertion begins.
19. Fragile Assertion Pattern
❌ Immediate Property Check
assert page.get_by_text(
"Payment Successful"
).is_visible()
The boolean property is evaluated immediately. If the application is still rendering the message, the assertion may fail before the expected state appears.
✅ Web-First Assertion
expect(
page.get_by_text(
"Payment Successful"
)
).to_be_visible()
20. Assertions vs Explicit Waits
A common beginner mistake is adding an explicit wait before every assertion.
❌ Unnecessary Pattern
page.wait_for_timeout(5000)
expect(
page.get_by_text("Success")
).to_be_visible()
✅ Better
expect(
page.get_by_text("Success")
).to_be_visible()
21. Assertion Timeout
Sometimes a particular operation genuinely needs a different timeout. Playwright assertions support timeout configuration.
expect(
page.get_by_text(
"Large Report Ready"
)
).to_be_visible(
timeout=30000
)
22. Table Row Assertions
Tables are common in enterprise applications.
row = page.locator("tr").filter(
has_text="John Smith"
)
expect(row).to_be_visible()
expect(row).to_contain_text(
"Active"
)
expect(row).to_contain_text(
"Premium"
)
23. Product List Assertions
products = page.get_by_test_id(
"product-card"
)
expect(products).to_have_count(20)
expect(
products.nth(0)
).to_contain_text("Laptop")
nth() when position is genuinely part of the
requirement. If the test is about a specific product, a semantic
filter is usually more meaningful.
24. Soft Assertions
Soft assertions allow a test to continue after an assertion failure, so multiple problems can be reported from one test execution.
expect(
page.get_by_text("Dashboard")
).to_be_visible()
expect(
page.get_by_text("Orders")
).to_be_visible()
expect(
page.get_by_text("Customers")
).to_be_visible()
25. Visual Assertions with Screenshots
Playwright can perform screenshot comparisons for visual regression testing.
expect(page).to_have_screenshot(
"dashboard.png"
)
Element Screenshot
expect(
page.get_by_test_id("dashboard-card")
).to_have_screenshot(
"dashboard-card.png"
)
26. Real-Time Example — Login Validation
from playwright.sync_api import expect
def test_login(page):
page.goto(
"https://example.com/login"
)
page.get_by_label(
"Username"
).fill("testuser")
page.get_by_label(
"Password"
).fill("TestPassword123")
page.get_by_role(
"button",
name="Sign In"
).click()
# URL assertion
expect(page).to_have_url(
"https://example.com/dashboard"
)
# Page assertion
expect(page).to_have_title(
"Dashboard"
)
# UI assertion
expect(
page.get_by_role(
"heading",
name="Dashboard"
)
).to_be_visible()
27. Real-Time Example — E-Commerce Checkout
from playwright.sync_api import expect
def test_checkout(page):
page.goto(
"https://example.com/products"
)
product = page.locator(
".product-card"
).filter(
has_text="Laptop"
)
expect(product).to_be_visible()
product.get_by_role(
"button",
name="Add to Cart"
).click()
cart = page.get_by_role(
"link",
name="Cart"
)
expect(cart).to_be_visible()
cart.click()
checkout = page.get_by_role(
"button",
name="Checkout"
)
expect(checkout).to_be_enabled()
checkout.click()
expect(page).to_have_url(
"https://example.com/checkout"
)
expect(
page.get_by_role(
"heading",
name="Checkout"
)
).to_be_visible()
28. Validate Application State After an Action
A strong test verifies the outcome of the business operation, not merely that the click completed.
Weak Test
page.get_by_role(
"button",
name="Approve"
).click()
Strong Test
page.get_by_role(
"button",
name="Approve"
).click()
expect(
page.get_by_text("Approved")
).to_be_visible()
expect(
page.get_by_test_id("request-status")
).to_have_text("Approved")
29. Assertion Strategy for Real-Time Applications
For example, after approving a customer request:
approve = page.get_by_role(
"button",
name="Approve"
)
approve.click()
# UI state
expect(
page.get_by_text("Approved")
).to_be_visible()
# Business state
expect(
page.get_by_test_id("request-status")
).to_have_text("Approved")
# Action availability
expect(approve).to_be_disabled()
30. Locator + Action + Assertion
The core Playwright pattern can be summarized as:
login_button = page.get_by_role(
"button",
name="Login"
)
login_button.click()
expect(
page.get_by_role(
"heading",
name="Dashboard"
)
).to_be_visible()
31. Playwright Assertion Cheat Sheet
| Requirement | Assertion | Example |
|---|---|---|
| Visible | to_be_visible() |
expect(locator).to_be_visible() |
| Hidden | to_be_hidden() |
expect(locator).to_be_hidden() |
| Text | to_have_text() |
expect(locator).to_have_text("Success") |
| Contains text | to_contain_text() |
expect(locator).to_contain_text("Success") |
| Input value | to_have_value() |
expect(locator).to_have_value("John") |
| Attribute | to_have_attribute() |
expect(locator).to_have_attribute("href", "/home") |
| Class | to_have_class() |
expect(locator).to_have_class("active") |
| Enabled | to_be_enabled() |
expect(locator).to_be_enabled() |
| Disabled | to_be_disabled() |
expect(locator).to_be_disabled() |
| Checked | to_be_checked() |
expect(locator).to_be_checked() |
| Editable | to_be_editable() |
expect(locator).to_be_editable() |
| Read-only | to_be_read_only() |
expect(locator).to_be_read_only() |
| Count | to_have_count() |
expect(locator).to_have_count(10) |
| URL | to_have_url() |
expect(page).to_have_url(...) |
| Title | to_have_title() |
expect(page).to_have_title(...) |
| Screenshot | to_have_screenshot() |
expect(page).to_have_screenshot(...) |
32. Bad vs Robust Assertions
❌ Hard Sleep + Immediate Check
import time
time.sleep(5)
assert page.get_by_text(
"Order Completed"
).is_visible()
✅ Web-First Assertion
expect(
page.get_by_text(
"Order Completed"
)
).to_be_visible()
❌ Checking an Arbitrary Position
assert page.locator(
".product"
).nth(4).is_visible()
✅ Assert the Business Object
product = page.locator(
".product"
).filter(
has_text="Laptop"
)
expect(product).to_be_visible()
33. Professional Assertion Design
Assertions should validate meaningful business behavior instead of implementation details whenever possible.
UI State
Is the correct component visible? Is the button enabled? Is the selected tab active?
Business State
Was the order created? Was the customer approved? Was payment completed?
Navigation
Did the application navigate to the expected URL? Did the correct page load?
34. Assertions with Page Object Model
Page objects can contain interactions and expose meaningful page-level operations. Tests can then perform assertions against the page's externally visible behavior.
from playwright.sync_api import Page, expect
class LoginPage:
def __init__(self, page: Page):
self.page = page
self.username = page.get_by_label(
"Username"
)
self.password = page.get_by_label(
"Password"
)
self.login_button = page.get_by_role(
"button",
name="Sign In"
)
self.dashboard_heading = page.get_by_role(
"heading",
name="Dashboard"
)
def login(self, username, password):
self.username.fill(username)
self.password.fill(password)
self.login_button.click()
def assert_dashboard_visible(self):
expect(
self.dashboard_heading
).to_be_visible()
Test
def test_login(page):
login = LoginPage(page)
login.login(
"testuser",
"TestPassword123"
)
login.assert_dashboard_visible()
35. Complete Real-Time Assertion Workflow
from playwright.sync_api import expect
def test_customer_approval(page):
page.goto(
"https://example.com/customers"
)
customer = page.locator(
"tr"
).filter(
has_text="John Smith"
)
# Customer exists
expect(customer).to_be_visible()
# Initial state
expect(customer).to_contain_text(
"Pending"
)
# Perform action
customer.get_by_role(
"button",
name="Approve"
).click()
# UI result
expect(customer).to_contain_text(
"Approved"
)
# Status control
expect(
customer.get_by_test_id(
"status"
)
).to_have_text("Approved")
# Button state
expect(
customer.get_by_role(
"button",
name="Approve"
)
).to_be_disabled()
36. Playwright Assertion Best Practices
-
Prefer web-first assertions through
expect(). - Assert meaningful application behavior rather than implementation details.
- Use visibility assertions for UI presence.
- Use text assertions for user-visible messages and business states.
- Use value assertions for form fields.
- Use attribute assertions when the attribute represents meaningful state.
- Use URL and title assertions to validate navigation.
- Use count assertions for lists, tables and collections.
- Avoid fixed sleeps before assertions.
- Avoid immediate property checks when the UI is expected to change asynchronously.
- Use negative assertions only when absence or a negative state is actually part of the requirement.
- Keep assertions close to the business action they validate.
37. Professional Assertion Mindset
Action:
Approve Customer
Expected behavior:
Customer status changes from Pending to Approved
Good assertion:
expect(status).to_have_text("Approved")
38. Final Mental Model
They verify that the application reached the expected state after that action.
39. Next Learning Step
Next → Waits
Learn auto-waiting, explicit waits, event-based synchronization, network waits and dynamic UI handling.
Then → Fixtures
Learn how Playwright fixtures provide reusable browser, context, page and test data setup.
Professional → Page Object Model
Combine locators, actions and assertions into maintainable enterprise automation architecture.