Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Import expect from the Playwright API that matches your test style: playwright.sync_api for synchronous tests or playwright.async_api for asynchronous tests. Then assert the state you care about on a page, locator, or API response. Playwright’s web-specific assertions retry until the condition passes or the assertion timeout expires, which makes them a better fit for changing page state than an immediate Python comparison.

Import and use the right assertion API

Playwright provides synchronous and asynchronous Python APIs. Keep the assertion import and call style consistent with the API used to create and control the browser: synchronous tests call matchers directly, while asynchronous tests await them.

Synchronous assertions

from playwright.sync_api import expect

expect(page.get_by_role("button", name="Submit")).to_be_enabled()
expect(page).to_have_title("Checkout")

Here, page represents the Playwright Page object already created by your test or test runner. The example demonstrates assertion syntax; it does not prescribe a particular fixture or setup. The Playwright Python Assertions guide shows this assertion model.

Asynchronous assertions

from playwright.async_api import expect

await expect(page.get_by_role("button", name="Submit")).to_be_enabled()
await expect(page).to_have_title("Checkout")

In async code, await both the browser operations and the assertions. Do not mix a synchronous expect import into an async test, or omit await from an async assertion. The Python API documentation provides sync and async forms for the relevant assertion classes, including LocatorAssertions and PageAssertions.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose the assertion target that matches the behavior

Use the Playwright object that represents the condition under test. A page assertion describes page-level state, a locator assertion describes an element, and a response assertion describes an API result. This makes the test state its intent rather than checking an incidental implementation detail.

Check a locator’s state, text, or value

from playwright.sync_api import expect

submit = page.get_by_role("button", name="Submit")
expect(submit).to_be_enabled()
expect(page.get_by_label("Email")).to_have_value("person@example.com")
expect(page.get_by_role("status")).to_have_text("Order placed")

Use a state matcher such as to_be_checked(), to_be_enabled(), or to_be_hidden() when that is what matters. For text, use to_have_text(); for an input value, use to_have_value(). The Python Locator documentation specifically recommends the text and value assertions to avoid flakiness when page content may still be updating. Use a locator that identifies the intended element, such as one built from a role and accessible name, rather than asserting against an arbitrary element.

Check page URL or title

expect(page).to_have_url("https://example.com/checkout")
expect(page).to_have_title("Checkout")

These are page-level conditions, so assert them on page, not on a locator. Use the URL or title form that expresses the outcome your test requires. The PageAssertions reference documents both matchers, including their async forms.

Check an API response

response = page.request.get("https://example.com/api/health")
expect(response).to_be_ok()

to_be_ok() checks whether the response status is in the 200–299 range. In asynchronous code, await the request and assertion:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
response = await page.request.get("https://example.com/api/health")
await expect(response).to_be_ok()

See the APIResponseAssertions reference for the response assertion API.

Understand retries and assertion timeouts

Playwright’s web-specific assertions automatically retry: they re-check the relevant page state until the condition passes or the assertion times out. The Playwright Python Assertions guide gives a default assertion timeout of five seconds. This is useful when an action triggers rendering, navigation, or another asynchronous update: the assertion can pass when the expected state arrives instead of failing on the first transient mismatch.

That retry behavior is for the documented web-specific assertions. It does not make an ordinary Python comparison retry:

# Immediate Python comparison: it does not wait for the page to update.
assert page.locator("[data-testid='status']").inner_text() == "Ready"

# Playwright assertion: retries for the expected web state.
expect(page.get_by_test_id("status")).to_have_text("Ready")

Prefer the Playwright matcher when the condition depends on page state that may change. An immediate comparison can be appropriate for an ordinary value that is already available and does not need browser-state retry behavior.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Set a timeout for one assertion

expect(page.get_by_role("status")).to_be_visible(timeout=10_000)

The matcher’s timeout is in milliseconds. A per-assertion timeout is useful when one particular state is expected to take longer than the default; choose a value based on the behavior the test needs to allow, rather than increasing it indiscriminately.

Set a timeout globally

expect.set_options(timeout=10_000)

