Playwright Assertions

On This Page What are Playwright Assertions?Playwright Expect ()

April 02, 2026 · 14 min read · Tool Comparison

Understanding Playwright Assertions [2026]

When a test bunk, I always wonder—did the app really behave the way I await, or did the hand just move on? That incertitude is exactly where Playwright averment come in.

I use assertions to intermit the test and requirement proof. Is the component visible? Did the value modification? Did the action actually succeed? Each cheque forces the application to reveal whether it ’ s bear correctly.

That moment of proof decides everything. If the prospect holds, the test surpass. If not, it betray instantly. With affirmation in spot, I ’ m no longer assuming correctness—I ’ m verify it, tread by step.

What are Playwright Assertions?

Playwright Assertionsare a set of built-in purpose which includesexpect () functionply by the Playwright prove framework to validate the behavior and state of a web coating during machine-controlled tests.

Playwright Assertions are used to verify whether specific conditions are met, such as ensure if an element exists, contains certain text, or has a particular state. These assertions are essential for confirming that the application carry as expected during end-to-end testing.

Playwright provides diverse assertion types:

  • Element States:Check the visibility, availability, and interactivity of UI elements.
  • Contented Validation:Ensure elements display the correct text, values, or match specific form.
  • Page Properties:Assertions can support page details like URLs, titles, or cookie presence.
  • Network Interactions:Verify the outcomes of network postulation and responses to ensure proper information loading and form submissions.

Playwright Expect () Function

Playwrightexpectis the built-in asseveration API used to validate how an application behaves during a test.

It allows tests towait for conditions to be trueand so control outcomes such as element visibleness, text content, attributes, URLs, or network states. Instead of checking value instantly, look mechanically retries until the condition passes or the timeout is hit, which helps handle dynamical UI behavior.

In simple terms, expect is how Playwright affirm whether the app under test matches the expected province and decides if a tryout should pass or fail.

For Example:

