Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
Import expect from the API that matches your test style, then assert against a Page, Locator, or APIResponse: expect(page.get_by_role('button', name='Submit')).to_be_enabled() in synchronous code, or await expect(...).to_be_enabled() in asynchronous code. Playwright’s web-specific assertions wait and retry until the condition is true or the assertion timeout expires, which makes them safer for asynchronously rendered pages than one-time value checks. The Python Assertions guide documents a five-second default timeout; confirm details against the Playwright version installed in your project.
What expect asserts
expect expresses the state your test requires. The target determines the matcher family:
- Locator: element state and content, such as checked, enabled, hidden, text, or input value.
- Page: URL and title.
- APIResponse: whether an HTTP response is successful.
Playwright describes these as web-specific assertions that automatically retry until the expected condition is met. The assertion repeatedly re-fetches the relevant page state, so it can observe a framework-rendered update instead of racing it. Ordinary Python comparisons, such as assert locator.text_content() == 'Ready', do not acquire this retry behavior.
The examples below follow the Python documentation. The main Assertions page is served under the Next documentation path; API details are in the LocatorAssertions, PageAssertions, and APIResponseAssertions references. Check the matching documentation for your installed Playwright release before relying on a newly introduced option.
#1 Best Overall
Set up a synchronous or asynchronous test
Synchronous Playwright
Import from playwright.sync_api. This complete example uses the synchronous browser context manager and asserts a button and page title:
from playwright.sync_api import sync_playwright, expect
def test_checkout_title_and_submit():
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
page.goto('https://example.com/checkout')
expect(page).to_have_title('Checkout')
expect(page.get_by_role('button', name='Submit')).to_be_enabled()
browser.close()
The fixture or runner you use can manage the browser instead; the assertion syntax is the same.
Asynchronous Playwright
Import from playwright.async_api and await both browser operations and assertions:
Free tools Windows power users keep installed
One-click scans. No signup required.
import asyncio
from playwright.async_api import async_playwright, expect
async def check_checkout():
async with async_playwright() as p:
browser = await p.chromium.launch()
page = await browser.new_page()
await page.goto('https://example.com/checkout')
await expect(page).to_have_title('Checkout')
await expect(page.get_by_role('button', name='Submit')).to_be_enabled()
await browser.close()
asyncio.run(check_checkout())
Forgetting await on an asynchronous assertion leaves the check unexecuted and can produce a warning or a test that does not fail when it should.
Assert locator state and content
State matchers
Use a semantic locator and the state that matters to the behavior under test:
Rank #2
submit = page.get_by_role('button', name='Submit')
checkbox = page.get_by_role('checkbox', name='I agree')
spinner = page.get_by_role('status', name='Loading')
expect(submit).to_be_enabled()
expect(checkbox).to_be_checked()
expect(spinner).to_be_hidden()
Other state assertions include visibility and disabled or editable conditions. A locator can represent multiple matching elements; make it specific enough that the assertion describes one intended control. Role and accessible-name locators generally communicate that intent better than a broad CSS selector.
Text and input values
For text that may arrive after an API call or a client-side render, use to_have_text() rather than reading text once. For an input’s current value, use to_have_value(). The Locator documentation specifically recommends these waiting assertions to avoid flakiness.
expect(page.get_by_test_id('order-status')).to_have_text('Paid')
expect(page.get_by_label('Email')).to_have_value('[email protected]')
# A list can be checked as a sequence when your installed version supports it.
expect(page.locator('.cart-item')).to_have_count(2)
Match the expected text to the application contract: exact text is useful for a stable label, while a regular expression or substring expectation is more tolerant when only part of the message is guaranteed. Keep the assertion focused; an over-broad locator can pass because an unrelated element happens to contain the same words.
Assert a page URL or title
Page assertions make navigation requirements explicit and retain retry behavior while redirects or client-side routing finish:
expect(page).to_have_url('https://example.com/account')
expect(page).to_have_title('Account settings')
# A regular expression is useful when only the path or an ID varies.
import re
expect(page).to_have_url(re.compile(r'/orders/\d+$'))
Place the assertion after the action that should navigate, such as a click or form submission. If navigation is expected to be slow, give that particular assertion a justified timeout instead of making every assertion globally long.
Assert that an API response is successful
When a request is made through a Playwright request context or captured from a page, expect(response).to_be_ok() checks that the HTTP status is in the 200–299 range. In asynchronous code, await it.
# Synchronous request context
from playwright.sync_api import sync_playwright, expect
with sync_playwright() as p:
request = p.request.new_context()
response = request.get('https://example.com/api/health')
expect(response).to_be_ok()
request.dispose()
# Asynchronous request context
from playwright.async_api import async_playwright, expect
async with async_playwright() as p:
request = await p.request.new_context()
response = await request.get('https://example.com/api/health')
await expect(response).to_be_ok()
await request.dispose()
This assertion verifies status success; it does not by itself prove that the JSON body has the fields your application needs. Add separate response-content checks using the response data and ordinary Python assertions when those are part of the contract.
Understand retries and configure timeouts
The Assertions guide states a five-second default assertion timeout. A web assertion keeps checking until it passes or that timeout is reached. This is different from a fixed sleep: a passing condition completes immediately, while a genuinely slow condition receives the extra time you explicitly allow.
Set a global assertion timeout
from playwright.sync_api import expect
expect.set_options(timeout=10_000)
expect(page.get_by_role('heading', name='Report')).to_be_visible()
Set a global value only when most assertions in the suite need the same budget. A large global timeout can hide regressions and make every failure slower.
Set a timeout for one assertion
expect(page.get_by_role('heading', name='Report')).to_be_visible(timeout=10_000)
await expect(page.get_by_role('heading', name='Report')).to_be_visible(timeout=10_000)
Use the synchronous call in synchronous tests and the awaited call in asynchronous tests. Choose a value based on the documented response time of the operation under test, not on an arbitrary delay. If a condition never becomes true, the timeout error should identify the target and expected state; treat that diagnostic as a signal to inspect the locator, navigation, or application failure.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problemsSoft assertions and version compatibility
The Next Assertions guide describes soft assertions as checks that allow the test to continue while still marking it failed. That guide says soft assertions require pytest-playwright or pytest-playwright-asyncio 0.8.0 or newer. Because this requirement is documented on the /python/docs/next/ page, verify the plugin version and the corresponding release documentation before using soft-assertion APIs in a project pinned to an older version.
Use hard assertions for prerequisites: if the page is not the expected page, continuing can create misleading failures. Soft checks are most useful when several independent fields should be reported in one test run and your installed plugin explicitly supports the feature.
Patterns that keep assertions stable
Assert after the user-visible action
Perform the click, fill, or submission first, then assert the resulting state. Do not insert a fixed sleep to guess when rendering will finish; the matcher already polls the relevant state.
Use a locator that describes one element
Prefer get_by_role(), get_by_label(), or a test ID agreed with the application team. If a selector can match several controls, refine it before asserting text or enabled state.
Recommended Free Tools
Keep timeout scope narrow
Start with the five-second default. Increase one assertion when an external service or known long operation warrants it, and record why that operation has the longer budget. This preserves fast feedback for ordinary failures.
Best Value
Separate browser state from Python data checks
Use expect for the page, locator, and response conditions documented by Playwright. Once you extract a value into Python, use a normal Python comparison for calculations or data-structure rules; those comparisons are immediate and are not retried.
Or skip the browser setup
If your goal is to obtain a clean image of a page for a test artifact, visual baseline, or debugging ticket rather than interact with it, ScreenshotNeo provides a single HTTP request. Its API accepts the URL and returns PNG, JPEG, WebP, or PDF; the documentation is at screenshotneo.com/docs/.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get('https://api.screenshotneo.com/v1/shot', params={'access_key': 'YOUR_API_KEY', 'url': 'https://stripe.com'}, timeout=90)
open('shot.webp', 'wb').write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
Before capture, ScreenshotNeo accepts cookie or consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing status. An MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots, with every feature on every plan. Sign up for the free plan.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Troubleshoot failed assertions
Timeout while waiting for visibility or text
- Cause: the locator matches nothing, the action did not complete, or the application really is slower than the timeout.
- Fix: inspect the locator in the trace or browser, assert the preceding navigation or response, and use a larger per-assertion timeout only when the slower behavior is expected.
Text assertion is flaky
- Cause: a one-time text read races a client-side update, or the selector matches multiple elements.
- Fix: replace the read with
to_have_text(), narrow the locator, and assert the stable user-visible text.
URL assertion fails after a click
- Cause: the click did not trigger navigation, a redirect has a different final URL, or the expected pattern is too exact.
- Fix: verify the clicked control, inspect the final URL, and use a regular expression when only a path segment varies.
Response is not OK
- Cause: the server returned a status outside 200–299, often because authentication, request data, or an environment endpoint is wrong.
- Fix: log the response URL and status, check credentials and test data, and keep the
to_be_ok()assertion so the test fails at the HTTP boundary.
Async test produces a coroutine warning
- Cause: an asynchronous browser operation or assertion was called without
await. - Fix: follow the async API consistently, including
await expect(...)and awaited context cleanup.
Soft assertion is unavailable
- Cause: the installed pytest Playwright plugin is older than the 0.8.0-or-newer requirement stated by the Next guide, or a different runner is in use.
- Fix: check installed package versions and use the documentation matching that release, or use hard assertions until the supported plugin is available.
Performance and maintenance guidance
Assertions themselves are lightweight; the time cost comes from the polling window and the browser or network work that produces the state. Specific locators reduce repeated DOM queries, and immediate success means a five-second maximum is not a five-second delay on every passing test. Avoid setting a very high global timeout merely to accommodate one endpoint. Keep API-response assertions close to the request, and keep page assertions close to the action that changes the page, so failures identify the slow or broken boundary.
Finally, pin Playwright and its pytest plugin in your project, then read the matching versioned Python documentation. The URLs above include a Next guide as well as API references; behavior described on Next can differ from the release you have installed.
Frequently Asked Questions
What object should I pass to expect when checking an HTTP result?
Pass the Playwright APIResponse returned by a request context, then use the API-response assertion methods documented in APIResponseAssertions.
Why does the Assertions page use a /next/ URL?
It is the Playwright documentation’s Next-version page. Treat version-sensitive behavior, including soft-assertion support, as something to verify against the documentation and packages installed in your project.
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minutePC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11The Bottom Line
Use expect with the Playwright object that represents the behavior you care about, and let its web-specific matcher retry until the state is reached or a deliberate timeout expires. Keep synchronous and asynchronous imports consistent, prefer locator assertions for dynamic UI state, and verify Next-documentation features against your installed version.
Quick Recap
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.