This changes the assertion timeout option globally for the test process using that configuration. The Assertions guide documents the five-second default and both the global and per-assertion approaches. Keep timeout configuration intentional: a longer limit can accommodate a genuinely slower expected operation, but it can also delay failure when the condition will never occur.

Use soft assertions only with compatible test tooling

A soft assertion records a failure without stopping execution at that assertion, allowing later checks to run; the test is still marked as failed. The Playwright Python guide under its /next/ documentation path says soft assertions require pytest-playwright or pytest-playwright-asyncio version 0.8.0 or newer. That is a version-qualified statement from Next documentation, not a guarantee for every installed release or runner.

Before adopting soft assertions, verify the behavior in the documentation matching your installed Playwright and plugin versions. For a test where later steps depend on the state being asserted, a hard assertion is often clearer because it stops execution at the failed precondition.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Write assertions that wait for the outcome, not the delay

A fixed sleep waits a predetermined amount of time whether the page is ready quickly or remains unready throughout. A web-specific assertion instead waits for the meaningful condition itself. For example, after an action that should reveal confirmation text, assert the text with to_have_text() rather than reading it once immediately or sleeping for an assumed duration.

Keep the assertion narrow and behavior-focused. If a test is about a submitted form, checking that the confirmation appears is generally more informative than checking unrelated markup. If it is about whether an action is available, assert the button’s enabled state. A test with a clear target and matcher is easier to interpret when it fails.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshoot common assertion failures

The assertion fails immediately in an async test

  • Cause: The test imported expect from the sync API, or called an async assertion without await.
  • Fix: Import from playwright.async_api and await the assertion, as well as asynchronous browser operations. In a synchronous test, use playwright.sync_api and call the assertion directly.

A text or value assertion is flaky

  • Cause: The test reads a changing page value once, before rendering or an update has finished.
  • Fix: Assert with expect(locator).to_have_text(...) or to_have_value(...) so Playwright can retry the expected page state. Confirm that the locator points to the element whose text or value should change.

A visibility or state assertion times out

  • Cause: The expected state did not become true within the timeout. The locator may identify the wrong element, the action leading to the state may not have occurred, or the page may not have reached the expected outcome.
  • Fix: Check the target and the preceding test action first. If the application legitimately needs longer for that specific outcome, give that matcher an appropriate timeout. Increasing timeouts will not correct a wrong locator or missing state transition.

A page assertion checks the wrong object

  • Cause: A page-level condition, such as the URL or title, is being treated as an element condition, or vice versa.
  • Fix: Use expect(page) for URL and title; use expect(locator) for an element’s state, text, or value; use expect(response) for a response status assertion.

A response is not considered OK

  • Cause: The response status is outside the 200–299 range checked by to_be_ok().
  • Fix: Inspect the response and confirm what status the endpoint is expected to return. Do not use an “OK” assertion if the behavior under test intentionally returns a status outside that range.

A soft assertion is unavailable or behaves differently

  • Cause: The installed pytest Playwright plugin may not meet the version requirement stated in the Next guide, or the project’s released documentation may differ.
  • Fix: Check the documentation for the versions actually installed before depending on soft assertions. Keep a hard assertion if compatibility is uncertain.

Capture a screenshot separately from asserting page state

A screenshot can provide a visual artifact for debugging, but it does not replace a Playwright assertion: an image alone does not establish that a locator has the expected text, that a page has the intended URL, or that a response is successful. Use expect for those behavioral checks. For a separate screenshot capture without setting up your own browser capture flow, ScreenshotNeo is a website screenshot API and MCP server for developers.

Or skip the browser setup

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo API documentation for request details. ScreenshotNeo accepts cookie or consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each of those steps can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents and MCP clients. The free plan includes 1,000 shots per month without a card; paid plans start at $5 for 3,000 shots.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Sign up for ScreenshotNeo to get 1,000 screenshots a month free, with no card required.

Frequently Asked Questions

Does `expect` work with a Python `unittest` test, or only pytest?

The syntax shown here applies to Playwright’s Python sync and async APIs; test-runner fixture and setup details depend on the runner and are not established by these assertion references.

Can I use an assertion timeout to wait for a specific page element?

Yes. Use a locator assertion such as `to_be_visible()` with its `timeout` argument when visibility is the condition you need.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.