test (`` Validate BrowserStack demo application site title '', async ({page}) = & gt; {await page.goto (`` https: //bstackdemo.com/ '') expect expect (page) .toHaveTitle (`` StackDemo '')})

In the above codification example, using BrowserStack ’ s Demo application in the playwright test to validate the Site Title.

Code Breakdown:

Below code will access the BrowserStack ’ s Demo Application

await page.goto (`` https: //bstackdemo.com/ '')

Below codification Asserts the BrowserStack ’ s Website Title.

await anticipate (page) .toHaveTitle (`` StackDemo '')

Here, Playwright await until the component becomes visible before marking the assertion successful.

Different Types of Playwright Assertions

Assertions in Playwright is broadly classified into below case

Types of Playwright Assertions:

  • Auto-retrying Assertions
  • Non-retrying Assertions
  • Negating Matchers
  • Soft Assertions

Let ’ s look into each assertion character.

Auto-retrying Assertion

Auto-retrying affirmation in Playwright are a lively functionality that significantly boosts the reliability and stability of test playscript by repeatedly attempting to control assertions until they either succeed or a predefined timeout is gain.

Auto-retrying feature is especially utilitarian in scenario where web element might not immediately meet expected conditions due to network delays, dynamical content loading, or client-side scripting operations.

Let ’ s write a test which asserts a schoolbook from BrowserStack ’ s Demo Application Website.

In this exam, performing below steps:

  1. Access BrowserStack ’ s Demo application
  2. Validate the default Number of Products found
exam (`` Validate BrowserStack nonpayment products found enumeration '', async ({page}) = & gt; {await page.goto (`` https: //bstackdemo.com/ '') const productLocator = await page.locator (`` .products-found span '') wait expect (productLocator) .toHaveText ('25 Product (s) found ')})

Code Breakdown

Visit the BrowserStack ’ s Demo application

await page.goto (`` https: //bstackdemo.com/ '')

Get the locator reference

const productLocator = await page.locator (`` .products-found span '')

Assert the Number of Products found from Web page against expected value

await expect (productLocator) .toHaveText ('25 Product (s) found ')

Observe that in the above assertion you pass the locator acknowledgment and then you are using matchmakertoHaveTextwhich take expected value as string.

If you run the above test, the test will fail in assertion with automobile retry timeout.

Note that the exam is timed out after retrying for 5000 milliseconds, this is because Playwright has a default timeout of 5000 milliseconds.

You can overwrite the assertion timeout at command level like below.

await expect (productLocator) .toHaveText ('25 Product (s) found ', {timeout: 2000})

Below is the full inclination of Auto-Retrying assertions.

AssertionDescription
await expect (locater) .toBeAttached ()Element is attached
await expect (locator) .toBeChecked ()Checkbox is insure
await await (locater) .toBeDisabled ()Element is disabled
await wait (locator) .toBeEditable ()Element is editable
await expect (locator) .toBeEmpty ()Container is vacuous
await expect (locator) .toBeEnabled ()Element is enabled
await expect (locater) .toBeFocused ()Element is concentrate
await await (locator) .toBeHidden ()Element is not visible
await expect (locator) .toBeInViewport ()Element intersects viewport
await expect (locator) .toBeVisible ()Element is visible
await expect (locator) .toContainText ()Element contains text
await expect (locator) .toHaveAttribute ()Element has a DOM attribute
await anticipate (locater) .toHaveClass ()Element has a class holding
await ask (locater) .toHaveCount ()List has exact number of children
await wait (locator) .toHaveCSS ()Element has CSS property
await expect (locator) .toHaveId ()Element has an ID
await expect (locater) .toHaveJSProperty ()Element has a JavaScript property
await anticipate (locator) .toHaveScreenshot ()Element has a screenshot
await expect (locator) .toHaveText ()Element matches text
await ask (locator) .toHaveValue ()Input has a value
await expect (locator) .toHaveValues ()Select has option selected
await expect (page) .toHaveScreenshot ()Page has a screenshot
await ask (page) .toHaveTitle ()Page has a title
await expect (page) .toHaveURL ()Page has a URL
await wait (response) .toBeOK ()Response has an OK status

Non-retrying Assertions

Non-retrying Assertions are only useful when web pages load data asynchronously. Test assertion will fail without any timeout or rehear when using the Non-retrying Assertion and below is an instance test for the same.

test (`` example for non-retrying averment '', async ({page}) = & gt; {await page.goto (`` https: //bstackdemo.com/ '') const productLocator = await page.locator (`` .products-found couplet '') const productSearchText = await productLocator.innerText () await expect (productSearchText) .toBe ('25 Product (s) found ')})

When you run this test, it will fail with affirmation without retrying.

Below is the full list of Non-retrying assertion matchers

AssertionDescription
expect (value) .toBe ()Value is the same
expect (value) .toBeCloseTo ()Number is approximately equal
expect (value) .toBeDefined ()Value is not vague
expect (value) .toBeFalsy ()Value is falsy, e.g.false, 0, null, etc.
expect (value) .toBeGreaterThan ()Number is more than
expect (value) .toBeGreaterThanOrEqual ()Number is more than or equal
expect (value) .toBeInstanceOf ()Object is an representative of a class
expect (value) .toBeLessThan ()Number is less than
expect (value) .toBeLessThanOrEqual ()Number is less than or equal
expect (value) .toBeNaN ()Value is NaN
expect (value) .toBeNull ()Value is null
expect (value) .toBeTruthy ()Value is truthy, i.e. notfalse, 0, null, etc.
expect (value) .toBeUndefined ()Value is undefined
expect (value) .toContain ()String contains a substring
expect (value) .toContain ()Array or set contains an element
expect (value) .toContainEqual ()Array or set contains a like factor
expect (value) .toEqual ()Value is alike & # 8211; deep equality and pattern matching
expect (value) .toHaveLength ()Array or string has length
expect (value) .toHaveProperty ()Object has a property
expect (value) .toMatch ()String matches a veritable face
expect (value) .toMatchObject ()Object contains specified properties
expect (value) .toStrictEqual ()Value is similar, including property types
expect (value) .toThrow ()Function throws an error
expect (value) .any ()Matches any example of a class/primitive
expect (value) .anything ()Matches anything
expect (value) .arrayContaining ()Array contains specific elements
expect (value) .closeTo ()Number is approximately equal
expect (value) .objectContaining ()Object contains specific property
expect (value) .stringContaining ()String control a substring
expect (value) .stringMatching ()String match a veritable face

Negating Matchers

Negating Matchers are used when we want to check that a certain condition perform not hold true. It basically reverses the condition you & # 8217; re checking for, enabling you to assert the absence of a condition or element. Negating Matchers are especially helpful for ensuring that a web page or application is gratuitous from errors, incorrect province, or unwanted elements.

For autonomous testing across multiple user personas, check out SUSATest — it explores your app like 10 different real users.

Below is the example test. The tryout will assert for filter count not matching the value 3

test (`` example for negate matchmaker '', async ({page}) = & gt; {await page.goto (`` https: //bstackdemo.com/ '') const filter = await page.locator (`` .filters .filters-available-size '') const filterCount = await filter.count () look expect (filterCount) .not.toEqual (3)})

Soft Assertions

By nonremittal Assertion will abort the examination as soon as the expected result is not mate with the actual result. There are cases where we have to control multiple assertions and at the end of the test shed the assertion error.

Soft statement is good for cases where we want to swan multiple cases and then fail the test at the end.

Below is the example trial. The test has two assertions and both will execute and fail.

test (`` example for soft assertion '', async ({page}) = & gt; {await page.goto (`` https: //bstackdemo.com/ '') const filter = await page.locator (`` .filters .filters-available-size '') const filterCount = await filter.count () await expect.soft (filterCount) .not.toEqual (4) await expect.soft (page) .toHaveTitle (`` StackDemo! '')})

If you don ’ t use soft assertion, so the test will fail at the first assertion check and doesn ’ t continue.

Running the above test will shew two assertion fault.

Playwright Custom Matchers with Examples

Playwright render users to create their own Custom Matchers, which can be chained withexpect() for Assertions

To create Custom Matchers, we need to go theexpect() map from Playwright and then add our Custom Matchers within the extend function like below

import { expect asbaseExpect}from' @ playwright/test ';importtype {Page, Locator}from' @ playwright/test ';export { test } from' @ playwright/test ';export constexpect = baseExpect.extend ({asynctoHavePrice (locater: Locator, expected: number, pick?: {timeout?: number}) {constassertionName = 'toHavePrice ';letpass: boolean;letmatcherResult: any;try {

     awaitbaseExpect (locator) .toHaveText (String (expected), options); pass = true;}catch(e: any) {matcherResult = e.matcherResult; pass = false;}constcontent = passing? () = & gt;this.utils.matcherHint (assertionName, undefined, undefined, {isNot:this.isNot}) + '\n\n ' + ` Locator: $ {locater} \n ` + ` Expected: $ {this.isNot? 'not ': ``} $ {this.utils.printExpected (expected)} \n ` + (matcherResult? ` Received: $ {this.utils.printReceived (matcherResult.actual)} `: ``): () = & gt;this.utils.matcherHint (assertionName, undefined, undefined, {isNot:this.isNot}) + '\n\n ' + ` Locator: $ {locator} \n ` + ` Expected: $ {this.utils.printExpected (expected)} \n ` + (matcherResult? ` Received: $ {this.utils.printReceived (matcherResult.actual)} `: ``);return{message, pass, gens: assertionName, expected, actual: matcherResult? .actual,};},});

We can make a new file called fixture.ts and add the above code in that file. Once the code is added we can then write a tryout like below.

import{test, expect}from' .. /fixtures/fixtures '; test (`` example for usage matcher '',async({page}) = & gt; {awaitpage.goto (`` https: //bstackdemo.com/ '')const phone = awaitpage.locator (`` .shelf-item__title '', {hasText: '' iPhone 12 Mini '',})constphoneParent =awaitphone.locator (`` .. '')constphonePrice = phoneParent.locator (`` .shelf-item__price .val b '')awaitexpect (phonePrice) .toHavePrice (`` 699 '')})

Handling Dynamic UI States with Assertions

Modern web coating rarely abide still. Elements lade asynchronously, UI states vary based on user actions, and content updates after network calls. Assertions in Playwright are designed to care this dynamism without relying on manual waits or fragile timing logic.

Playwright ’ s expect () averment automatically wait for the expected condition to be met before failing. This makes them effective for corroborate UI states that appear, disappear, or update over time.

Mutual active scenario handled with affirmation include:

  • Elements turn seeable after an API response
  • Buttons enable or disabling establish on form stimulant
  • Text or property updating after user interaction
  • Loaders or spinner disappearing before content renders

For instance:

await expect (page.locator ('.loader ')) .toBeHidden (); await expect (page.locator (' # condition ')) .toHaveText ('Completed ');

Here, the assertions await until the UI reaches the expected state instead of checking immediately. This access cut flakiness and keeps test aligned with how existent users get the covering.

Are your Playwright statement really reliable?

Assertions can pass locally and fail for users. Validate them on real devices with BrowserStack.

Assertions for Network Requests and Responses

UI validation alone is frequently not plenty. Many user-visible changes bet on network activity, and Playwright allows affirmation to validate those interactions straight.

Assertions can be combine with web interception to control:

  • API response status codes
  • Request payload post by the application
  • Response body affecting UI behavior
  • Completion of critical backend operation

A common pattern involve look for a reaction and so asseverate on its outcome:

const response = await page.waitForResponse (resp = & gt; resp.url () .includes ('/api/order ') & amp; & amp; resp.status () === 200); await expect (response.ok ()) .toBeTruthy ();

By asserting on mesh doings, trial confirm not merely that the UI changed, but that it changed for the right intellect. This strengthens test reporting for data-driven workflow and reduces blind spot where UI-only assertions might pass despite backend issue.

Common Mistakes with Playwright Assertions

Even with powerful defaults, assertions can inclose imbalance when used incorrectly. Many flaky tests follow backward to assertion misuse rather than application defects.

Frequent misunderstanding include:

  • Using manual waits instead of relying on auto-retrying assertions
  • Asserting too early on constituent that depend on async provide
  • Overusing hard assertions where soft assertions are more appropriate
  • Validating effectuation details instead of user-visible behavior

For example, checking textbook now after navigation:

// Fragile approach await page.click (' # submit '); wait (await page.textContent (' # msg ')) .toBe ('Success ');

A more stable approach:

await page.click (' # submit '); await ask (page.locator (' # msg ')) .toHaveText ('Success ');

This allows Playwright to wait until the UI is truly ready. Open, user-focused assertions combined with built-in retries result in tests that fail for real issues, not timing quirks or transient states

Best Practices to use Playwright Expect ()

The expect()function is a cornerstone of assertions in Playwright, volunteer the ability to assert on elements, net response, and other test conditions.

Below are the few Best Practices for Playwright Expect ():

1. Leverage Built-In Retry Mechanism

Understand the reflexive retry characteristic in Playwright ’ s expect ():

  • Utilize this feature for dynamic message where elements may appear or vary province over time.
  • Avoid extravagant trust which might conceal execution issues or complex race weather.

2. Employ Semantic Locators

Opt for Playwright ’ s progress picker like role and text selectors to improve both the legibility and maintainability of your tests:

awaitanticipate (page.locator ('text=Sign In ')) .toBeVisible ();awaitexpect (page.locator ('role=button ', {gens: 'Send '})) .toBeEnabled ();

These chooser heighten the semantic clarity and handiness focus of your tests.

3. Integrate Actions with Verification

Simultaneously perform user activity and control outcomes to mime real user flows:

awaitpage.click ('button # save ');awaitask (page.locator ('text=Saved successfully ')) .toBeVisible ();

This method validates user interactions in real-time.

4. Customize Timeouts

Adjust timeouts inexpect()when the default scene do not align with specific test requirements:

  • Modify the timeout parameter to suit specific expect want without overextending test durations.

5. Assert Non-Presence

Assert the non-presence of constituent or messages, particularly useful in validate error handling and user feedback:

awaitexpect (page.locator ('text=Error ')) .not.toBeVisible ();

6. Utilize State-Specific Assertions

Make total use of Playwright ’ s state-specific averment to directly valuate the user interface:

awaitrequire (page.locator ('input [type= '' checkbox ''] ')) .toBeChecked ();

7. Assert Network Interactions

Capture and assert network response to ensure backend integration is functioning as expected:

const[reaction] =awaitPromise.all ([page.waitForResponse (resp = & gt; resp.url () .includes ('/api/submit ') & amp; & amp; resp.status () === 200), page.click ('button # submit ')]);awaitexpect (response) .toBeOK ();

8. Validate Accessibility Features

Assert on accessibility characteristic to ensure your application is accessible:

awaitexpect (page.locator (& # 8216; role=button & # 8217;, {gens: & # 8216; Confirm & # 8217;})) .toHaveAttribute (& # 8216; aria-live & # 8217;, & # 8216; polite & # 8217;);

9. Enhance Assertion Failures

Incorporate symptomatic creature like screenshots or logs to enquire why averment betray:

test.fail (async({page}) = & gt; {awaitpage.screenshot ({route: 'error-snapshot.png '});});

Why run Playwright Tests on Real Device Cloud?

Here & # 8217; s why you should run Playwright examination on existent browsers & amp; devices employ a cloud-based testing platform like:

  • Accurate UI behavior validation:Assertions related to visibility, text rendering, focus states, and animations can behave differently across existent browser and device. Running them onBrowserStack Automateensures these checks hold true in real environments.
  • Reduced mistaken positives in test results:Assertions may legislate locally but fail for exploiter due to OS-level differences, browser engines, or device-specific timing. Existent device testing helps catch these gaps betimes.
  • Logical assertion timing under real conditions:Real devices reveal performance variations that impact assertion retries and timeouts. This makes assertions more reliable and align with real-world load and rendering behavior.
  • Scalable validation across environments:BrowserStack Automate enables scat assertion-heavy Playwright tests in parallel across multiple browser–OS combinations, ensuring extensive coverage without increasing execution clip.
  • Better debug when averment fail:Screenshots, videos, and logarithm from existent device runs ply clear context for why an asseveration failed, making root cause analysis quicker and more accurate.

Talk to an Expert

Conclusion

The expect()office of Playwright is a critical plus for automation testers, delivering powerful and adaptable assertions crucial for control the integrity and functionality of web coating. Its inherent retry capability, couple with its proficiency in handling complex assertions on component, network interactions, and accessibility attributes, is particularly efficacious for modern web applications qualify by dynamic and asynchronous behavior.

Utilizing expect()adeptly within Playwright exam enables testers to sustain that their applications not alone adhere to specific essential but also present a stable exploiter experience across divers scenarios. This map & # 8217; s ability to exactly adjust statement conditions, such as timeouts, and to assess a all-embracing spectrum of criteria—from the visibleness of elements to the rightness of API responses—increases the preciseness and dependability of tests.

Running your Playwright Tests on BrowserStack ’ s helps you get access to 3500+ real device and browser combinations for. It grant you to, which will facilitate name the bottlenecks in the real user experience and rectify them. BrowserStack ’ s allows you to run Playwright exam on the cloud and across browser and device simultaneously by leveraging for faster testing with a vast coverage.

Tags
93,000+ Views

# Ask-and-Contributeabout this topic with our Discord community.

Related Guides

Automate This With SUSA

Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts needed.

Try SUSA Free

Test Your App Autonomously

Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.

Try SUSA Free